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
31 changes: 24 additions & 7 deletions lib/rexml/parsers/xpathparser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not good, but we need to do this to avoid infinite recursion of unknown operator.
predicate_to_path calls abbreviate if predicate_to_path doesn't know the operator.

Some possible workaround for this may break XPathParser#expand which is not tested and the spec is unknown.

component = ''
components << component
parsed.unshift(op)
component << predicate_to_path(parsed) {|x| abbreviate(x)}
Comment on lines +106 to +110
else
unless component
component = ''
components << component
end
component << "UNKNOWN("
component << op.inspect
component << ")"
Expand Down Expand Up @@ -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 )
Expand All @@ -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 )
Comment on lines +207 to +210
when :function
parsed.shift
name = parsed.shift
Expand All @@ -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
Expand Down
50 changes: 50 additions & 0 deletions test/parser/test_xpath.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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()/"))
Expand Down
Loading