github.com/godaddy-x/freego@v1.0.156/goquery/filter.go (about)

     1  package goquery
     2  
     3  import "golang.org/x/net/html"
     4  
     5  // Filter reduces the set of matched elements to those that match the selector string.
     6  // It returns a new Selection object for this subset of matching elements.
     7  func (s *Selection) Filter(selector string) *Selection {
     8  	return s.FilterMatcher(compileMatcher(selector))
     9  }
    10  
    11  // FilterMatcher reduces the set of matched elements to those that match
    12  // the given matcher. It returns a new Selection object for this subset
    13  // of matching elements.
    14  func (s *Selection) FilterMatcher(m Matcher) *Selection {
    15  	return pushStack(s, winnow(s, m, true))
    16  }
    17  
    18  // Not removes elements from the Selection that match the selector string.
    19  // It returns a new Selection object with the matching elements removed.
    20  func (s *Selection) Not(selector string) *Selection {
    21  	return s.NotMatcher(compileMatcher(selector))
    22  }
    23  
    24  // NotMatcher removes elements from the Selection that match the given matcher.
    25  // It returns a new Selection object with the matching elements removed.
    26  func (s *Selection) NotMatcher(m Matcher) *Selection {
    27  	return pushStack(s, winnow(s, m, false))
    28  }
    29  
    30  // FilterFunction reduces the set of matched elements to those that pass the function's test.
    31  // It returns a new Selection object for this subset of elements.
    32  func (s *Selection) FilterFunction(f func(int, *Selection) bool) *Selection {
    33  	return pushStack(s, winnowFunction(s, f, true))
    34  }
    35  
    36  // NotFunction removes elements from the Selection that pass the function's test.
    37  // It returns a new Selection object with the matching elements removed.
    38  func (s *Selection) NotFunction(f func(int, *Selection) bool) *Selection {
    39  	return pushStack(s, winnowFunction(s, f, false))
    40  }
    41  
    42  // FilterNodes reduces the set of matched elements to those that match the specified nodes.
    43  // It returns a new Selection object for this subset of elements.
    44  func (s *Selection) FilterNodes(nodes ...*html.Node) *Selection {
    45  	return pushStack(s, winnowNodes(s, nodes, true))
    46  }
    47  
    48  // NotNodes removes elements from the Selection that match the specified nodes.
    49  // It returns a new Selection object with the matching elements removed.
    50  func (s *Selection) NotNodes(nodes ...*html.Node) *Selection {
    51  	return pushStack(s, winnowNodes(s, nodes, false))
    52  }
    53  
    54  // FilterSelection reduces the set of matched elements to those that match a
    55  // node in the specified Selection object.
    56  // It returns a new Selection object for this subset of elements.
    57  func (s *Selection) FilterSelection(sel *Selection) *Selection {
    58  	if sel == nil {
    59  		return pushStack(s, winnowNodes(s, nil, true))
    60  	}
    61  	return pushStack(s, winnowNodes(s, sel.Nodes, true))
    62  }
    63  
    64  // NotSelection removes elements from the Selection that match a node in the specified
    65  // Selection object. It returns a new Selection object with the matching elements removed.
    66  func (s *Selection) NotSelection(sel *Selection) *Selection {
    67  	if sel == nil {
    68  		return pushStack(s, winnowNodes(s, nil, false))
    69  	}
    70  	return pushStack(s, winnowNodes(s, sel.Nodes, false))
    71  }
    72  
    73  // Intersection is an alias for FilterSelection.
    74  func (s *Selection) Intersection(sel *Selection) *Selection {
    75  	return s.FilterSelection(sel)
    76  }
    77  
    78  // Has reduces the set of matched elements to those that have a descendant
    79  // that matches the selector.
    80  // It returns a new Selection object with the matching elements.
    81  func (s *Selection) Has(selector string) *Selection {
    82  	return s.HasSelection(s.document.Find(selector))
    83  }
    84  
    85  // HasMatcher reduces the set of matched elements to those that have a descendant
    86  // that matches the matcher.
    87  // It returns a new Selection object with the matching elements.
    88  func (s *Selection) HasMatcher(m Matcher) *Selection {
    89  	return s.HasSelection(s.document.FindMatcher(m))
    90  }
    91  
    92  // HasNodes reduces the set of matched elements to those that have a
    93  // descendant that matches one of the nodes.
    94  // It returns a new Selection object with the matching elements.
    95  func (s *Selection) HasNodes(nodes ...*html.Node) *Selection {
    96  	return s.FilterFunction(func(_ int, sel *Selection) bool {
    97  		// Add all nodes that contain one of the specified nodes
    98  		for _, n := range nodes {
    99  			if sel.Contains(n) {
   100  				return true
   101  			}
   102  		}
   103  		return false
   104  	})
   105  }
   106  
   107  // HasSelection reduces the set of matched elements to those that have a
   108  // descendant that matches one of the nodes of the specified Selection object.
   109  // It returns a new Selection object with the matching elements.
   110  func (s *Selection) HasSelection(sel *Selection) *Selection {
   111  	if sel == nil {
   112  		return s.HasNodes()
   113  	}
   114  	return s.HasNodes(sel.Nodes...)
   115  }
   116  
   117  // End ends the most recent filtering operation in the current chain and
   118  // returns the set of matched elements to its previous state.
   119  func (s *Selection) End() *Selection {
   120  	if s.prevSel != nil {
   121  		return s.prevSel
   122  	}
   123  	return newEmptySelection(s.document)
   124  }
   125  
   126  // Filter based on the matcher, and the indicator to keep (Filter) or
   127  // to get rid of (Not) the matching elements.
   128  func winnow(sel *Selection, m Matcher, keep bool) []*html.Node {
   129  	// Optimize if keep is requested
   130  	if keep {
   131  		return m.Filter(sel.Nodes)
   132  	}
   133  	// Use grep
   134  	return grep(sel, func(i int, s *Selection) bool {
   135  		return !m.Match(s.Get(0))
   136  	})
   137  }
   138  
   139  // Filter based on an array of nodes, and the indicator to keep (Filter) or
   140  // to get rid of (Not) the matching elements.
   141  func winnowNodes(sel *Selection, nodes []*html.Node, keep bool) []*html.Node {
   142  	if len(nodes)+len(sel.Nodes) < minNodesForSet {
   143  		return grep(sel, func(i int, s *Selection) bool {
   144  			return isInSlice(nodes, s.Get(0)) == keep
   145  		})
   146  	}
   147  
   148  	set := make(map[*html.Node]bool)
   149  	for _, n := range nodes {
   150  		set[n] = true
   151  	}
   152  	return grep(sel, func(i int, s *Selection) bool {
   153  		return set[s.Get(0)] == keep
   154  	})
   155  }
   156  
   157  // Filter based on a function test, and the indicator to keep (Filter) or
   158  // to get rid of (Not) the matching elements.
   159  func winnowFunction(sel *Selection, f func(int, *Selection) bool, keep bool) []*html.Node {
   160  	return grep(sel, func(i int, s *Selection) bool {
   161  		return f(i, s) == keep
   162  	})
   163  }