Skip to content

Commit 511abd5

Browse files
committed
Merge PR #117
2 parents 8d50c25 + 060b154 commit 511abd5

File tree

3 files changed

+65
-0
lines changed

3 files changed

+65
-0
lines changed

query.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ type ancestorQuery struct {
147147
name string
148148
iterator func() NodeNavigator
149149
table map[uint64]bool
150+
pos int
150151

151152
Self bool
152153
Input query
@@ -164,6 +165,8 @@ func (a *ancestorQuery) Select(t iterator) NodeNavigator {
164165
if node == nil {
165166
return nil
166167
}
168+
// Reset position for a new input context node
169+
a.pos = 0
167170
first := true
168171
node = node.Copy()
169172
a.iterator = func() NodeNavigator {
@@ -186,6 +189,8 @@ func (a *ancestorQuery) Select(t iterator) NodeNavigator {
186189
node_id := getHashCode(node.Copy())
187190
if _, ok := a.table[node_id]; !ok {
188191
a.table[node_id] = true
192+
// Increase position for each matched node in current input context
193+
a.pos++
189194
return node
190195
}
191196
}
@@ -215,6 +220,13 @@ func (a *ancestorQuery) Properties() queryProp {
215220
return queryProps.Position | queryProps.Count | queryProps.Cached | queryProps.Merge | queryProps.Reverse
216221
}
217222

223+
// position returns the ordinal of the current matched node within the axis
224+
// traversal for the current input context node. This is required so numeric
225+
// predicates like [1] or [2] on the ancestor axis resolve in axis order.
226+
func (a *ancestorQuery) position() int {
227+
return a.pos
228+
}
229+
218230
// attributeQuery is an XPath attribute node query.(@*)
219231
type attributeQuery struct {
220232
name string

xpath_axes_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,39 @@ func Test_ancestor(t *testing.T) {
3232
//test_xpath_elements(t, employee_example, `//ancestor::name`, 4, 9, 14)
3333
}
3434

35+
func Test_ancestor_predicate(t *testing.T) {
36+
doc := createElement(0, "",
37+
createElement(1, "html",
38+
createElement(2, "body",
39+
createElement(3, "h1"),
40+
createElement(4, "section",
41+
createElement(5, "div",
42+
createElement(6, "section",
43+
createElement(7, "div",
44+
createElement(8, "span"),
45+
),
46+
),
47+
),
48+
),
49+
createElement(9, "section",
50+
createElement(10, "div",
51+
createElement(11, "section",
52+
createElement(12, "div",
53+
createElement(13, "span"),
54+
),
55+
),
56+
),
57+
),
58+
),
59+
),
60+
)
61+
62+
test_xpath_elements(t, doc, `//span/ancestor::*`, 7, 6, 5, 4, 2, 1, 12, 11, 10, 9)
63+
test_xpath_elements(t, doc, `//span/ancestor::section`, 6, 4, 11, 9)
64+
test_xpath_elements(t, doc, `//span/ancestor::section[1]`, 6, 11)
65+
test_xpath_elements(t, doc, `//span/ancestor::section[2]`, 4, 9)
66+
}
67+
3568
func Test_ancestor_or_self(t *testing.T) {
3669
// Expected the value is [2, 3, 8, 13], but got [3, 2, 8, 13]
3770
test_xpath_elements(t, employee_example, `//employee/ancestor-or-self::*`, 3, 2, 8, 13)

xpath_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,26 @@ func (n *TNode) getAttribute(key string) string {
587587
return ""
588588
}
589589

590+
func createElement(line int, name string, children ...*TNode) *TNode {
591+
nodeType := ElementNode
592+
if name == "" {
593+
nodeType = RootNode
594+
}
595+
n := createNode(name, nodeType)
596+
n.lines = line
597+
for _, c := range children {
598+
c.Parent = n
599+
c.PrevSibling = n.LastChild
600+
if c.PrevSibling == nil {
601+
n.FirstChild = c
602+
} else {
603+
c.PrevSibling.NextSibling = c
604+
}
605+
n.LastChild = c
606+
}
607+
return n
608+
}
609+
590610
func createBookExample() *TNode {
591611
/*
592612
<?xml version="1.0" encoding="UTF-8"?>

0 commit comments

Comments
 (0)