Skip to content

Commit 9ea2ef4

Browse files
committed
pull317
1 parent b504245 commit 9ea2ef4

3 files changed

Lines changed: 43 additions & 9 deletions

File tree

lib/rexml/parsers/xpathparser.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,7 @@ def PrimaryExpr path, parsed
654654
contents = contents[1..-2]
655655
n = []
656656
OrExpr( contents, n )
657-
parsed.concat(n)
657+
parsed.push(:group, n)
658658
end
659659
path
660660
end

lib/rexml/xpath_parser.rb

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,18 @@ def expr( path_stack, nodeset, context=nil )
439439
end
440440
Functions.context = target_context
441441
return Functions.send(func_name, *args)
442-
442+
when :group
443+
sub_expression = path_stack.shift
444+
result = expr(sub_expression, nodeset, context)
445+
if result.is_a?(Array)
446+
# If result is a nodeset, apply following predicates
447+
path_stack.unshift(:node)
448+
nodeset = step(path_stack) do
449+
[result]
450+
end
451+
else
452+
return result
453+
end
443454
else
444455
raise "[BUG] Unexpected path: <#{op.inspect}>: <#{path_stack.inspect}>"
445456
end
@@ -592,7 +603,6 @@ def filter_nodeset(nodeset)
592603

593604
def evaluate_predicate(expression, nodesets)
594605
enter(:predicate, expression, nodesets) if @debug
595-
new_nodeset_count = 0
596606
new_nodesets = nodesets.collect do |nodeset|
597607
new_nodeset = []
598608
subcontext = { :size => nodeset.size }
@@ -609,20 +619,17 @@ def evaluate_predicate(expression, nodesets)
609619
result = result[0] if result.kind_of? Array and result.length == 1
610620
if result.kind_of? Numeric
611621
if result == node.position
612-
new_nodeset_count += 1
613-
new_nodeset << XPathNode.new(node, position: new_nodeset_count)
622+
new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
614623
end
615624
elsif result.instance_of? Array
616625
if result.size > 0 and result.inject(false) {|k,s| s or k}
617626
if result.size > 0
618-
new_nodeset_count += 1
619-
new_nodeset << XPathNode.new(node, position: new_nodeset_count)
627+
new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
620628
end
621629
end
622630
else
623631
if result
624-
new_nodeset_count += 1
625-
new_nodeset << XPathNode.new(node, position: new_nodeset_count)
632+
new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
626633
end
627634
end
628635
end

test/xpath/test_base.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,18 +582,45 @@ def test_nested_predicates
582582
matches = XPath.match(doc, '(/div/div/test[3])').map(&:text)
583583
assert_equal [], matches
584584

585+
matches = XPath.match(doc, '/div/div/test[1][1]').map(&:text)
586+
assert_equal ["ab", "ef", "hi"], matches
585587
matches = XPath.match(doc, '(/div/div/test[1])[1]').map(&:text)
586588
assert_equal ["ab"], matches
589+
matches = XPath.match(doc, '/div/div/test[1][2]').map(&:text)
590+
assert_equal [], matches
587591
matches = XPath.match(doc, '(/div/div/test[1])[2]').map(&:text)
588592
assert_equal ["ef"], matches
589593
matches = XPath.match(doc, '(/div/div/test[1])[3]').map(&:text)
590594
assert_equal ["hi"], matches
595+
matches = XPath.match(doc, '/div/div/test[2][1]').map(&:text)
596+
assert_equal ["cd", "gh"], matches
591597
matches = XPath.match(doc, '(/div/div/test[2])[1]').map(&:text)
592598
assert_equal ["cd"], matches
599+
matches = XPath.match(doc, '/div/div/test[2][2]').map(&:text)
600+
assert_equal [], matches
593601
matches = XPath.match(doc, '(/div/div/test[2])[2]').map(&:text)
594602
assert_equal ["gh"], matches
595603
matches = XPath.match(doc, '(/div/div/test[2])[3]').map(&:text)
596604
assert_equal [], matches
605+
matches = XPath.match(doc, '//div[1]/test|//div[2]/test[2]').map(&:text)
606+
assert_equal ["ab", "cd", "gh"], matches
607+
matches = XPath.match(doc, '(//div[1]/test|//div[2]/test)[2]').map(&:text)
608+
assert_equal ["cd"], matches
609+
610+
xpath = '/div/div/test/preceding::*'
611+
without_parentheses = XPath.match(doc, xpath).map(&:text)
612+
with_parentheses = XPath.match(doc, "(#{xpath})").map(&:text)
613+
assert_equal without_parentheses, with_parentheses
614+
615+
xpath = '/div/div/test/preceding-sibling::*'
616+
without_parentheses = XPath.match(doc, xpath).map(&:text)
617+
with_parentheses = XPath.match(doc, "(#{xpath})").map(&:text)
618+
assert_equal without_parentheses, with_parentheses
619+
620+
xpath = '/div/div/test/ancestor::*'
621+
without_parentheses = XPath.match(doc, xpath).map(&:text)
622+
with_parentheses = XPath.match(doc, "(#{xpath})").map(&:text)
623+
assert_equal without_parentheses, with_parentheses
597624
end
598625

599626
# Contributed by Mike Stok

0 commit comments

Comments
 (0)