Skip to content

Commit

Permalink
xpath: Fix wrong position with nested path (#122)
Browse files Browse the repository at this point in the history
## Why?
Fixed incorrect calculation of position in node set.

Fix GH-25

Reported by jcavalieri. Thanks!!!
  • Loading branch information
naitoh authored May 2, 2024
1 parent 030bfb4 commit 06be5cf
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 3 deletions.
10 changes: 7 additions & 3 deletions lib/rexml/xpath_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ def filter_nodeset(nodeset)

def evaluate_predicate(expression, nodesets)
enter(:predicate, expression, nodesets) if @debug
new_nodeset_count = 0
new_nodesets = nodesets.collect do |nodeset|
new_nodeset = []
subcontext = { :size => nodeset.size }
Expand All @@ -606,17 +607,20 @@ def evaluate_predicate(expression, nodesets)
result = result[0] if result.kind_of? Array and result.length == 1
if result.kind_of? Numeric
if result == node.position
new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
new_nodeset_count += 1
new_nodeset << XPathNode.new(node, position: new_nodeset_count)
end
elsif result.instance_of? Array
if result.size > 0 and result.inject(false) {|k,s| s or k}
if result.size > 0
new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
new_nodeset_count += 1
new_nodeset << XPathNode.new(node, position: new_nodeset_count)
end
end
else
if result
new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
new_nodeset_count += 1
new_nodeset << XPathNode.new(node, position: new_nodeset_count)
end
end
end
Expand Down
40 changes: 40 additions & 0 deletions test/xpath/test_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,46 @@ def test_following
# puts results
#end

def test_nested_predicates
doc = Document.new <<-EOF
<div>
<div>
<test>ab</test>
<test>cd</test>
</div>
<div>
<test>ef</test>
<test>gh</test>
</div>
<div>
<test>hi</test>
</div>
</div>
EOF

matches = XPath.match(doc, '(/div/div/test[0])').map(&:text)
assert_equal [], matches
matches = XPath.match(doc, '(/div/div/test[1])').map(&:text)
assert_equal ["ab", "ef", "hi"], matches
matches = XPath.match(doc, '(/div/div/test[2])').map(&:text)
assert_equal ["cd", "gh"], matches
matches = XPath.match(doc, '(/div/div/test[3])').map(&:text)
assert_equal [], matches

matches = XPath.match(doc, '(/div/div/test[1])[1]').map(&:text)
assert_equal ["ab"], matches
matches = XPath.match(doc, '(/div/div/test[1])[2]').map(&:text)
assert_equal ["ef"], matches
matches = XPath.match(doc, '(/div/div/test[1])[3]').map(&:text)
assert_equal ["hi"], matches
matches = XPath.match(doc, '(/div/div/test[2])[1]').map(&:text)
assert_equal ["cd"], matches
matches = XPath.match(doc, '(/div/div/test[2])[2]').map(&:text)
assert_equal ["gh"], matches
matches = XPath.match(doc, '(/div/div/test[2])[3]').map(&:text)
assert_equal [], matches
end

# Contributed by Mike Stok
def test_starts_with
source = <<-EOF
Expand Down

0 comments on commit 06be5cf

Please sign in to comment.