traversal.go 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. package goquery
  2. import (
  3. "github.com/andybalholm/cascadia"
  4. "golang.org/x/net/html"
  5. )
  6. type siblingType int
  7. // Sibling type, used internally when iterating over children at the same
  8. // level (siblings) to specify which nodes are requested.
  9. const (
  10. siblingPrevUntil siblingType = iota - 3
  11. siblingPrevAll
  12. siblingPrev
  13. siblingAll
  14. siblingNext
  15. siblingNextAll
  16. siblingNextUntil
  17. siblingAllIncludingNonElements
  18. )
  19. // Find gets the descendants of each element in the current set of matched
  20. // elements, filtered by a selector. It returns a new Selection object
  21. // containing these matched elements.
  22. func (s *Selection) Find(selector string) *Selection {
  23. return pushStack(s, findWithMatcher(s.Nodes, cascadia.MustCompile(selector)))
  24. }
  25. // FindMatcher gets the descendants of each element in the current set of matched
  26. // elements, filtered by the matcher. It returns a new Selection object
  27. // containing these matched elements.
  28. func (s *Selection) FindMatcher(m Matcher) *Selection {
  29. return pushStack(s, findWithMatcher(s.Nodes, m))
  30. }
  31. // FindSelection gets the descendants of each element in the current
  32. // Selection, filtered by a Selection. It returns a new Selection object
  33. // containing these matched elements.
  34. func (s *Selection) FindSelection(sel *Selection) *Selection {
  35. if sel == nil {
  36. return pushStack(s, nil)
  37. }
  38. return s.FindNodes(sel.Nodes...)
  39. }
  40. // FindNodes gets the descendants of each element in the current
  41. // Selection, filtered by some nodes. It returns a new Selection object
  42. // containing these matched elements.
  43. func (s *Selection) FindNodes(nodes ...*html.Node) *Selection {
  44. return pushStack(s, mapNodes(nodes, func(i int, n *html.Node) []*html.Node {
  45. if sliceContains(s.Nodes, n) {
  46. return []*html.Node{n}
  47. }
  48. return nil
  49. }))
  50. }
  51. // Contents gets the children of each element in the Selection,
  52. // including text and comment nodes. It returns a new Selection object
  53. // containing these elements.
  54. func (s *Selection) Contents() *Selection {
  55. return pushStack(s, getChildrenNodes(s.Nodes, siblingAllIncludingNonElements))
  56. }
  57. // ContentsFiltered gets the children of each element in the Selection,
  58. // filtered by the specified selector. It returns a new Selection
  59. // object containing these elements. Since selectors only act on Element nodes,
  60. // this function is an alias to ChildrenFiltered unless the selector is empty,
  61. // in which case it is an alias to Contents.
  62. func (s *Selection) ContentsFiltered(selector string) *Selection {
  63. if selector != "" {
  64. return s.ChildrenFiltered(selector)
  65. }
  66. return s.Contents()
  67. }
  68. // ContentsMatcher gets the children of each element in the Selection,
  69. // filtered by the specified matcher. It returns a new Selection
  70. // object containing these elements. Since matchers only act on Element nodes,
  71. // this function is an alias to ChildrenMatcher.
  72. func (s *Selection) ContentsMatcher(m Matcher) *Selection {
  73. return s.ChildrenMatcher(m)
  74. }
  75. // Children gets the child elements of each element in the Selection.
  76. // It returns a new Selection object containing these elements.
  77. func (s *Selection) Children() *Selection {
  78. return pushStack(s, getChildrenNodes(s.Nodes, siblingAll))
  79. }
  80. // ChildrenFiltered gets the child elements of each element in the Selection,
  81. // filtered by the specified selector. It returns a new
  82. // Selection object containing these elements.
  83. func (s *Selection) ChildrenFiltered(selector string) *Selection {
  84. return filterAndPush(s, getChildrenNodes(s.Nodes, siblingAll), cascadia.MustCompile(selector))
  85. }
  86. // ChildrenMatcher gets the child elements of each element in the Selection,
  87. // filtered by the specified matcher. It returns a new
  88. // Selection object containing these elements.
  89. func (s *Selection) ChildrenMatcher(m Matcher) *Selection {
  90. return filterAndPush(s, getChildrenNodes(s.Nodes, siblingAll), m)
  91. }
  92. // Parent gets the parent of each element in the Selection. It returns a
  93. // new Selection object containing the matched elements.
  94. func (s *Selection) Parent() *Selection {
  95. return pushStack(s, getParentNodes(s.Nodes))
  96. }
  97. // ParentFiltered gets the parent of each element in the Selection filtered by a
  98. // selector. It returns a new Selection object containing the matched elements.
  99. func (s *Selection) ParentFiltered(selector string) *Selection {
  100. return filterAndPush(s, getParentNodes(s.Nodes), cascadia.MustCompile(selector))
  101. }
  102. // ParentMatcher gets the parent of each element in the Selection filtered by a
  103. // matcher. It returns a new Selection object containing the matched elements.
  104. func (s *Selection) ParentMatcher(m Matcher) *Selection {
  105. return filterAndPush(s, getParentNodes(s.Nodes), m)
  106. }
  107. // Closest gets the first element that matches the selector by testing the
  108. // element itself and traversing up through its ancestors in the DOM tree.
  109. func (s *Selection) Closest(selector string) *Selection {
  110. cs := cascadia.MustCompile(selector)
  111. return s.ClosestMatcher(cs)
  112. }
  113. // ClosestMatcher gets the first element that matches the matcher by testing the
  114. // element itself and traversing up through its ancestors in the DOM tree.
  115. func (s *Selection) ClosestMatcher(m Matcher) *Selection {
  116. return pushStack(s, mapNodes(s.Nodes, func(i int, n *html.Node) []*html.Node {
  117. // For each node in the selection, test the node itself, then each parent
  118. // until a match is found.
  119. for ; n != nil; n = n.Parent {
  120. if m.Match(n) {
  121. return []*html.Node{n}
  122. }
  123. }
  124. return nil
  125. }))
  126. }
  127. // ClosestNodes gets the first element that matches one of the nodes by testing the
  128. // element itself and traversing up through its ancestors in the DOM tree.
  129. func (s *Selection) ClosestNodes(nodes ...*html.Node) *Selection {
  130. return pushStack(s, mapNodes(s.Nodes, func(i int, n *html.Node) []*html.Node {
  131. // For each node in the selection, test the node itself, then each parent
  132. // until a match is found.
  133. for ; n != nil; n = n.Parent {
  134. if isInSlice(nodes, n) {
  135. return []*html.Node{n}
  136. }
  137. }
  138. return nil
  139. }))
  140. }
  141. // ClosestSelection gets the first element that matches one of the nodes in the
  142. // Selection by testing the element itself and traversing up through its ancestors
  143. // in the DOM tree.
  144. func (s *Selection) ClosestSelection(sel *Selection) *Selection {
  145. if sel == nil {
  146. return pushStack(s, nil)
  147. }
  148. return s.ClosestNodes(sel.Nodes...)
  149. }
  150. // Parents gets the ancestors of each element in the current Selection. It
  151. // returns a new Selection object with the matched elements.
  152. func (s *Selection) Parents() *Selection {
  153. return pushStack(s, getParentsNodes(s.Nodes, nil, nil))
  154. }
  155. // ParentsFiltered gets the ancestors of each element in the current
  156. // Selection. It returns a new Selection object with the matched elements.
  157. func (s *Selection) ParentsFiltered(selector string) *Selection {
  158. return filterAndPush(s, getParentsNodes(s.Nodes, nil, nil), cascadia.MustCompile(selector))
  159. }
  160. // ParentsMatcher gets the ancestors of each element in the current
  161. // Selection. It returns a new Selection object with the matched elements.
  162. func (s *Selection) ParentsMatcher(m Matcher) *Selection {
  163. return filterAndPush(s, getParentsNodes(s.Nodes, nil, nil), m)
  164. }
  165. // ParentsUntil gets the ancestors of each element in the Selection, up to but
  166. // not including the element matched by the selector. It returns a new Selection
  167. // object containing the matched elements.
  168. func (s *Selection) ParentsUntil(selector string) *Selection {
  169. return pushStack(s, getParentsNodes(s.Nodes, cascadia.MustCompile(selector), nil))
  170. }
  171. // ParentsUntilMatcher gets the ancestors of each element in the Selection, up to but
  172. // not including the element matched by the matcher. It returns a new Selection
  173. // object containing the matched elements.
  174. func (s *Selection) ParentsUntilMatcher(m Matcher) *Selection {
  175. return pushStack(s, getParentsNodes(s.Nodes, m, nil))
  176. }
  177. // ParentsUntilSelection gets the ancestors of each element in the Selection,
  178. // up to but not including the elements in the specified Selection. It returns a
  179. // new Selection object containing the matched elements.
  180. func (s *Selection) ParentsUntilSelection(sel *Selection) *Selection {
  181. if sel == nil {
  182. return s.Parents()
  183. }
  184. return s.ParentsUntilNodes(sel.Nodes...)
  185. }
  186. // ParentsUntilNodes gets the ancestors of each element in the Selection,
  187. // up to but not including the specified nodes. It returns a
  188. // new Selection object containing the matched elements.
  189. func (s *Selection) ParentsUntilNodes(nodes ...*html.Node) *Selection {
  190. return pushStack(s, getParentsNodes(s.Nodes, nil, nodes))
  191. }
  192. // ParentsFilteredUntil is like ParentsUntil, with the option to filter the
  193. // results based on a selector string. It returns a new Selection
  194. // object containing the matched elements.
  195. func (s *Selection) ParentsFilteredUntil(filterSelector, untilSelector string) *Selection {
  196. return filterAndPush(s, getParentsNodes(s.Nodes, cascadia.MustCompile(untilSelector), nil), cascadia.MustCompile(filterSelector))
  197. }
  198. // ParentsFilteredUntilMatcher is like ParentsUntilMatcher, with the option to filter the
  199. // results based on a matcher. It returns a new Selection object containing the matched elements.
  200. func (s *Selection) ParentsFilteredUntilMatcher(filter, until Matcher) *Selection {
  201. return filterAndPush(s, getParentsNodes(s.Nodes, until, nil), filter)
  202. }
  203. // ParentsFilteredUntilSelection is like ParentsUntilSelection, with the
  204. // option to filter the results based on a selector string. It returns a new
  205. // Selection object containing the matched elements.
  206. func (s *Selection) ParentsFilteredUntilSelection(filterSelector string, sel *Selection) *Selection {
  207. return s.ParentsMatcherUntilSelection(cascadia.MustCompile(filterSelector), sel)
  208. }
  209. // ParentsMatcherUntilSelection is like ParentsUntilSelection, with the
  210. // option to filter the results based on a matcher. It returns a new
  211. // Selection object containing the matched elements.
  212. func (s *Selection) ParentsMatcherUntilSelection(filter Matcher, sel *Selection) *Selection {
  213. if sel == nil {
  214. return s.ParentsMatcher(filter)
  215. }
  216. return s.ParentsMatcherUntilNodes(filter, sel.Nodes...)
  217. }
  218. // ParentsFilteredUntilNodes is like ParentsUntilNodes, with the
  219. // option to filter the results based on a selector string. It returns a new
  220. // Selection object containing the matched elements.
  221. func (s *Selection) ParentsFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection {
  222. return filterAndPush(s, getParentsNodes(s.Nodes, nil, nodes), cascadia.MustCompile(filterSelector))
  223. }
  224. // ParentsMatcherUntilNodes is like ParentsUntilNodes, with the
  225. // option to filter the results based on a matcher. It returns a new
  226. // Selection object containing the matched elements.
  227. func (s *Selection) ParentsMatcherUntilNodes(filter Matcher, nodes ...*html.Node) *Selection {
  228. return filterAndPush(s, getParentsNodes(s.Nodes, nil, nodes), filter)
  229. }
  230. // Siblings gets the siblings of each element in the Selection. It returns
  231. // a new Selection object containing the matched elements.
  232. func (s *Selection) Siblings() *Selection {
  233. return pushStack(s, getSiblingNodes(s.Nodes, siblingAll, nil, nil))
  234. }
  235. // SiblingsFiltered gets the siblings of each element in the Selection
  236. // filtered by a selector. It returns a new Selection object containing the
  237. // matched elements.
  238. func (s *Selection) SiblingsFiltered(selector string) *Selection {
  239. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingAll, nil, nil), cascadia.MustCompile(selector))
  240. }
  241. // SiblingsMatcher gets the siblings of each element in the Selection
  242. // filtered by a matcher. It returns a new Selection object containing the
  243. // matched elements.
  244. func (s *Selection) SiblingsMatcher(m Matcher) *Selection {
  245. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingAll, nil, nil), m)
  246. }
  247. // Next gets the immediately following sibling of each element in the
  248. // Selection. It returns a new Selection object containing the matched elements.
  249. func (s *Selection) Next() *Selection {
  250. return pushStack(s, getSiblingNodes(s.Nodes, siblingNext, nil, nil))
  251. }
  252. // NextFiltered gets the immediately following sibling of each element in the
  253. // Selection filtered by a selector. It returns a new Selection object
  254. // containing the matched elements.
  255. func (s *Selection) NextFiltered(selector string) *Selection {
  256. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNext, nil, nil), cascadia.MustCompile(selector))
  257. }
  258. // NextMatcher gets the immediately following sibling of each element in the
  259. // Selection filtered by a matcher. It returns a new Selection object
  260. // containing the matched elements.
  261. func (s *Selection) NextMatcher(m Matcher) *Selection {
  262. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNext, nil, nil), m)
  263. }
  264. // NextAll gets all the following siblings of each element in the
  265. // Selection. It returns a new Selection object containing the matched elements.
  266. func (s *Selection) NextAll() *Selection {
  267. return pushStack(s, getSiblingNodes(s.Nodes, siblingNextAll, nil, nil))
  268. }
  269. // NextAllFiltered gets all the following siblings of each element in the
  270. // Selection filtered by a selector. It returns a new Selection object
  271. // containing the matched elements.
  272. func (s *Selection) NextAllFiltered(selector string) *Selection {
  273. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextAll, nil, nil), cascadia.MustCompile(selector))
  274. }
  275. // NextAllMatcher gets all the following siblings of each element in the
  276. // Selection filtered by a matcher. It returns a new Selection object
  277. // containing the matched elements.
  278. func (s *Selection) NextAllMatcher(m Matcher) *Selection {
  279. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextAll, nil, nil), m)
  280. }
  281. // Prev gets the immediately preceding sibling of each element in the
  282. // Selection. It returns a new Selection object containing the matched elements.
  283. func (s *Selection) Prev() *Selection {
  284. return pushStack(s, getSiblingNodes(s.Nodes, siblingPrev, nil, nil))
  285. }
  286. // PrevFiltered gets the immediately preceding sibling of each element in the
  287. // Selection filtered by a selector. It returns a new Selection object
  288. // containing the matched elements.
  289. func (s *Selection) PrevFiltered(selector string) *Selection {
  290. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrev, nil, nil), cascadia.MustCompile(selector))
  291. }
  292. // PrevMatcher gets the immediately preceding sibling of each element in the
  293. // Selection filtered by a matcher. It returns a new Selection object
  294. // containing the matched elements.
  295. func (s *Selection) PrevMatcher(m Matcher) *Selection {
  296. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrev, nil, nil), m)
  297. }
  298. // PrevAll gets all the preceding siblings of each element in the
  299. // Selection. It returns a new Selection object containing the matched elements.
  300. func (s *Selection) PrevAll() *Selection {
  301. return pushStack(s, getSiblingNodes(s.Nodes, siblingPrevAll, nil, nil))
  302. }
  303. // PrevAllFiltered gets all the preceding siblings of each element in the
  304. // Selection filtered by a selector. It returns a new Selection object
  305. // containing the matched elements.
  306. func (s *Selection) PrevAllFiltered(selector string) *Selection {
  307. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevAll, nil, nil), cascadia.MustCompile(selector))
  308. }
  309. // PrevAllMatcher gets all the preceding siblings of each element in the
  310. // Selection filtered by a matcher. It returns a new Selection object
  311. // containing the matched elements.
  312. func (s *Selection) PrevAllMatcher(m Matcher) *Selection {
  313. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevAll, nil, nil), m)
  314. }
  315. // NextUntil gets all following siblings of each element up to but not
  316. // including the element matched by the selector. It returns a new Selection
  317. // object containing the matched elements.
  318. func (s *Selection) NextUntil(selector string) *Selection {
  319. return pushStack(s, getSiblingNodes(s.Nodes, siblingNextUntil,
  320. cascadia.MustCompile(selector), nil))
  321. }
  322. // NextUntilMatcher gets all following siblings of each element up to but not
  323. // including the element matched by the matcher. It returns a new Selection
  324. // object containing the matched elements.
  325. func (s *Selection) NextUntilMatcher(m Matcher) *Selection {
  326. return pushStack(s, getSiblingNodes(s.Nodes, siblingNextUntil,
  327. m, nil))
  328. }
  329. // NextUntilSelection gets all following siblings of each element up to but not
  330. // including the element matched by the Selection. It returns a new Selection
  331. // object containing the matched elements.
  332. func (s *Selection) NextUntilSelection(sel *Selection) *Selection {
  333. if sel == nil {
  334. return s.NextAll()
  335. }
  336. return s.NextUntilNodes(sel.Nodes...)
  337. }
  338. // NextUntilNodes gets all following siblings of each element up to but not
  339. // including the element matched by the nodes. It returns a new Selection
  340. // object containing the matched elements.
  341. func (s *Selection) NextUntilNodes(nodes ...*html.Node) *Selection {
  342. return pushStack(s, getSiblingNodes(s.Nodes, siblingNextUntil,
  343. nil, nodes))
  344. }
  345. // PrevUntil gets all preceding siblings of each element up to but not
  346. // including the element matched by the selector. It returns a new Selection
  347. // object containing the matched elements.
  348. func (s *Selection) PrevUntil(selector string) *Selection {
  349. return pushStack(s, getSiblingNodes(s.Nodes, siblingPrevUntil,
  350. cascadia.MustCompile(selector), nil))
  351. }
  352. // PrevUntilMatcher gets all preceding siblings of each element up to but not
  353. // including the element matched by the matcher. It returns a new Selection
  354. // object containing the matched elements.
  355. func (s *Selection) PrevUntilMatcher(m Matcher) *Selection {
  356. return pushStack(s, getSiblingNodes(s.Nodes, siblingPrevUntil,
  357. m, nil))
  358. }
  359. // PrevUntilSelection gets all preceding siblings of each element up to but not
  360. // including the element matched by the Selection. It returns a new Selection
  361. // object containing the matched elements.
  362. func (s *Selection) PrevUntilSelection(sel *Selection) *Selection {
  363. if sel == nil {
  364. return s.PrevAll()
  365. }
  366. return s.PrevUntilNodes(sel.Nodes...)
  367. }
  368. // PrevUntilNodes gets all preceding siblings of each element up to but not
  369. // including the element matched by the nodes. It returns a new Selection
  370. // object containing the matched elements.
  371. func (s *Selection) PrevUntilNodes(nodes ...*html.Node) *Selection {
  372. return pushStack(s, getSiblingNodes(s.Nodes, siblingPrevUntil,
  373. nil, nodes))
  374. }
  375. // NextFilteredUntil is like NextUntil, with the option to filter
  376. // the results based on a selector string.
  377. // It returns a new Selection object containing the matched elements.
  378. func (s *Selection) NextFilteredUntil(filterSelector, untilSelector string) *Selection {
  379. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil,
  380. cascadia.MustCompile(untilSelector), nil), cascadia.MustCompile(filterSelector))
  381. }
  382. // NextFilteredUntilMatcher is like NextUntilMatcher, with the option to filter
  383. // the results based on a matcher.
  384. // It returns a new Selection object containing the matched elements.
  385. func (s *Selection) NextFilteredUntilMatcher(filter, until Matcher) *Selection {
  386. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil,
  387. until, nil), filter)
  388. }
  389. // NextFilteredUntilSelection is like NextUntilSelection, with the
  390. // option to filter the results based on a selector string. It returns a new
  391. // Selection object containing the matched elements.
  392. func (s *Selection) NextFilteredUntilSelection(filterSelector string, sel *Selection) *Selection {
  393. return s.NextMatcherUntilSelection(cascadia.MustCompile(filterSelector), sel)
  394. }
  395. // NextMatcherUntilSelection is like NextUntilSelection, with the
  396. // option to filter the results based on a matcher. It returns a new
  397. // Selection object containing the matched elements.
  398. func (s *Selection) NextMatcherUntilSelection(filter Matcher, sel *Selection) *Selection {
  399. if sel == nil {
  400. return s.NextMatcher(filter)
  401. }
  402. return s.NextMatcherUntilNodes(filter, sel.Nodes...)
  403. }
  404. // NextFilteredUntilNodes is like NextUntilNodes, with the
  405. // option to filter the results based on a selector string. It returns a new
  406. // Selection object containing the matched elements.
  407. func (s *Selection) NextFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection {
  408. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil,
  409. nil, nodes), cascadia.MustCompile(filterSelector))
  410. }
  411. // NextMatcherUntilNodes is like NextUntilNodes, with the
  412. // option to filter the results based on a matcher. It returns a new
  413. // Selection object containing the matched elements.
  414. func (s *Selection) NextMatcherUntilNodes(filter Matcher, nodes ...*html.Node) *Selection {
  415. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil,
  416. nil, nodes), filter)
  417. }
  418. // PrevFilteredUntil is like PrevUntil, with the option to filter
  419. // the results based on a selector string.
  420. // It returns a new Selection object containing the matched elements.
  421. func (s *Selection) PrevFilteredUntil(filterSelector, untilSelector string) *Selection {
  422. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil,
  423. cascadia.MustCompile(untilSelector), nil), cascadia.MustCompile(filterSelector))
  424. }
  425. // PrevFilteredUntilMatcher is like PrevUntilMatcher, with the option to filter
  426. // the results based on a matcher.
  427. // It returns a new Selection object containing the matched elements.
  428. func (s *Selection) PrevFilteredUntilMatcher(filter, until Matcher) *Selection {
  429. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil,
  430. until, nil), filter)
  431. }
  432. // PrevFilteredUntilSelection is like PrevUntilSelection, with the
  433. // option to filter the results based on a selector string. It returns a new
  434. // Selection object containing the matched elements.
  435. func (s *Selection) PrevFilteredUntilSelection(filterSelector string, sel *Selection) *Selection {
  436. return s.PrevMatcherUntilSelection(cascadia.MustCompile(filterSelector), sel)
  437. }
  438. // PrevMatcherUntilSelection is like PrevUntilSelection, with the
  439. // option to filter the results based on a matcher. It returns a new
  440. // Selection object containing the matched elements.
  441. func (s *Selection) PrevMatcherUntilSelection(filter Matcher, sel *Selection) *Selection {
  442. if sel == nil {
  443. return s.PrevMatcher(filter)
  444. }
  445. return s.PrevMatcherUntilNodes(filter, sel.Nodes...)
  446. }
  447. // PrevFilteredUntilNodes is like PrevUntilNodes, with the
  448. // option to filter the results based on a selector string. It returns a new
  449. // Selection object containing the matched elements.
  450. func (s *Selection) PrevFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection {
  451. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil,
  452. nil, nodes), cascadia.MustCompile(filterSelector))
  453. }
  454. // PrevMatcherUntilNodes is like PrevUntilNodes, with the
  455. // option to filter the results based on a matcher. It returns a new
  456. // Selection object containing the matched elements.
  457. func (s *Selection) PrevMatcherUntilNodes(filter Matcher, nodes ...*html.Node) *Selection {
  458. return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil,
  459. nil, nodes), filter)
  460. }
  461. // Filter and push filters the nodes based on a matcher, and pushes the results
  462. // on the stack, with the srcSel as previous selection.
  463. func filterAndPush(srcSel *Selection, nodes []*html.Node, m Matcher) *Selection {
  464. // Create a temporary Selection with the specified nodes to filter using winnow
  465. sel := &Selection{nodes, srcSel.document, nil}
  466. // Filter based on matcher and push on stack
  467. return pushStack(srcSel, winnow(sel, m, true))
  468. }
  469. // Internal implementation of Find that return raw nodes.
  470. func findWithMatcher(nodes []*html.Node, m Matcher) []*html.Node {
  471. // Map nodes to find the matches within the children of each node
  472. return mapNodes(nodes, func(i int, n *html.Node) (result []*html.Node) {
  473. // Go down one level, becausejQuery's Find selects only within descendants
  474. for c := n.FirstChild; c != nil; c = c.NextSibling {
  475. if c.Type == html.ElementNode {
  476. result = append(result, m.MatchAll(c)...)
  477. }
  478. }
  479. return
  480. })
  481. }
  482. // Internal implementation to get all parent nodes, stopping at the specified
  483. // node (or nil if no stop).
  484. func getParentsNodes(nodes []*html.Node, stopm Matcher, stopNodes []*html.Node) []*html.Node {
  485. return mapNodes(nodes, func(i int, n *html.Node) (result []*html.Node) {
  486. for p := n.Parent; p != nil; p = p.Parent {
  487. sel := newSingleSelection(p, nil)
  488. if stopm != nil {
  489. if sel.IsMatcher(stopm) {
  490. break
  491. }
  492. } else if len(stopNodes) > 0 {
  493. if sel.IsNodes(stopNodes...) {
  494. break
  495. }
  496. }
  497. if p.Type == html.ElementNode {
  498. result = append(result, p)
  499. }
  500. }
  501. return
  502. })
  503. }
  504. // Internal implementation of sibling nodes that return a raw slice of matches.
  505. func getSiblingNodes(nodes []*html.Node, st siblingType, untilm Matcher, untilNodes []*html.Node) []*html.Node {
  506. var f func(*html.Node) bool
  507. // If the requested siblings are ...Until, create the test function to
  508. // determine if the until condition is reached (returns true if it is)
  509. if st == siblingNextUntil || st == siblingPrevUntil {
  510. f = func(n *html.Node) bool {
  511. if untilm != nil {
  512. // Matcher-based condition
  513. sel := newSingleSelection(n, nil)
  514. return sel.IsMatcher(untilm)
  515. } else if len(untilNodes) > 0 {
  516. // Nodes-based condition
  517. sel := newSingleSelection(n, nil)
  518. return sel.IsNodes(untilNodes...)
  519. }
  520. return false
  521. }
  522. }
  523. return mapNodes(nodes, func(i int, n *html.Node) []*html.Node {
  524. return getChildrenWithSiblingType(n.Parent, st, n, f)
  525. })
  526. }
  527. // Gets the children nodes of each node in the specified slice of nodes,
  528. // based on the sibling type request.
  529. func getChildrenNodes(nodes []*html.Node, st siblingType) []*html.Node {
  530. return mapNodes(nodes, func(i int, n *html.Node) []*html.Node {
  531. return getChildrenWithSiblingType(n, st, nil, nil)
  532. })
  533. }
  534. // Gets the children of the specified parent, based on the requested sibling
  535. // type, skipping a specified node if required.
  536. func getChildrenWithSiblingType(parent *html.Node, st siblingType, skipNode *html.Node,
  537. untilFunc func(*html.Node) bool) (result []*html.Node) {
  538. // Create the iterator function
  539. var iter = func(cur *html.Node) (ret *html.Node) {
  540. // Based on the sibling type requested, iterate the right way
  541. for {
  542. switch st {
  543. case siblingAll, siblingAllIncludingNonElements:
  544. if cur == nil {
  545. // First iteration, start with first child of parent
  546. // Skip node if required
  547. if ret = parent.FirstChild; ret == skipNode && skipNode != nil {
  548. ret = skipNode.NextSibling
  549. }
  550. } else {
  551. // Skip node if required
  552. if ret = cur.NextSibling; ret == skipNode && skipNode != nil {
  553. ret = skipNode.NextSibling
  554. }
  555. }
  556. case siblingPrev, siblingPrevAll, siblingPrevUntil:
  557. if cur == nil {
  558. // Start with previous sibling of the skip node
  559. ret = skipNode.PrevSibling
  560. } else {
  561. ret = cur.PrevSibling
  562. }
  563. case siblingNext, siblingNextAll, siblingNextUntil:
  564. if cur == nil {
  565. // Start with next sibling of the skip node
  566. ret = skipNode.NextSibling
  567. } else {
  568. ret = cur.NextSibling
  569. }
  570. default:
  571. panic("Invalid sibling type.")
  572. }
  573. if ret == nil || ret.Type == html.ElementNode || st == siblingAllIncludingNonElements {
  574. return
  575. }
  576. // Not a valid node, try again from this one
  577. cur = ret
  578. }
  579. }
  580. for c := iter(nil); c != nil; c = iter(c) {
  581. // If this is an ...Until case, test before append (returns true
  582. // if the until condition is reached)
  583. if st == siblingNextUntil || st == siblingPrevUntil {
  584. if untilFunc(c) {
  585. return
  586. }
  587. }
  588. result = append(result, c)
  589. if st == siblingNext || st == siblingPrev {
  590. // Only one node was requested (immediate next or previous), so exit
  591. return
  592. }
  593. }
  594. return
  595. }
  596. // Internal implementation of parent nodes that return a raw slice of Nodes.
  597. func getParentNodes(nodes []*html.Node) []*html.Node {
  598. return mapNodes(nodes, func(i int, n *html.Node) []*html.Node {
  599. if n.Parent != nil && n.Parent.Type == html.ElementNode {
  600. return []*html.Node{n.Parent}
  601. }
  602. return nil
  603. })
  604. }
  605. // Internal map function used by many traversing methods. Takes the source nodes
  606. // to iterate on and the mapping function that returns an array of nodes.
  607. // Returns an array of nodes mapped by calling the callback function once for
  608. // each node in the source nodes.
  609. func mapNodes(nodes []*html.Node, f func(int, *html.Node) []*html.Node) (result []*html.Node) {
  610. for i, n := range nodes {
  611. if vals := f(i, n); len(vals) > 0 {
  612. result = appendWithoutDuplicates(result, vals)
  613. }
  614. }
  615. return
  616. }