mirror of
https://github.com/PuerkitoBio/goquery
synced 2025-11-02 04:32:34 +08:00
add Next() and NextFiltered() with tests
This commit is contained in:
5
doc.go
5
doc.go
@@ -77,7 +77,6 @@ The various methods are split into files based on the category of behavior:
|
|||||||
|
|
||||||
* traversal.go : methods to traverse the HTML document tree.
|
* traversal.go : methods to traverse the HTML document tree.
|
||||||
- Children...()
|
- Children...()
|
||||||
- Closest()
|
|
||||||
- Contents()
|
- Contents()
|
||||||
- Find...()
|
- Find...()
|
||||||
- Next...()
|
- Next...()
|
||||||
@@ -103,7 +102,7 @@ package goquery
|
|||||||
// DONE expand.go : "Expanding": Add(), AndSelf()
|
// DONE expand.go : "Expanding": Add(), AndSelf()
|
||||||
// DONE query.go : Reflect (query) node: Is(), Contains(), HasClass()
|
// DONE query.go : Reflect (query) node: Is(), Contains(), HasClass()
|
||||||
// DONE property.go : Inspect node: Html(), Text(), Attr(), Length(), Size()
|
// DONE property.go : Inspect node: Html(), Text(), Attr(), Length(), Size()
|
||||||
// traversal.go : Traversal: Contents(), Find(), Children(), Parents...(), Next...(), Prev...(), Closest(), Siblings()
|
// traversal.go : Traversal: Contents(), Find(), Children(), Parents...(), Next...(), Prev...(), Siblings()
|
||||||
// DONE iteration.go : Iteration: Each(), Map()
|
// DONE iteration.go : Iteration: Each(), Map()
|
||||||
// DONE type.go : Selection and Document
|
// DONE type.go : Selection and Document
|
||||||
|
|
||||||
@@ -116,7 +115,7 @@ package goquery
|
|||||||
// x AndSelf()
|
// x AndSelf()
|
||||||
// x Attr()
|
// x Attr()
|
||||||
// x Children()
|
// x Children()
|
||||||
// - Closest() - Tree Traversal
|
// x Closest() ?
|
||||||
// x Contains()
|
// x Contains()
|
||||||
// x Contents()
|
// x Contents()
|
||||||
// x Each()
|
// x Each()
|
||||||
|
|||||||
8
testdata/page.html
vendored
8
testdata/page.html
vendored
@@ -14,14 +14,14 @@
|
|||||||
<link href="/css/pvk.min.css" rel="stylesheet" type="text/css">
|
<link href="/css/pvk.min.css" rel="stylesheet" type="text/css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid" id="cf1">
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
<div class="pvk-gutter">
|
<div class="pvk-gutter">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="pvk-content">
|
<div class="pvk-content">
|
||||||
<div ng-controller="HeroCtrl" class="hero-unit">
|
<div ng-controller="HeroCtrl" class="hero-unit">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid" id="cf2">
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
<div class="span12">
|
<div class="span12">
|
||||||
<h1>
|
<h1>
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="pvk-content">
|
<div class="pvk-content">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid" id="cf3">
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
<div ng-cloak="" view-on-display="" ng-controller="MsgCtrl" ng-class="{'displayed': blockIsDisplayed}" class="message-box">
|
<div ng-cloak="" view-on-display="" ng-controller="MsgCtrl" ng-class="{'displayed': blockIsDisplayed}" class="message-box">
|
||||||
<div ng-class="{'alert-info': isInfo, 'alert-error': !isInfo, 'displayed': isDisplayed}" class="alert">
|
<div ng-class="{'alert-info': isInfo, 'alert-error': !isInfo, 'displayed': isDisplayed}" class="alert">
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid" id="cf4">
|
||||||
<div ng-controller="ShareCtrl" ng-hide="isHidden" class="row-fluid center-content"></div>
|
<div ng-controller="ShareCtrl" ng-hide="isHidden" class="row-fluid center-content"></div>
|
||||||
</div>
|
</div>
|
||||||
<div ng-view=""></div>
|
<div ng-view=""></div>
|
||||||
|
|||||||
53
traversal.go
53
traversal.go
@@ -182,7 +182,7 @@ func (this *Selection) ParentsFilteredUntilNodes(filterSelector string, nodes ..
|
|||||||
// Siblings() gets the siblings of each element in the Selection. It returns
|
// Siblings() gets the siblings of each element in the Selection. It returns
|
||||||
// a new Selection object containing the matched elements.
|
// a new Selection object containing the matched elements.
|
||||||
func (this *Selection) Siblings() *Selection {
|
func (this *Selection) Siblings() *Selection {
|
||||||
return pushStack(this, getSiblingNodes(this.Nodes))
|
return pushStack(this, getSiblingNodes(this.Nodes, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SiblingsFiltered() gets the siblings of each element in the Selection
|
// SiblingsFiltered() gets the siblings of each element in the Selection
|
||||||
@@ -190,7 +190,26 @@ func (this *Selection) Siblings() *Selection {
|
|||||||
// matched elements.
|
// matched elements.
|
||||||
func (this *Selection) SiblingsFiltered(selector string) *Selection {
|
func (this *Selection) SiblingsFiltered(selector string) *Selection {
|
||||||
// Get the Siblings() unfiltered
|
// Get the Siblings() unfiltered
|
||||||
n := getSiblingNodes(this.Nodes)
|
n := getSiblingNodes(this.Nodes, 0)
|
||||||
|
// Create a temporary Selection to filter using winnow
|
||||||
|
sel := &Selection{n, this.document, nil}
|
||||||
|
// Filter based on selector
|
||||||
|
n = winnow(sel, selector, true)
|
||||||
|
return pushStack(this, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next() gets the immediately following sibling of each element in the
|
||||||
|
// Selection. It returns a new Selection object containing the matched elements.
|
||||||
|
func (this *Selection) Next() *Selection {
|
||||||
|
return pushStack(this, getSiblingNodes(this.Nodes, 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextFiltered() gets the immediately following sibling of each element in the
|
||||||
|
// Selection filtered by a selector. It returns a new Selection object
|
||||||
|
// containing the matched elements.
|
||||||
|
func (this *Selection) NextFiltered(selector string) *Selection {
|
||||||
|
// Get the Next() unfiltered
|
||||||
|
n := getSiblingNodes(this.Nodes, 1)
|
||||||
// Create a temporary Selection to filter using winnow
|
// Create a temporary Selection to filter using winnow
|
||||||
sel := &Selection{n, this.document, nil}
|
sel := &Selection{n, this.document, nil}
|
||||||
// Filter based on selector
|
// Filter based on selector
|
||||||
@@ -222,12 +241,36 @@ func getParentsNodes(nodes []*html.Node, stopSelector string, stopNodes []*html.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Internal implementation of sibling nodes that return a raw slice of matches.
|
// Internal implementation of sibling nodes that return a raw slice of matches.
|
||||||
func getSiblingNodes(nodes []*html.Node) []*html.Node {
|
func getSiblingNodes(nodes []*html.Node, siblingType int) []*html.Node {
|
||||||
|
// Sibling type means:
|
||||||
|
// -1 : previous node only
|
||||||
|
// 1 : next node only
|
||||||
|
// 0 : all but itself
|
||||||
return mapNodes(nodes, func(i int, n *html.Node) (result []*html.Node) {
|
return mapNodes(nodes, func(i int, n *html.Node) (result []*html.Node) {
|
||||||
|
var prev *html.Node
|
||||||
|
|
||||||
|
// Get the parent and loop through all children
|
||||||
if p := n.Parent; p != nil {
|
if p := n.Parent; p != nil {
|
||||||
for _, c := range p.Child {
|
for _, c := range p.Child {
|
||||||
if c != n && c.Type == html.ElementNode {
|
// Care only about elements
|
||||||
result = append(result, c)
|
if c.Type == html.ElementNode {
|
||||||
|
// Is it the existing node?
|
||||||
|
if c == n && siblingType == -1 {
|
||||||
|
// We want the previous node only, so append it and return
|
||||||
|
if prev != nil {
|
||||||
|
result = append(result, prev)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else if prev == n && siblingType == 1 {
|
||||||
|
// We want only the next node and this is it, so append it and return
|
||||||
|
result = append(result, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
prev = c
|
||||||
|
if c != n && siblingType == 0 {
|
||||||
|
// This is not the original node, so append it
|
||||||
|
result = append(result, c)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,3 +132,28 @@ func TestSiblingsFiltered(t *testing.T) {
|
|||||||
sel := Doc().Root.Find(".pvk-gutter").SiblingsFiltered(".pvk-content")
|
sel := Doc().Root.Find(".pvk-gutter").SiblingsFiltered(".pvk-content")
|
||||||
AssertLength(t, sel.Nodes, 3)
|
AssertLength(t, sel.Nodes, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNext(t *testing.T) {
|
||||||
|
sel := Doc().Root.Find("h1").Next()
|
||||||
|
AssertLength(t, sel.Nodes, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNext2(t *testing.T) {
|
||||||
|
sel := Doc().Root.Find(".close").Next()
|
||||||
|
AssertLength(t, sel.Nodes, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNextNone(t *testing.T) {
|
||||||
|
sel := Doc().Root.Find("small").Next()
|
||||||
|
AssertLength(t, sel.Nodes, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNextFiltered(t *testing.T) {
|
||||||
|
sel := Doc().Root.Find(".container-fluid").NextFiltered("div")
|
||||||
|
AssertLength(t, sel.Nodes, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNextFiltered2(t *testing.T) {
|
||||||
|
sel := Doc().Root.Find(".container-fluid").NextFiltered("[ng-view]")
|
||||||
|
AssertLength(t, sel.Nodes, 1)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user