-
-
Notifications
You must be signed in to change notification settings - Fork 76
/
Copy pathnavigator.go
162 lines (141 loc) · 3.49 KB
/
navigator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package idr
import (
"github.com/antchfx/xpath"
)
type navigator struct {
root, cur *Node
}
func (nav *navigator) Current() *Node {
return nav.cur
}
func (nav *navigator) NodeType() xpath.NodeType {
switch nav.cur.Type {
case DocumentNode:
return xpath.RootNode
case ElementNode:
return xpath.ElementNode
case TextNode:
return xpath.TextNode
case AttributeNode:
return xpath.AttributeNode
}
panic(nav.cur.Type.String())
}
func (nav *navigator) LocalName() string {
return nav.cur.Data
}
func (nav *navigator) Prefix() string {
if !IsXML(nav.cur) {
return ""
}
return XMLSpecificOf(nav.cur).NamespacePrefix
}
func (nav *navigator) NamespaceURL() string {
if !IsXML(nav.cur) {
return ""
}
return XMLSpecificOf(nav.cur).NamespaceURI
}
func (nav *navigator) Value() string {
return nav.cur.InnerText()
}
func (nav *navigator) Copy() xpath.NodeNavigator {
n := *nav
return &n
}
func (nav *navigator) MoveToRoot() {
nav.cur = nav.root
}
func (nav *navigator) MoveToParent() bool {
if nav.cur.Parent == nil {
return false
}
nav.cur = nav.cur.Parent
return true
}
func (nav *navigator) MoveToNextAttribute() bool {
if nav.cur.Type == AttributeNode {
// if we are currently on an AttributeNode, move to the next AttributeNode if there is one.
if nav.cur.NextSibling == nil || nav.cur.NextSibling.Type != AttributeNode {
return false
}
nav.cur = nav.cur.NextSibling
return true
}
// If we're not on an AttributeNode, then check its first child - because if there are
// AttributeNodes, they will always be packed first.
if nav.cur.FirstChild == nil || nav.cur.FirstChild.Type != AttributeNode {
return false
}
nav.cur = nav.cur.FirstChild
return true
}
func (nav *navigator) MoveToChild() bool {
if nav.cur.Type == AttributeNode {
// In xpath navigation, if we're on attribute, we will/should never move down to
// child of attribute (because there is none).
return false
}
n := nav.cur.FirstChild
for ; n != nil && n.Type == AttributeNode; n = n.NextSibling {
// this loop basically skips all the attribute nodes if any.
}
if n == nil {
return false
}
nav.cur = n
return true
}
func (nav *navigator) MoveToFirst() bool {
if nav.cur.Type == AttributeNode {
// once we're on attribute node, we're never asked to move around.
return false
}
n := nav.cur
for ; n.PrevSibling != nil && n.PrevSibling.Type != AttributeNode; n = n.PrevSibling {
// move to the first node that is not attribute node.
}
if n == nav.cur {
return false
}
nav.cur = n
return true
}
func (nav *navigator) String() string {
return nav.Value()
}
func (nav *navigator) MoveToNext() bool {
if nav.cur.Type == AttributeNode || nav.cur.NextSibling == nil {
// If on attribute, we never move.
return false
}
nav.cur = nav.cur.NextSibling
return true
}
func (nav *navigator) MoveToPrevious() bool {
if nav.cur.Type == AttributeNode {
// if on attribute, we never move.
return false
}
if nav.cur.PrevSibling == nil || nav.cur.PrevSibling.Type == AttributeNode {
return false
}
nav.cur = nav.cur.PrevSibling
return true
}
func (nav *navigator) MoveTo(other xpath.NodeNavigator) bool {
node, ok := other.(*navigator)
if !ok || node.root != nav.root {
return false
}
nav.cur = node.cur
return true
}
// Ensure *navigator implements xpath.NodeNavigator interface
var _ xpath.NodeNavigator = &navigator{}
func createNavigator(n *Node) *navigator {
return &navigator{root: n, cur: n}
}
func nodeFromIter(iter *xpath.NodeIterator) *Node {
return iter.Current().(*navigator).cur
}