mirror of
https://github.com/PuerkitoBio/goquery
synced 2025-09-27 21:22:27 +08:00
work on filter.go, needs tests now
This commit is contained in:
4
doc.go
4
doc.go
@@ -41,7 +41,7 @@ https://github.com/puerkitobio/goquery
|
|||||||
package goquery
|
package goquery
|
||||||
|
|
||||||
// DONE array.go : Positional Manipulation: First(), Last(), Eq(), Get(), Index(), Slice()
|
// DONE array.go : Positional Manipulation: First(), Last(), Eq(), Get(), Index(), Slice()
|
||||||
// filter.go : Filtering: Filter(), Not(), Has(), End()
|
// TESTS filter.go : Filtering: Filter(), Not(), Has(), End()
|
||||||
// expand.go : "Expanding": Add(), AndSelf()
|
// expand.go : "Expanding": Add(), AndSelf()
|
||||||
// query.go : Reflect (query) node: Is(), Contains(), HasClass()
|
// query.go : Reflect (query) node: Is(), Contains(), HasClass()
|
||||||
// property.go : Inspect node: Contents(), Html(), Text(), Attr(), Val(), Length(), Size()
|
// property.go : Inspect node: Contents(), Html(), Text(), Attr(), Val(), Length(), Size()
|
||||||
@@ -62,7 +62,7 @@ package goquery
|
|||||||
// x Contains() (static function?) - Utilities - needs tests
|
// x Contains() (static function?) - Utilities - needs tests
|
||||||
// - Contents() (similar to Children(), but includes text and comment nodes, so Children() should filter them out) - Misc. Traversing
|
// - Contents() (similar to Children(), but includes text and comment nodes, so Children() should filter them out) - Misc. Traversing
|
||||||
// x Each() - Traversing
|
// x Each() - Traversing
|
||||||
// - End() - Misc. Traversing
|
// x End() - Misc. Traversing
|
||||||
// x Eq() - Filtering
|
// x Eq() - Filtering
|
||||||
// x Filter() - Filtering
|
// x Filter() - Filtering
|
||||||
// x Find() : Complete with Selection object and Node object as selectors - Tree Traversal
|
// x Find() : Complete with Selection object and Node object as selectors - Tree Traversal
|
||||||
|
91
filter.go
91
filter.go
@@ -5,42 +5,98 @@ import (
|
|||||||
"exp/html"
|
"exp/html"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Filter() reduces the set of matched elements to those that match the selector string.
|
||||||
|
// It returns a new Selection object for this subset of matching elements.
|
||||||
func (this *Selection) Filter(selector string) *Selection {
|
func (this *Selection) Filter(selector string) *Selection {
|
||||||
return pushStack(this, winnow(this, selector, true))
|
return pushStack(this, winnow(this, selector, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not() removes elements from the Selection that match the selector string.
|
||||||
|
// It returns a new Selection object with the matching elements removed.
|
||||||
func (this *Selection) Not(selector string) *Selection {
|
func (this *Selection) Not(selector string) *Selection {
|
||||||
return pushStack(this, winnow(this, selector, false))
|
return pushStack(this, winnow(this, selector, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FilterFunction() reduces the set of matched elements to those that pass the function's test.
|
||||||
|
// It returns a new Selection object for this subset of elements.
|
||||||
func (this *Selection) FilterFunction(f func(int, *Selection) bool) *Selection {
|
func (this *Selection) FilterFunction(f func(int, *Selection) bool) *Selection {
|
||||||
return pushStack(this, winnowFunction(this, f, true))
|
return pushStack(this, winnowFunction(this, f, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not() removes elements from the Selection that pass the function's test.
|
||||||
|
// It returns a new Selection object with the matching elements removed.
|
||||||
func (this *Selection) NotFunction(f func(int, *Selection) bool) *Selection {
|
func (this *Selection) NotFunction(f func(int, *Selection) bool) *Selection {
|
||||||
return pushStack(this, winnowFunction(this, f, false))
|
return pushStack(this, winnowFunction(this, f, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FilterNodes() reduces the set of matched elements to those that match the specified nodes.
|
||||||
|
// It returns a new Selection object for this subset of elements.
|
||||||
func (this *Selection) FilterNodes(nodes ...*html.Node) *Selection {
|
func (this *Selection) FilterNodes(nodes ...*html.Node) *Selection {
|
||||||
return pushStack(this, winnowNodes(this, nodes, true))
|
return pushStack(this, winnowNodes(this, nodes, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not() removes elements from the Selection that match the specified nodes.
|
||||||
|
// It returns a new Selection object with the matching elements removed.
|
||||||
func (this *Selection) NotNodes(nodes ...*html.Node) *Selection {
|
func (this *Selection) NotNodes(nodes ...*html.Node) *Selection {
|
||||||
return pushStack(this, winnowNodes(this, nodes, false))
|
return pushStack(this, winnowNodes(this, nodes, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FilterSelection() reduces the set of matched elements to those that match a node in the specified Selection object.
|
||||||
|
// It returns a new Selection object for this subset of elements.
|
||||||
func (this *Selection) FilterSelection(s *Selection) *Selection {
|
func (this *Selection) FilterSelection(s *Selection) *Selection {
|
||||||
return pushStack(this, winnowNodes(this, s.Nodes, true))
|
return pushStack(this, winnowNodes(this, s.Nodes, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not() removes elements from the Selection that match a node in the specified Selection object.
|
||||||
|
// It returns a new Selection object with the matching elements removed.
|
||||||
func (this *Selection) NotSelection(s *Selection) *Selection {
|
func (this *Selection) NotSelection(s *Selection) *Selection {
|
||||||
return pushStack(this, winnowNodes(this, s.Nodes, false))
|
return pushStack(this, winnowNodes(this, s.Nodes, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Union() is an alias for FilterSelection().
|
||||||
func (this *Selection) Union(s *Selection) *Selection {
|
func (this *Selection) Union(s *Selection) *Selection {
|
||||||
return this.FilterSelection(s)
|
return this.FilterSelection(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Has() reduces the set of matched elements to those that have a descendant that matches the selector.
|
||||||
|
// It returns a new Selection object with the matching elements.
|
||||||
|
func (this *Selection) Has(selector string) *Selection {
|
||||||
|
sel := this.document.Find(selector)
|
||||||
|
return this.HasSelection(sel)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasNodes() reduces the set of matched elements to those that have a descendant that matches one of the nodes.
|
||||||
|
// It returns a new Selection object with the matching elements.
|
||||||
|
func (this *Selection) HasNodes(nodes ...*html.Node) *Selection {
|
||||||
|
return this.FilterFunction(func(_ int, s *Selection) bool {
|
||||||
|
// Add all nodes that contain one of the specified nodes
|
||||||
|
for _, n := range nodes {
|
||||||
|
if s.Contains(n) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasSelection() reduces the set of matched elements to those that have a descendant that matches one of
|
||||||
|
// the nodes of the specified Selection object.
|
||||||
|
// It returns a new Selection object with the matching elements.
|
||||||
|
func (this *Selection) HasSelection(sel *Selection) *Selection {
|
||||||
|
return this.HasNodes(sel.Nodes...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// End() ends the most recent filtering operation in the current chain and returns
|
||||||
|
// the set of matched elements to its previous state.
|
||||||
|
func (this *Selection) End() *Selection {
|
||||||
|
if this.prevSel != nil {
|
||||||
|
return this.prevSel
|
||||||
|
}
|
||||||
|
return newEmptySelection(this.document)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter based on a selector string, and the indicator to keep (Filter) or
|
||||||
|
// to get rid of (Not) the matching elements.
|
||||||
func winnow(sel *Selection, selector string, keep bool) []*html.Node {
|
func winnow(sel *Selection, selector string, keep bool) []*html.Node {
|
||||||
cs := cascadia.MustCompile(selector)
|
cs := cascadia.MustCompile(selector)
|
||||||
|
|
||||||
@@ -50,49 +106,24 @@ func winnow(sel *Selection, selector string, keep bool) []*html.Node {
|
|||||||
} else {
|
} else {
|
||||||
// Use grep
|
// Use grep
|
||||||
return grep(sel, func(i int, s *Selection) bool {
|
return grep(sel, func(i int, s *Selection) bool {
|
||||||
return !cs(s.Get(0))
|
return !cs.Match(s.Get(0))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter based on an array of nodes, and the indicator to keep (Filter) or
|
||||||
|
// to get rid of (Not) the matching elements.
|
||||||
func winnowNodes(sel *Selection, nodes []*html.Node, keep bool) []*html.Node {
|
func winnowNodes(sel *Selection, nodes []*html.Node, keep bool) []*html.Node {
|
||||||
return grep(sel, func(i int, s *Selection) bool {
|
return grep(sel, func(i int, s *Selection) bool {
|
||||||
return isInSlice(nodes, s.Get(0)) == keep
|
return isInSlice(nodes, s.Get(0)) == keep
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identical functionality for FilterFunction() and NotFunction(), only keep changes.
|
// Filter based on a function test, and the indicator to keep (Filter) or
|
||||||
|
// to get rid of (Not) the matching elements.
|
||||||
func winnowFunction(sel *Selection, f func(int, *Selection) bool, keep bool) []*html.Node {
|
func winnowFunction(sel *Selection, f func(int, *Selection) bool, keep bool) []*html.Node {
|
||||||
return grep(sel, func(i int, s *Selection) bool {
|
return grep(sel, func(i int, s *Selection) bool {
|
||||||
return f(i, s) == keep
|
return f(i, s) == keep
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *Selection) Has(selector string) *Selection {
|
|
||||||
sel := this.document.Find(selector)
|
|
||||||
|
|
||||||
return this.HasSelection(sel)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *Selection) HasNode(node *html.Node) *Selection {
|
|
||||||
return this.FilterFunction(func(_ int, s *Selection) bool {
|
|
||||||
// Add all nodes that contain the node specified
|
|
||||||
if s.Contains(node) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *Selection) HasSelection(sel *Selection) *Selection {
|
|
||||||
return this.FilterFunction(func(_ int, s *Selection) bool {
|
|
||||||
// Add all nodes that contain one of the nodes in the selection
|
|
||||||
for _, n := range sel.Nodes {
|
|
||||||
if s.Contains(n) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
18
query.go
18
query.go
@@ -24,3 +24,21 @@ func (this *Selection) HasClass(class string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Contains() returns true if the specified Node is within,
|
||||||
|
// at any depth, one of the nodes in the Selection object.
|
||||||
|
// It is NOT inclusive, to behave like jQuery's implementation, and
|
||||||
|
// unlike Javascript's .contains(), so if the contained
|
||||||
|
// node is itself in the selection, it returns false.
|
||||||
|
func (this *Selection) Contains(n *html.Node) bool {
|
||||||
|
return sliceContains(this.Nodes, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contains() returns true if the specified Node is within,
|
||||||
|
// at any depth, the root node of the Document object.
|
||||||
|
// It is NOT inclusive, to behave like jQuery's implementation, and
|
||||||
|
// unlike Javascript's .contains(), so if the contained
|
||||||
|
// node is itself in the selection, it returns false.
|
||||||
|
func (this *Document) Contains(n *html.Node) bool {
|
||||||
|
return sliceContains([]*html.Node{this.Root}, n)
|
||||||
|
}
|
||||||
|
18
utilities.go
18
utilities.go
@@ -4,24 +4,6 @@ import (
|
|||||||
"exp/html"
|
"exp/html"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Contains() returns true if the specified Node is within,
|
|
||||||
// at any depth, one of the nodes in the Selection object.
|
|
||||||
// It is NOT inclusive, to behave like jQuery's implementation, and
|
|
||||||
// unlike Javascript's .contains(), so if the contained
|
|
||||||
// node is itself in the selection, it returns false.
|
|
||||||
func (this *Selection) Contains(n *html.Node) bool {
|
|
||||||
return sliceContains(this.Nodes, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contains() returns true if the specified Node is within,
|
|
||||||
// at any depth, the root node of the Document object.
|
|
||||||
// It is NOT inclusive, to behave like jQuery's implementation, and
|
|
||||||
// unlike Javascript's .contains(), so if the contained
|
|
||||||
// node is itself in the selection, it returns false.
|
|
||||||
func (this *Document) Contains(n *html.Node) bool {
|
|
||||||
return sliceContains([]*html.Node{this.Root}, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop through all container nodes to search for the target node.
|
// Loop through all container nodes to search for the target node.
|
||||||
func sliceContains(container []*html.Node, contained *html.Node) bool {
|
func sliceContains(container []*html.Node, contained *html.Node) bool {
|
||||||
for _, n := range container {
|
for _, n := range container {
|
||||||
|
Reference in New Issue
Block a user