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