Skip to content
Open
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
2 changes: 1 addition & 1 deletion lib/rexml/parsers/xpathparser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ def PrimaryExpr path, parsed
contents = contents[1..-2]
n = []
OrExpr( contents, n )
parsed.concat(n)
parsed.push(:group, n)
end
path
end
Expand Down
23 changes: 15 additions & 8 deletions lib/rexml/xpath_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,18 @@ def expr( path_stack, nodeset, context=nil )
end
Functions.context = target_context
return Functions.send(func_name, *args)

when :group
sub_expression = path_stack.shift
result = expr(sub_expression, nodeset, context)
if result.is_a?(Array)
# If result is a nodeset, apply following predicates
path_stack.unshift(:node)
nodeset = step(path_stack) do
[result]
end
Comment on lines +442 to +450
else
return result
end
else
raise "[BUG] Unexpected path: <#{op.inspect}>: <#{path_stack.inspect}>"
end
Expand Down Expand Up @@ -594,7 +605,6 @@ 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 @@ -611,20 +621,17 @@ 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_count += 1
new_nodeset << XPathNode.new(node, position: new_nodeset_count)
new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
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_count += 1
new_nodeset << XPathNode.new(node, position: new_nodeset_count)
new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
end
end
else
if result
new_nodeset_count += 1
new_nodeset << XPathNode.new(node, position: new_nodeset_count)
new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
end
end
end
Expand Down
27 changes: 27 additions & 0 deletions test/xpath/test_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -575,18 +575,45 @@ def test_nested_predicates
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", "ef", "hi"], 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 [], 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", "gh"], 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 [], 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
matches = XPath.match(doc, '//div[1]/test|//div[2]/test[2]').map(&:text)
assert_equal ["ab", "cd", "gh"], matches
matches = XPath.match(doc, '(//div[1]/test|//div[2]/test)[2]').map(&:text)
assert_equal ["cd"], matches

xpath = '/div/div/test/preceding::*'
without_parentheses = XPath.match(doc, xpath).map(&:text)
with_parentheses = XPath.match(doc, "(#{xpath})").map(&:text)
assert_equal without_parentheses, with_parentheses

xpath = '/div/div/test/preceding-sibling::*'
without_parentheses = XPath.match(doc, xpath).map(&:text)
with_parentheses = XPath.match(doc, "(#{xpath})").map(&:text)
assert_equal without_parentheses, with_parentheses

xpath = '/div/div/test/ancestor::*'
without_parentheses = XPath.match(doc, xpath).map(&:text)
with_parentheses = XPath.match(doc, "(#{xpath})").map(&:text)
assert_equal without_parentheses, with_parentheses
end

# Contributed by Mike Stok
Expand Down
Loading