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