Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions query.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ func (a *ancestorQuery) Select(t iterator) NodeNavigator {
func (a *ancestorQuery) Evaluate(t iterator) interface{} {
a.Input.Evaluate(t)
a.iterator = nil
// Reset the table when re-evaluating to ensure clean state
a.table = nil
return a
}

Expand Down Expand Up @@ -829,6 +831,8 @@ func (f *filterQuery) Select(t iterator) NodeNavigator {

func (f *filterQuery) Evaluate(t iterator) interface{} {
f.Input.Evaluate(t)
// Reset the position map when re-evaluating to ensure clean state
f.positmap = nil
return f
}

Expand Down
22 changes: 22 additions & 0 deletions xpath_axes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,28 @@ func Test_ancestor_predicate(t *testing.T) {
test_xpath_elements(t, doc, `//span/ancestor::section[2]`, 4, 9)
}

func Test_ancestor_predicate_chain(t *testing.T) {
doc := createElement(0, "",
createElement(1, "html",
createElementAttr(2, "body", map[string]string{"itemscope": "", "itemtype": "Article"},
createElement(3, "section",
createElementAttr(4, "span", map[string]string{"itemprop": "author"}),
createElementAttr(5, "div", map[string]string{"itemscope": "", "itemtype": "Comment"},
createElementAttr(6, "span", map[string]string{"itemprop": "author"}),
createElement(7, "div",
createElementAttr(8, "span", map[string]string{"itemprop": "author"}),
),
),
),
),
),
)

// Find elements marked as "author" property whose closest "itemscope" ancestor is of "Comment" type.
// This should find "span" elements on lines 6 and 8, but not line 4 since that one is under "Article".
test_xpath_elements(t, doc, `//*[@itemprop="author"][ancestor::*[@itemscope][1][@itemtype="Comment"]]`, 6, 8)
}

func Test_ancestor_or_self(t *testing.T) {
// Expected the value is [2, 3, 8, 13], but got [3, 2, 8, 13]
test_xpath_elements(t, employee_example, `//employee/ancestor-or-self::*`, 3, 2, 8, 13)
Expand Down
19 changes: 16 additions & 3 deletions xpath_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"math"
"reflect"
"sort"
"strings"
"testing"
Expand Down Expand Up @@ -41,10 +42,14 @@ func (t testQuery) Properties() queryProp {

func test_xpath_elements(t *testing.T, root *TNode, expr string, expected ...int) {
result := selectNodes(root, expr)
assertEqual(t, len(expected), len(result))

for i := 0; i < len(expected); i++ {
assertEqual(t, expected[i], result[i].lines)
var gotLines []int
for i := 0; i < len(result); i++ {
gotLines = append(gotLines, result[i].lines)
}

if !reflect.DeepEqual(gotLines, expected) {
t.Fatalf("expected lines %+v, got %+v", expected, gotLines)
}
}

Expand Down Expand Up @@ -587,6 +592,14 @@ func (n *TNode) getAttribute(key string) string {
return ""
}

func createElementAttr(line int, name string, attrs map[string]string, children ...*TNode) *TNode {
el := createElement(line, name, children...)
for k, v := range attrs {
el.addAttribute(k, v)
}
return el
}

func createElement(line int, name string, children ...*TNode) *TNode {
nodeType := ElementNode
if name == "" {
Expand Down
Loading