add Contents() and Children() with tests.

This commit is contained in:
Martin Angers
2012-09-02 14:07:18 -04:00
parent 9f46e15492
commit bae24062b4
4 changed files with 83 additions and 34 deletions

8
doc.go
View File

@@ -95,6 +95,9 @@ The various methods are split into files based on the category of behavior:
*/ */
package goquery 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 array.go : Positional Manipulation: First(), Last(), Eq(), Get(), Index(), Slice()
// DONE filter.go : Filtering: Filter(), Not(), Has(), End() // DONE filter.go : Filtering: Filter(), Not(), Has(), End()
// DONE expand.go : "Expanding": Add(), AndSelf() // DONE expand.go : "Expanding": Add(), AndSelf()
@@ -115,7 +118,7 @@ package goquery
// x Children() // x Children()
// - Closest() - Tree Traversal // - Closest() - Tree Traversal
// x Contains() // x Contains()
// - Contents() (similar to Children(), but includes text and comment nodes, so Children() should filter them out) - Misc. Traversing // x Contents()
// x Each() // x Each()
// x End() // x End()
// x Eq() // x Eq()
@@ -125,7 +128,7 @@ package goquery
// x Get() // x Get()
// x Has() // x Has()
// x HasClass() // x HasClass()
// - Html() ? - Attributes // x Html()
// x Index() // x Index()
// x Is() - Filtering // x Is() - Filtering
// x Last() // x Last()
@@ -147,4 +150,3 @@ package goquery
// x Text() - DOM Manipulation // x Text() - DOM Manipulation
// x ToArray() // x ToArray()
// x Unique() internally only // x Unique() internally only
// - Val() ? - Attributes

View File

@@ -21,6 +21,22 @@ func TestEach(t *testing.T) {
} }
} }
func TestEachEmptySelection(t *testing.T) {
var cnt int
sel := Doc().Find("zzzz")
sel.Each(func(i int, n *Selection) {
cnt++
})
if cnt > 0 {
t.Error("Expected Each() to not be called on empty Selection.")
}
sel2 := sel.Find("div")
if sel2.Nodes != nil {
t.Error("Expected Find() on empty Selection to return an empty Selection.")
}
}
func TestMap(t *testing.T) { func TestMap(t *testing.T) {
sel := Doc().Find(".pvk-content") sel := Doc().Find(".pvk-content")
vals := sel.Map(func(i int, s *Selection) string { vals := sel.Map(func(i int, s *Selection) string {

View File

@@ -3,7 +3,6 @@ package goquery
import ( import (
"code.google.com/p/cascadia" "code.google.com/p/cascadia"
"exp/html" "exp/html"
"strings"
) )
// TODO : Maybe make the Document's Root return a Selection, Find() on the // TODO : Maybe make the Document's Root return a Selection, Find() on the
@@ -40,24 +39,52 @@ func findWithContext(selector string, nodes ...*html.Node) []*html.Node {
return matches return matches
} }
// TODO : Tests and doc for contents and children // Contents() gets the children of each element in the Selection,
// including text and comment nodes. It returns a new Selection object
// containing these elements.
func (this *Selection) Contents() *Selection { func (this *Selection) Contents() *Selection {
var matches []*html.Node return pushStack(this, getSelectionChildren(this, false))
for _, n := range this.Nodes {
matches = appendWithoutDuplicates(matches, getChildren(n, false))
}
return pushStack(this, matches)
} }
func (this *Selection) Children() *Selection { // ContentsFiltered() gets the children of each element in the Selection,
var matches []*html.Node // filtered by the specified selector. It returns a new Selection
// object containing these elements. Since selectors only act on Element nodes,
for _, n := range this.Nodes { // this function is an alias to ChildrenFiltered() unless the selector is empty,
matches = appendWithoutDuplicates(matches, getChildren(n, true)) // in which case it is an alias to Contents().
func (this *Selection) ContentsFiltered(selector string) *Selection {
if selector != "" {
return this.ChildrenFiltered(selector)
} }
return pushStack(this, matches) return this.Contents()
}
// Children() gets the child elements of each element in the Selection.
// It returns a new Selection object containing these elements.
func (this *Selection) Children() *Selection {
return pushStack(this, getSelectionChildren(this, true))
}
// ChildrenFiltered() gets the child elements of each element in the Selection,
// filtered by the specified selector. It returns a new
// Selection object containing these elements.
func (this *Selection) ChildrenFiltered(selector string) *Selection {
// Get the Children() unfiltered
nodes := getSelectionChildren(this, true)
// Create a temporary Selection to filter using winnow
sel := &Selection{nodes, this.document, nil}
// Filter based on selector
nodes = winnow(sel, selector, true)
// Push on the stack and return the "real" Selection
return pushStack(this, nodes)
}
// Return the child nodes of each node in the Selection object, without
// duplicates.
func getSelectionChildren(s *Selection, elemOnly bool) (result []*html.Node) {
for _, n := range s.Nodes {
result = appendWithoutDuplicates(result, getChildren(n, elemOnly))
}
return
} }
// Return the immediate children of the node, filtered on element nodes only // Return the immediate children of the node, filtered on element nodes only

View File

@@ -28,22 +28,6 @@ func TestFindInvalidSelector(t *testing.T) {
Doc().Find(":+ ^") Doc().Find(":+ ^")
} }
func TestEachEmptySelection(t *testing.T) {
var cnt int
sel := Doc().Find("zzzz")
sel.Each(func(i int, n *Selection) {
cnt++
})
if cnt > 0 {
t.Error("Expected Each() to not be called on empty Selection.")
}
sel2 := sel.Find("div")
if sel2.Nodes != nil {
t.Error("Expected Find() on empty Selection to return an empty Selection.")
}
}
func TestChainedFind(t *testing.T) { func TestChainedFind(t *testing.T) {
sel := Doc().Find("div.hero-unit").Find(".row-fluid") sel := Doc().Find("div.hero-unit").Find(".row-fluid")
if sel.Nodes == nil || len(sel.Nodes) != 4 { if sel.Nodes == nil || len(sel.Nodes) != 4 {
@@ -53,6 +37,16 @@ func TestChainedFind(t *testing.T) {
func TestChildren(t *testing.T) { func TestChildren(t *testing.T) {
sel := Doc().Find(".pvk-content").Children() sel := Doc().Find(".pvk-content").Children()
if len(sel.Nodes) != 5 {
t.Errorf("Expected 5 child nodes, got %v.", len(sel.Nodes))
for _, n := range sel.Nodes {
t.Logf("%+v", n)
}
}
}
func TestContents(t *testing.T) {
sel := Doc().Find(".pvk-content").Contents()
if len(sel.Nodes) != 13 { if len(sel.Nodes) != 13 {
t.Errorf("Expected 13 child nodes, got %v.", len(sel.Nodes)) t.Errorf("Expected 13 child nodes, got %v.", len(sel.Nodes))
for _, n := range sel.Nodes { for _, n := range sel.Nodes {
@@ -71,6 +65,16 @@ func TestChildrenFiltered(t *testing.T) {
} }
} }
func TestContentsFiltered(t *testing.T) {
sel := Doc().Find(".pvk-content").ContentsFiltered(".hero-unit")
if len(sel.Nodes) != 1 {
t.Errorf("Expected 1 child nodes, got %v.", len(sel.Nodes))
for _, n := range sel.Nodes {
t.Logf("%+v", n)
}
}
}
func TestChildrenFilteredNone(t *testing.T) { func TestChildrenFilteredNone(t *testing.T) {
sel := Doc().Find(".pvk-content").ChildrenFiltered("a.btn") sel := Doc().Find(".pvk-content").ChildrenFiltered("a.btn")
if len(sel.Nodes) != 0 { if len(sel.Nodes) != 0 {