...

Source file src/github.com/PuerkitoBio/goquery/traversal.go

Documentation: github.com/PuerkitoBio/goquery

     1  package goquery
     2  
     3  import "golang.org/x/net/html"
     4  
     5  type siblingType int
     6  
     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  
    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
    29  func (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.
    36  func (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.
    43  func (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.
    53  func (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.
    65  func (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.
    74  func (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.
    85  func (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.
    91  func (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.
    98  func (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.
   105  func (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.
   111  func (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.
   117  func (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.
   123  func (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.
   129  func (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.
   136  func (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.
   151  func (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.
   171  func (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.
   180  func (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.
   186  func (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.
   192  func (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.
   199  func (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.
   206  func (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.
   213  func (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.
   223  func (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.
   230  func (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.
   236  func (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.
   243  func (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.
   250  func (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.
   260  func (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.
   267  func (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.
   273  func (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.
   280  func (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.
   287  func (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.
   293  func (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.
   300  func (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.
   307  func (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.
   313  func (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.
   320  func (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.
   327  func (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.
   333  func (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.
   340  func (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.
   347  func (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.
   353  func (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.
   360  func (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.
   367  func (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.
   374  func (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.
   382  func (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.
   390  func (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.
   400  func (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.
   408  func (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.
   416  func (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.
   424  func (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.
   434  func (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.
   442  func (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.
   450  func (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.
   458  func (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.
   465  func (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.
   475  func (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.
   483  func (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.
   491  func (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.
   499  func (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.
   507  func (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.
   514  func (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.
   524  func (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.
   532  func (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.
   539  func 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.
   547  func 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).
   562  func 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.
   584  func 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.
   611  func 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.
   619  func 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.
   683  func 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.
   696  func 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  }
   705  

View as plain text