diff --git a/lib/rexml/parsers/xpathparser.rb b/lib/rexml/parsers/xpathparser.rb index 7145d547..22f3c098 100644 --- a/lib/rexml/parsers/xpathparser.rb +++ b/lib/rexml/parsers/xpathparser.rb @@ -587,14 +587,21 @@ def PathExpr path, parsed path = path.lstrip n = [] rest = FilterExpr( path, n ) - if rest != path - if rest and rest[0] == ?/ + if rest == path + rest = LocationPath(rest, n) + else + if /\A\s*\//.match?(rest) + rest = rest.lstrip + if rest.start_with?('//') + n << :descendant_or_self + n << :node + rest = rest[2..-1] + else # starts with '/' + rest = rest[1..-1] + end rest = RelativeLocationPath(rest, n) - parsed.concat(n) - return rest end end - rest = LocationPath(rest, n) if rest =~ /\A[\/\.\@\[\w*]/ parsed.concat(n) rest end diff --git a/test/parser/test_xpath.rb b/test/parser/test_xpath.rb index c62c1391..2484ed29 100644 --- a/test/parser/test_xpath.rb +++ b/test/parser/test_xpath.rb @@ -129,5 +129,18 @@ def test_spaces_between_tokens parser.parse('//processing-instruction( "a" )'), ) end + + def test_mult_asterisk_without_surrounding_spaces + parser = REXML::Parsers::XPathParser.new + assert_equal(parser.parse("1 * 2 * 3"), parser.parse("1*2*3")) + assert_equal(parser.parse("a[( ( 1 + 2 ) * 3 + 4 * ( 5 + 6 ) ) * 7 < 8]"), parser.parse("a[((1+2)*3+4*(5+6))*7<8]")) + # number(a/b) * 2 + assert_equal(parser.parse("(a/b) * 2"), parser.parse("(a/b)*2")) + assert_equal(parser.parse("a/b * 2"), parser.parse("a/b*2")) + # number(a/b/*) * 2 + assert_equal(parser.parse("a/b/* * 2"), parser.parse("a/b/**2")) + # number(*) * number(*/*) * number(*) + assert_equal(parser.parse("* * */* * *"), parser.parse("***/***")) + end end end diff --git a/test/xpath/test_base.rb b/test/xpath/test_base.rb index c7049d67..f6d01d85 100644 --- a/test/xpath/test_base.rb +++ b/test/xpath/test_base.rb @@ -616,6 +616,33 @@ def test_nested_predicates assert_equal without_parentheses, with_parentheses end + def test_parenthesized_xpath + doc = Document.new <<-EOF +
+
+ ab +
cd
+
+
+ ef +
gh
+
+
+ hi +
+
+ EOF + parenthesized_xpath = '(//div[@id="1"] | //div[@id="2"])' + assert_equal(%w[ab ef], XPath.match(doc, "#{parenthesized_xpath}/test").map(&:text)) + assert_equal(%w[ab ef], XPath.match(doc, "#{parenthesized_xpath} / test").map(&:text)) + assert_equal(%w[ab cd ef gh], XPath.match(doc, "#{parenthesized_xpath}//test").map(&:text)) + assert_equal(%w[ab cd ef gh], XPath.match(doc, "#{parenthesized_xpath} // test").map(&:text)) + assert_equal(%w[ab], XPath.match(doc, "#{parenthesized_xpath}[@id='1']/test").map(&:text)) + assert_equal(%w[ef gh], XPath.match(doc, "#{parenthesized_xpath}[@id='2']//test").map(&:text)) + assert_equal(%w[ef], XPath.match(doc, "#{parenthesized_xpath}[2] / test").map(&:text)) + assert_equal(%w[ab cd], XPath.match(doc, "#{parenthesized_xpath}[1] // test").map(&:text)) + end + # Contributed by Mike Stok def test_starts_with source = <<-EOF