You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

550 lines
17 KiB

  1. package goquery
  2. import (
  3. "strings"
  4. "golang.org/x/net/html"
  5. )
  6. // After applies the selector from the root document and inserts the matched elements
  7. // after the elements in the set of matched elements.
  8. //
  9. // If one of the matched elements in the selection is not currently in the
  10. // document, it's impossible to insert nodes after it, so it will be ignored.
  11. //
  12. // This follows the same rules as Selection.Append.
  13. func (s *Selection) After(selector string) *Selection {
  14. return s.AfterMatcher(compileMatcher(selector))
  15. }
  16. // AfterMatcher applies the matcher from the root document and inserts the matched elements
  17. // after the elements in the set of matched elements.
  18. //
  19. // If one of the matched elements in the selection is not currently in the
  20. // document, it's impossible to insert nodes after it, so it will be ignored.
  21. //
  22. // This follows the same rules as Selection.Append.
  23. func (s *Selection) AfterMatcher(m Matcher) *Selection {
  24. return s.AfterNodes(m.MatchAll(s.document.rootNode)...)
  25. }
  26. // AfterSelection inserts the elements in the selection after each element in the set of matched
  27. // elements.
  28. //
  29. // This follows the same rules as Selection.Append.
  30. func (s *Selection) AfterSelection(sel *Selection) *Selection {
  31. return s.AfterNodes(sel.Nodes...)
  32. }
  33. // AfterHtml parses the html and inserts it after the set of matched elements.
  34. //
  35. // This follows the same rules as Selection.Append.
  36. func (s *Selection) AfterHtml(html string) *Selection {
  37. return s.AfterNodes(parseHtml(html)...)
  38. }
  39. // AfterNodes inserts the nodes after each element in the set of matched elements.
  40. //
  41. // This follows the same rules as Selection.Append.
  42. func (s *Selection) AfterNodes(ns ...*html.Node) *Selection {
  43. return s.manipulateNodes(ns, true, func(sn *html.Node, n *html.Node) {
  44. if sn.Parent != nil {
  45. sn.Parent.InsertBefore(n, sn.NextSibling)
  46. }
  47. })
  48. }
  49. // Append appends the elements specified by the selector to the end of each element
  50. // in the set of matched elements, following those rules:
  51. //
  52. // 1) The selector is applied to the root document.
  53. //
  54. // 2) Elements that are part of the document will be moved to the new location.
  55. //
  56. // 3) If there are multiple locations to append to, cloned nodes will be
  57. // appended to all target locations except the last one, which will be moved
  58. // as noted in (2).
  59. func (s *Selection) Append(selector string) *Selection {
  60. return s.AppendMatcher(compileMatcher(selector))
  61. }
  62. // AppendMatcher appends the elements specified by the matcher to the end of each element
  63. // in the set of matched elements.
  64. //
  65. // This follows the same rules as Selection.Append.
  66. func (s *Selection) AppendMatcher(m Matcher) *Selection {
  67. return s.AppendNodes(m.MatchAll(s.document.rootNode)...)
  68. }
  69. // AppendSelection appends the elements in the selection to the end of each element
  70. // in the set of matched elements.
  71. //
  72. // This follows the same rules as Selection.Append.
  73. func (s *Selection) AppendSelection(sel *Selection) *Selection {
  74. return s.AppendNodes(sel.Nodes...)
  75. }
  76. // AppendHtml parses the html and appends it to the set of matched elements.
  77. func (s *Selection) AppendHtml(html string) *Selection {
  78. return s.AppendNodes(parseHtml(html)...)
  79. }
  80. // AppendNodes appends the specified nodes to each node in the set of matched elements.
  81. //
  82. // This follows the same rules as Selection.Append.
  83. func (s *Selection) AppendNodes(ns ...*html.Node) *Selection {
  84. return s.manipulateNodes(ns, false, func(sn *html.Node, n *html.Node) {
  85. sn.AppendChild(n)
  86. })
  87. }
  88. // Before inserts the matched elements before each element in the set of matched elements.
  89. //
  90. // This follows the same rules as Selection.Append.
  91. func (s *Selection) Before(selector string) *Selection {
  92. return s.BeforeMatcher(compileMatcher(selector))
  93. }
  94. // BeforeMatcher inserts the matched elements before each element in the set of matched elements.
  95. //
  96. // This follows the same rules as Selection.Append.
  97. func (s *Selection) BeforeMatcher(m Matcher) *Selection {
  98. return s.BeforeNodes(m.MatchAll(s.document.rootNode)...)
  99. }
  100. // BeforeSelection inserts the elements in the selection before each element in the set of matched
  101. // elements.
  102. //
  103. // This follows the same rules as Selection.Append.
  104. func (s *Selection) BeforeSelection(sel *Selection) *Selection {
  105. return s.BeforeNodes(sel.Nodes...)
  106. }
  107. // BeforeHtml parses the html and inserts it before the set of matched elements.
  108. //
  109. // This follows the same rules as Selection.Append.
  110. func (s *Selection) BeforeHtml(html string) *Selection {
  111. return s.BeforeNodes(parseHtml(html)...)
  112. }
  113. // BeforeNodes inserts the nodes before each element in the set of matched elements.
  114. //
  115. // This follows the same rules as Selection.Append.
  116. func (s *Selection) BeforeNodes(ns ...*html.Node) *Selection {
  117. return s.manipulateNodes(ns, false, func(sn *html.Node, n *html.Node) {
  118. if sn.Parent != nil {
  119. sn.Parent.InsertBefore(n, sn)
  120. }
  121. })
  122. }
  123. // Clone creates a deep copy of the set of matched nodes. The new nodes will not be
  124. // attached to the document.
  125. func (s *Selection) Clone() *Selection {
  126. ns := newEmptySelection(s.document)
  127. ns.Nodes = cloneNodes(s.Nodes)
  128. return ns
  129. }
  130. // Empty removes all children nodes from the set of matched elements.
  131. // It returns the children nodes in a new Selection.
  132. func (s *Selection) Empty() *Selection {
  133. var nodes []*html.Node
  134. for _, n := range s.Nodes {
  135. for c := n.FirstChild; c != nil; c = n.FirstChild {
  136. n.RemoveChild(c)
  137. nodes = append(nodes, c)
  138. }
  139. }
  140. return pushStack(s, nodes)
  141. }
  142. // Prepend prepends the elements specified by the selector to each element in
  143. // the set of matched elements, following the same rules as Append.
  144. func (s *Selection) Prepend(selector string) *Selection {
  145. return s.PrependMatcher(compileMatcher(selector))
  146. }
  147. // PrependMatcher prepends the elements specified by the matcher to each
  148. // element in the set of matched elements.
  149. //
  150. // This follows the same rules as Selection.Append.
  151. func (s *Selection) PrependMatcher(m Matcher) *Selection {
  152. return s.PrependNodes(m.MatchAll(s.document.rootNode)...)
  153. }
  154. // PrependSelection prepends the elements in the selection to each element in
  155. // the set of matched elements.
  156. //
  157. // This follows the same rules as Selection.Append.
  158. func (s *Selection) PrependSelection(sel *Selection) *Selection {
  159. return s.PrependNodes(sel.Nodes...)
  160. }
  161. // PrependHtml parses the html and prepends it to the set of matched elements.
  162. func (s *Selection) PrependHtml(html string) *Selection {
  163. return s.PrependNodes(parseHtml(html)...)
  164. }
  165. // PrependNodes prepends the specified nodes to each node in the set of
  166. // matched elements.
  167. //
  168. // This follows the same rules as Selection.Append.
  169. func (s *Selection) PrependNodes(ns ...*html.Node) *Selection {
  170. return s.manipulateNodes(ns, true, func(sn *html.Node, n *html.Node) {
  171. // sn.FirstChild may be nil, in which case this functions like
  172. // sn.AppendChild()
  173. sn.InsertBefore(n, sn.FirstChild)
  174. })
  175. }
  176. // Remove removes the set of matched elements from the document.
  177. // It returns the same selection, now consisting of nodes not in the document.
  178. func (s *Selection) Remove() *Selection {
  179. for _, n := range s.Nodes {
  180. if n.Parent != nil {
  181. n.Parent.RemoveChild(n)
  182. }
  183. }
  184. return s
  185. }
  186. // RemoveFiltered removes the set of matched elements by selector.
  187. // It returns the Selection of removed nodes.
  188. func (s *Selection) RemoveFiltered(selector string) *Selection {
  189. return s.RemoveMatcher(compileMatcher(selector))
  190. }
  191. // RemoveMatcher removes the set of matched elements.
  192. // It returns the Selection of removed nodes.
  193. func (s *Selection) RemoveMatcher(m Matcher) *Selection {
  194. return s.FilterMatcher(m).Remove()
  195. }
  196. // ReplaceWith replaces each element in the set of matched elements with the
  197. // nodes matched by the given selector.
  198. // It returns the removed elements.
  199. //
  200. // This follows the same rules as Selection.Append.
  201. func (s *Selection) ReplaceWith(selector string) *Selection {
  202. return s.ReplaceWithMatcher(compileMatcher(selector))
  203. }
  204. // ReplaceWithMatcher replaces each element in the set of matched elements with
  205. // the nodes matched by the given Matcher.
  206. // It returns the removed elements.
  207. //
  208. // This follows the same rules as Selection.Append.
  209. func (s *Selection) ReplaceWithMatcher(m Matcher) *Selection {
  210. return s.ReplaceWithNodes(m.MatchAll(s.document.rootNode)...)
  211. }
  212. // ReplaceWithSelection replaces each element in the set of matched elements with
  213. // the nodes from the given Selection.
  214. // It returns the removed elements.
  215. //
  216. // This follows the same rules as Selection.Append.
  217. func (s *Selection) ReplaceWithSelection(sel *Selection) *Selection {
  218. return s.ReplaceWithNodes(sel.Nodes...)
  219. }
  220. // ReplaceWithHtml replaces each element in the set of matched elements with
  221. // the parsed HTML.
  222. // It returns the removed elements.
  223. //
  224. // This follows the same rules as Selection.Append.
  225. func (s *Selection) ReplaceWithHtml(html string) *Selection {
  226. return s.ReplaceWithNodes(parseHtml(html)...)
  227. }
  228. // ReplaceWithNodes replaces each element in the set of matched elements with
  229. // the given nodes.
  230. // It returns the removed elements.
  231. //
  232. // This follows the same rules as Selection.Append.
  233. func (s *Selection) ReplaceWithNodes(ns ...*html.Node) *Selection {
  234. s.AfterNodes(ns...)
  235. return s.Remove()
  236. }
  237. // Unwrap removes the parents of the set of matched elements, leaving the matched
  238. // elements (and their siblings, if any) in their place.
  239. // It returns the original selection.
  240. func (s *Selection) Unwrap() *Selection {
  241. s.Parent().Each(func(i int, ss *Selection) {
  242. // For some reason, jquery allows unwrap to remove the <head> element, so
  243. // allowing it here too. Same for <html>. Why it allows those elements to
  244. // be unwrapped while not allowing body is a mystery to me.
  245. if ss.Nodes[0].Data != "body" {
  246. ss.ReplaceWithSelection(ss.Contents())
  247. }
  248. })
  249. return s
  250. }
  251. // Wrap wraps each element in the set of matched elements inside the first
  252. // element matched by the given selector. The matched child is cloned before
  253. // being inserted into the document.
  254. //
  255. // It returns the original set of elements.
  256. func (s *Selection) Wrap(selector string) *Selection {
  257. return s.WrapMatcher(compileMatcher(selector))
  258. }
  259. // WrapMatcher wraps each element in the set of matched elements inside the
  260. // first element matched by the given matcher. The matched child is cloned
  261. // before being inserted into the document.
  262. //
  263. // It returns the original set of elements.
  264. func (s *Selection) WrapMatcher(m Matcher) *Selection {
  265. return s.wrapNodes(m.MatchAll(s.document.rootNode)...)
  266. }
  267. // WrapSelection wraps each element in the set of matched elements inside the
  268. // first element in the given Selection. The element is cloned before being
  269. // inserted into the document.
  270. //
  271. // It returns the original set of elements.
  272. func (s *Selection) WrapSelection(sel *Selection) *Selection {
  273. return s.wrapNodes(sel.Nodes...)
  274. }
  275. // WrapHtml wraps each element in the set of matched elements inside the inner-
  276. // most child of the given HTML.
  277. //
  278. // It returns the original set of elements.
  279. func (s *Selection) WrapHtml(html string) *Selection {
  280. return s.wrapNodes(parseHtml(html)...)
  281. }
  282. // WrapNode wraps each element in the set of matched elements inside the inner-
  283. // most child of the given node. The given node is copied before being inserted
  284. // into the document.
  285. //
  286. // It returns the original set of elements.
  287. func (s *Selection) WrapNode(n *html.Node) *Selection {
  288. return s.wrapNodes(n)
  289. }
  290. func (s *Selection) wrapNodes(ns ...*html.Node) *Selection {
  291. s.Each(func(i int, ss *Selection) {
  292. ss.wrapAllNodes(ns...)
  293. })
  294. return s
  295. }
  296. // WrapAll wraps a single HTML structure, matched by the given selector, around
  297. // all elements in the set of matched elements. The matched child is cloned
  298. // before being inserted into the document.
  299. //
  300. // It returns the original set of elements.
  301. func (s *Selection) WrapAll(selector string) *Selection {
  302. return s.WrapAllMatcher(compileMatcher(selector))
  303. }
  304. // WrapAllMatcher wraps a single HTML structure, matched by the given Matcher,
  305. // around all elements in the set of matched elements. The matched child is
  306. // cloned before being inserted into the document.
  307. //
  308. // It returns the original set of elements.
  309. func (s *Selection) WrapAllMatcher(m Matcher) *Selection {
  310. return s.wrapAllNodes(m.MatchAll(s.document.rootNode)...)
  311. }
  312. // WrapAllSelection wraps a single HTML structure, the first node of the given
  313. // Selection, around all elements in the set of matched elements. The matched
  314. // child is cloned before being inserted into the document.
  315. //
  316. // It returns the original set of elements.
  317. func (s *Selection) WrapAllSelection(sel *Selection) *Selection {
  318. return s.wrapAllNodes(sel.Nodes...)
  319. }
  320. // WrapAllHtml wraps the given HTML structure around all elements in the set of
  321. // matched elements. The matched child is cloned before being inserted into the
  322. // document.
  323. //
  324. // It returns the original set of elements.
  325. func (s *Selection) WrapAllHtml(html string) *Selection {
  326. return s.wrapAllNodes(parseHtml(html)...)
  327. }
  328. func (s *Selection) wrapAllNodes(ns ...*html.Node) *Selection {
  329. if len(ns) > 0 {
  330. return s.WrapAllNode(ns[0])
  331. }
  332. return s
  333. }
  334. // WrapAllNode wraps the given node around the first element in the Selection,
  335. // making all other nodes in the Selection children of the given node. The node
  336. // is cloned before being inserted into the document.
  337. //
  338. // It returns the original set of elements.
  339. func (s *Selection) WrapAllNode(n *html.Node) *Selection {
  340. if s.Size() == 0 {
  341. return s
  342. }
  343. wrap := cloneNode(n)
  344. first := s.Nodes[0]
  345. if first.Parent != nil {
  346. first.Parent.InsertBefore(wrap, first)
  347. first.Parent.RemoveChild(first)
  348. }
  349. for c := getFirstChildEl(wrap); c != nil; c = getFirstChildEl(wrap) {
  350. wrap = c
  351. }
  352. newSingleSelection(wrap, s.document).AppendSelection(s)
  353. return s
  354. }
  355. // WrapInner wraps an HTML structure, matched by the given selector, around the
  356. // content of element in the set of matched elements. The matched child is
  357. // cloned before being inserted into the document.
  358. //
  359. // It returns the original set of elements.
  360. func (s *Selection) WrapInner(selector string) *Selection {
  361. return s.WrapInnerMatcher(compileMatcher(selector))
  362. }
  363. // WrapInnerMatcher wraps an HTML structure, matched by the given selector,
  364. // around the content of element in the set of matched elements. The matched
  365. // child is cloned before being inserted into the document.
  366. //
  367. // It returns the original set of elements.
  368. func (s *Selection) WrapInnerMatcher(m Matcher) *Selection {
  369. return s.wrapInnerNodes(m.MatchAll(s.document.rootNode)...)
  370. }
  371. // WrapInnerSelection wraps an HTML structure, matched by the given selector,
  372. // around the content of element in the set of matched elements. The matched
  373. // child is cloned before being inserted into the document.
  374. //
  375. // It returns the original set of elements.
  376. func (s *Selection) WrapInnerSelection(sel *Selection) *Selection {
  377. return s.wrapInnerNodes(sel.Nodes...)
  378. }
  379. // WrapInnerHtml wraps an HTML structure, matched by the given selector, around
  380. // the content of element in the set of matched elements. The matched child is
  381. // cloned before being inserted into the document.
  382. //
  383. // It returns the original set of elements.
  384. func (s *Selection) WrapInnerHtml(html string) *Selection {
  385. return s.wrapInnerNodes(parseHtml(html)...)
  386. }
  387. // WrapInnerNode wraps an HTML structure, matched by the given selector, around
  388. // the content of element in the set of matched elements. The matched child is
  389. // cloned before being inserted into the document.
  390. //
  391. // It returns the original set of elements.
  392. func (s *Selection) WrapInnerNode(n *html.Node) *Selection {
  393. return s.wrapInnerNodes(n)
  394. }
  395. func (s *Selection) wrapInnerNodes(ns ...*html.Node) *Selection {
  396. if len(ns) == 0 {
  397. return s
  398. }
  399. s.Each(func(i int, s *Selection) {
  400. contents := s.Contents()
  401. if contents.Size() > 0 {
  402. contents.wrapAllNodes(ns...)
  403. } else {
  404. s.AppendNodes(cloneNode(ns[0]))
  405. }
  406. })
  407. return s
  408. }
  409. func parseHtml(h string) []*html.Node {
  410. // Errors are only returned when the io.Reader returns any error besides
  411. // EOF, but strings.Reader never will
  412. nodes, err := html.ParseFragment(strings.NewReader(h), &html.Node{Type: html.ElementNode})
  413. if err != nil {
  414. panic("goquery: failed to parse HTML: " + err.Error())
  415. }
  416. return nodes
  417. }
  418. // Get the first child that is an ElementNode
  419. func getFirstChildEl(n *html.Node) *html.Node {
  420. c := n.FirstChild
  421. for c != nil && c.Type != html.ElementNode {
  422. c = c.NextSibling
  423. }
  424. return c
  425. }
  426. // Deep copy a slice of nodes.
  427. func cloneNodes(ns []*html.Node) []*html.Node {
  428. cns := make([]*html.Node, 0, len(ns))
  429. for _, n := range ns {
  430. cns = append(cns, cloneNode(n))
  431. }
  432. return cns
  433. }
  434. // Deep copy a node. The new node has clones of all the original node's
  435. // children but none of its parents or siblings.
  436. func cloneNode(n *html.Node) *html.Node {
  437. nn := &html.Node{
  438. Type: n.Type,
  439. DataAtom: n.DataAtom,
  440. Data: n.Data,
  441. Attr: make([]html.Attribute, len(n.Attr)),
  442. }
  443. copy(nn.Attr, n.Attr)
  444. for c := n.FirstChild; c != nil; c = c.NextSibling {
  445. nn.AppendChild(cloneNode(c))
  446. }
  447. return nn
  448. }
  449. func (s *Selection) manipulateNodes(ns []*html.Node, reverse bool,
  450. f func(sn *html.Node, n *html.Node)) *Selection {
  451. lasti := s.Size() - 1
  452. // net.Html doesn't provide document fragments for insertion, so to get
  453. // things in the correct order with After() and Prepend(), the callback
  454. // needs to be called on the reverse of the nodes.
  455. if reverse {
  456. for i, j := 0, len(ns)-1; i < j; i, j = i+1, j-1 {
  457. ns[i], ns[j] = ns[j], ns[i]
  458. }
  459. }
  460. for i, sn := range s.Nodes {
  461. for _, n := range ns {
  462. if i != lasti {
  463. f(sn, cloneNode(n))
  464. } else {
  465. if n.Parent != nil {
  466. n.Parent.RemoveChild(n)
  467. }
  468. f(sn, n)
  469. }
  470. }
  471. }
  472. return s
  473. }