mirror of
https://github.com/PuerkitoBio/goquery.git
synced 2024-04-21 12:31:36 +00:00
refactor of Find() methods to use mapNodes
This commit is contained in:
@@ -36,9 +36,12 @@ Coming soon...
|
||||
|
||||
## TODOs
|
||||
|
||||
* Implement NextUntil() and PrevUntil().
|
||||
* Check each method, make sure it uses only ElementNodes except when explicitly specified (i.e.: `Contents()`). Cascadia's selectors act only on elements.
|
||||
* Tests to validate that all methods returning a new `*Selection` "rollback" correctly to the previous Selection when calling `.End()`.
|
||||
* Benchmarks so that future changes have a baseline to compare to.
|
||||
* Add jQuery's `Closest()`? Other missing functions?
|
||||
* Support negative indices in `Slice()`, like jQuery.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -94,9 +94,6 @@ The various methods are split into files based on the category of behavior:
|
||||
*/
|
||||
package goquery
|
||||
|
||||
// TODO : Test End() on all filtering/expanding/array/traversal functions, make
|
||||
// sure it returns the same object as the previous selection.
|
||||
|
||||
// DONE array.go : Positional Manipulation: First(), Last(), Eq(), Get(), Index(), Slice()
|
||||
// DONE filter.go : Filtering: Filter(), Not(), Has(), End()
|
||||
// DONE expand.go : "Expanding": Add(), AndSelf()
|
||||
@@ -105,47 +102,3 @@ package goquery
|
||||
// traversal.go : Traversal: Contents(), Find(), Children(), Parents...(), Next...(), Prev...(), Siblings()
|
||||
// DONE iteration.go : Iteration: Each(), Map()
|
||||
// DONE type.go : Selection and Document
|
||||
|
||||
// TODO : Benchmarks, examples
|
||||
|
||||
// TODO : Check each method, if it applies to any node or only Element nodes (Cascadia's selectors already make sure of that)
|
||||
|
||||
// TODO : Add the following methods:
|
||||
// x Add()
|
||||
// x AndSelf()
|
||||
// x Attr()
|
||||
// x Children()
|
||||
// x Closest() ?
|
||||
// x Contains()
|
||||
// x Contents()
|
||||
// x Each()
|
||||
// x End()
|
||||
// x Eq()
|
||||
// x Filter()
|
||||
// x Find() : Complete with Selection object and Node object as selectors - Tree Traversal
|
||||
// x First()
|
||||
// x Get()
|
||||
// x Has()
|
||||
// x HasClass()
|
||||
// x Html()
|
||||
// x Index()
|
||||
// x Is() - Filtering
|
||||
// x Last()
|
||||
// x Length() / Size()
|
||||
// x Map()
|
||||
// x Next() - Tree traversal
|
||||
// x NextAll() - Tree traversal
|
||||
// - NextUntil() - Tree traversal
|
||||
// x Not()
|
||||
// x Parent() - Tree traversal
|
||||
// x Parents() - Tree traversal
|
||||
// x ParentsUntil() - Tree traversal
|
||||
// x Prev() - Tree traversal
|
||||
// x PrevAll() - Tree traversal
|
||||
// - PrevUntil() - Tree traversal
|
||||
// x PushStack()
|
||||
// x Siblings() - Tree traversal
|
||||
// x Slice()
|
||||
// x Text() - DOM Manipulation
|
||||
// x ToArray()
|
||||
// x Unique() internally only
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
// The selector string is run in the context of the document of the current
|
||||
// Selection object.
|
||||
func (this *Selection) Add(selector string) *Selection {
|
||||
return this.AddNodes(findWithContext(selector, this.document.rootNode)...)
|
||||
return this.AddNodes(findWithSelector([]*html.Node{this.document.rootNode}, selector)...)
|
||||
}
|
||||
|
||||
// AddSelection() adds the specified Selection object's nodes to those in the
|
||||
|
||||
+27
-25
@@ -7,6 +7,8 @@ import (
|
||||
|
||||
type siblingType int
|
||||
|
||||
// Sibling type, used internally when iterating over children at the same
|
||||
// level (siblings) to specify which nodes are requested.
|
||||
const (
|
||||
siblintPrevAll siblingType = iota - 2
|
||||
siblingPrev
|
||||
@@ -20,7 +22,7 @@ const (
|
||||
// elements, filtered by a selector. It returns a new Selection object
|
||||
// containing these matched elements.
|
||||
func (this *Selection) Find(selector string) *Selection {
|
||||
return pushStack(this, findWithContext(selector, this.Nodes...))
|
||||
return pushStack(this, findWithSelector(this.Nodes, selector))
|
||||
}
|
||||
|
||||
// FindSelection() gets the descendants of each element in the current
|
||||
@@ -37,14 +39,12 @@ func (this *Selection) FindSelection(sel *Selection) *Selection {
|
||||
// Selection, filtered by some nodes. It returns a new Selection object
|
||||
// containing these matched elements.
|
||||
func (this *Selection) FindNodes(nodes ...*html.Node) *Selection {
|
||||
var matches []*html.Node
|
||||
|
||||
for _, n := range nodes {
|
||||
return pushStack(this, mapNodes(nodes, func(i int, n *html.Node) []*html.Node {
|
||||
if sliceContains(this.Nodes, n) {
|
||||
matches = appendWithoutDuplicates(matches, []*html.Node{n})
|
||||
return []*html.Node{n}
|
||||
}
|
||||
}
|
||||
return pushStack(this, matches)
|
||||
return nil
|
||||
}))
|
||||
}
|
||||
|
||||
// Contents() gets the children of each element in the Selection,
|
||||
@@ -225,6 +225,22 @@ func filterAndPush(srcSel *Selection, nodes []*html.Node, selector string) *Sele
|
||||
return pushStack(srcSel, winnow(sel, selector, true))
|
||||
}
|
||||
|
||||
// Internal implementation of Find that return raw nodes.
|
||||
func findWithSelector(nodes []*html.Node, selector string) []*html.Node {
|
||||
// Compile the selector once
|
||||
sel := cascadia.MustCompile(selector)
|
||||
// Map nodes to find the matches within the children of each node
|
||||
return mapNodes(nodes, func(i int, n *html.Node) (result []*html.Node) {
|
||||
// Go down one level, becausejQuery's Find() selects only within descendants
|
||||
for _, c := range n.Child {
|
||||
if c.Type == html.ElementNode {
|
||||
result = append(result, sel.MatchAll(c)...)
|
||||
}
|
||||
}
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
// Internal implementation to get all parent nodes, stopping at the specified
|
||||
// node (or nil if no stop).
|
||||
func getParentsNodes(nodes []*html.Node, stopSelector string, stopNodes []*html.Node) []*html.Node {
|
||||
@@ -260,12 +276,16 @@ func getSiblingNodes(nodes []*html.Node, st siblingType) []*html.Node {
|
||||
})
|
||||
}
|
||||
|
||||
// Gets the children nodes of each node in the specified slice of nodes,
|
||||
// based on the sibling type request.
|
||||
func getChildrenNodes(nodes []*html.Node, st siblingType) []*html.Node {
|
||||
return mapNodes(nodes, func(i int, n *html.Node) []*html.Node {
|
||||
return getChildrenWithSiblingType(n, st, nil)
|
||||
})
|
||||
}
|
||||
|
||||
// Gets the children of the specified parent, based on the requested sibling
|
||||
// type, skipping a specified node if required.
|
||||
func getChildrenWithSiblingType(parent *html.Node, st siblingType, skipNode *html.Node) (result []*html.Node) {
|
||||
var prev *html.Node
|
||||
var nFound bool
|
||||
@@ -326,21 +346,3 @@ func mapNodes(nodes []*html.Node, f func(int, *html.Node) []*html.Node) (result
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Private internal implementation of the Find() methods
|
||||
func findWithContext(selector string, nodes ...*html.Node) []*html.Node {
|
||||
var matches []*html.Node
|
||||
|
||||
// TODO : Refactor to use mapNodes?
|
||||
sel := cascadia.MustCompile(selector)
|
||||
// Match the selector on each node
|
||||
for _, n := range nodes {
|
||||
// Go down one level, becausejQuery's Find() selects only within descendants
|
||||
for _, c := range n.Child {
|
||||
if c.Type == html.ElementNode {
|
||||
matches = appendWithoutDuplicates(matches, sel.MatchAll(c))
|
||||
}
|
||||
}
|
||||
}
|
||||
return matches
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user