diff --git a/lib/rexml/parsers/xpathparser.rb b/lib/rexml/parsers/xpathparser.rb index 7145d547..25435295 100644 --- a/lib/rexml/parsers/xpathparser.rb +++ b/lib/rexml/parsers/xpathparser.rb @@ -103,14 +103,16 @@ def abbreviate(path_or_parsed) component << ']' when :document components << "" - when :function - component << parsed.shift - component << "( " - component << predicate_to_path(parsed.shift[0]) {|x| abbreviate(x)} - component << " )" - when :literal - component << quote_literal(parsed.shift) + when :function, :literal, :group, :neg, :and, :or, :mult, :plus, :minus, :neq, :eq, :lt, :gt, :lteq, :gteq, :div, :mod, :union + component = '' + components << component + parsed.unshift(op) + component << predicate_to_path(parsed) {|x| abbreviate(x)} else + unless component + component = '' + components << component + end component << "UNKNOWN(" component << op.inspect component << ")" @@ -188,6 +190,12 @@ def predicate_to_path(parsed, &block) op = "!=" when :union op = "|" + when :plus + op = "+" + when :minus + op = "-" + when :mult + op = "*" end left = predicate_to_path( parsed.shift, &block ) right = predicate_to_path( parsed.shift, &block ) @@ -196,6 +204,10 @@ def predicate_to_path(parsed, &block) path << op.to_s path << " " path << right + when :neg + parsed.shift + path << "-" + path << predicate_to_path( parsed, &block ) when :function parsed.shift name = parsed.shift @@ -209,6 +221,11 @@ def predicate_to_path(parsed, &block) when :literal parsed.shift path << quote_literal(parsed.shift) + when :group + parsed.shift + path << "(" + path << yield(parsed.shift) + path << ")" else path << yield( parsed ) end diff --git a/test/parser/test_xpath.rb b/test/parser/test_xpath.rb index c62c1391..06c2f138 100644 --- a/test/parser/test_xpath.rb +++ b/test/parser/test_xpath.rb @@ -16,6 +16,56 @@ def test_document abbreviate("/")) end + def test_raw_literal + assert_equal("1", + abbreviate("1")) + end + + def test_unary_operator + assert_equal("-1", + abbreviate("-1")) + assert_equal("/a[-/b]", + abbreviate("/a[-/b]")) + end + + def test_binary_operator + assert_equal("1 * 2 + 3 - 4", + abbreviate("1 * 2 + 3 - 4")) + assert_equal("/a | /b", + abbreviate("/a | /b")) + assert_equal("/a[1 + /b * 2]", + abbreviate("/a[1 + /b * 2]")) + end + + def test_operand_with_path + assert_equal("/a/b + 1", + abbreviate("/a/b + 1")) + end + + def test_paren + assert_equal("(1 + 2) * 3", + abbreviate("(1 + 2) * 3")) + end + + def test_predicate_paren + assert_equal("/a[(b + c) * d]", + abbreviate("/a[(b + c) * d]")) + end + + def test_path_paren + assert_equal("(a/b)[2]", + abbreviate("(a/b)[2]")) + end + + def test_unknown_not_infinitely_recursing + assert_instance_of(String, abbreviate([:unknown])) + end + + def test_function + assert_equal("string-length(a/b[last()])", + abbreviate("string-length(a/b[last()])")) + end + def test_descendant_or_self_only assert_equal("//", abbreviate("/descendant-or-self::node()/"))