Skip to content

Commit ff6960d

Browse files
authored
add {AncestorNodes, ChildNodes, DescendantNodes}() (#34)
1 parent c61987b commit ff6960d

File tree

4 files changed

+62
-22
lines changed

4 files changed

+62
-22
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,16 @@ type HtmlNode interface {
137137
// NextNodes return all of the nodes that was parsed after this node.
138138
NextNodes() []Node
139139

140+
// AncestorNodes returns an iterator over the ancestors of n,
141+
// starting with n.Parent.
142+
AncestorNodes() iter.Seq[Node]
143+
// ChildNodes returns an iterator over the immediate children of n,
144+
// starting with n.FirstChild.
145+
ChildNodes() iter.Seq[Node]
146+
// DescendantNodes returns an iterator over all nodes recursively
147+
// beneath n, excluding n itself. Nodes are visited in depth-first preorder.
148+
DescendantNodes() iter.Seq[Node]
149+
140150
// Finder includes a set of find methods.
141151
Finder
142152
}

go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
module github.com/sunshineplan/node
22

3-
go 1.21
3+
go 1.23
44

55
require (
66
github.com/antchfx/htmlquery v1.3.3
77
github.com/antchfx/xpath v1.3.2
88
github.com/ericchiang/css v1.4.0
9-
golang.org/x/net v0.30.0
9+
golang.org/x/net v0.31.0
1010
)
1111

1212
require (
1313
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
14-
golang.org/x/text v0.19.0 // indirect
14+
golang.org/x/text v0.20.0 // indirect
1515
)

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
1717
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
1818
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
1919
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
20-
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
21-
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
20+
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
21+
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
2222
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
2323
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
2424
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -36,8 +36,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
3636
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
3737
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
3838
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
39-
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
40-
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
39+
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
40+
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
4141
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
4242
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
4343
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=

node.go

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package node
22

33
import (
44
"io"
5+
"iter"
56
"strings"
67

78
"golang.org/x/net/html"
@@ -92,6 +93,16 @@ type HtmlNode interface {
9293
// NextNodes return all of the nodes that was parsed after this node.
9394
NextNodes() []Node
9495

96+
// AncestorNodes returns an iterator over the ancestors of n,
97+
// starting with n.Parent.
98+
AncestorNodes() iter.Seq[Node]
99+
// ChildNodes returns an iterator over the immediate children of n,
100+
// starting with n.FirstChild.
101+
ChildNodes() iter.Seq[Node]
102+
// DescendantNodes returns an iterator over all nodes recursively
103+
// beneath n, excluding n itself. Nodes are visited in depth-first preorder.
104+
DescendantNodes() iter.Seq[Node]
105+
95106
// Finder includes a set of find methods.
96107
Finder
97108
}
@@ -213,34 +224,23 @@ func (n *htmlNode) NextNode() Node {
213224
}
214225

215226
func (n *htmlNode) Parents() (parents []Node) {
216-
parent := n.Parent()
217-
for parent != nil {
227+
for parent := range n.AncestorNodes() {
218228
parents = append(parents, parent)
219-
parent = parent.Parent()
220229
}
221230
return
222231
}
223232

224233
func (n *htmlNode) Children() (children []Node) {
225-
child := n.FirstChild()
226-
for child != nil {
234+
for child := range n.ChildNodes() {
227235
children = append(children, child)
228-
child = child.NextSibling()
229236
}
230237
return
231238
}
232239

233240
func (n *htmlNode) Descendants() (nodes []Node) {
234-
var f func(Node)
235-
f = func(node Node) {
236-
if node.Raw() != n.Raw() {
237-
nodes = append(nodes, node)
238-
}
239-
for node := node.FirstChild(); node != nil; node = node.NextSibling() {
240-
f(node)
241-
}
241+
for node := range n.DescendantNodes() {
242+
nodes = append(nodes, node)
242243
}
243-
f(n.ToNode())
244244
return
245245
}
246246

@@ -280,6 +280,36 @@ func (n *htmlNode) NextNodes() (nextNodes []Node) {
280280
return
281281
}
282282

283+
func (n *htmlNode) AncestorNodes() iter.Seq[Node] {
284+
return func(yield func(Node) bool) {
285+
for c := range n.Ancestors() {
286+
if !yield(NewNode(c)) {
287+
return
288+
}
289+
}
290+
}
291+
}
292+
293+
func (n *htmlNode) ChildNodes() iter.Seq[Node] {
294+
return func(yield func(Node) bool) {
295+
for c := range n.Node.ChildNodes() {
296+
if !yield(NewNode(c)) {
297+
return
298+
}
299+
}
300+
}
301+
}
302+
303+
func (n *htmlNode) DescendantNodes() iter.Seq[Node] {
304+
return func(yield func(Node) bool) {
305+
for c := range n.Node.Descendants() {
306+
if !yield(NewNode(c)) {
307+
return
308+
}
309+
}
310+
}
311+
}
312+
283313
type node struct {
284314
*htmlNode
285315
}

0 commit comments

Comments
 (0)