diff options
-rw-r--r-- | lib/rexml/parsers/xpathparser.rb | 51 | ||||
-rw-r--r-- | test/rexml/xpath/test_base.rb | 51 |
2 files changed, 58 insertions, 44 deletions
diff --git a/lib/rexml/parsers/xpathparser.rb b/lib/rexml/parsers/xpathparser.rb index 9577b6dcbe..304dc51698 100644 --- a/lib/rexml/parsers/xpathparser.rb +++ b/lib/rexml/parsers/xpathparser.rb @@ -185,7 +185,7 @@ module REXML # | '/' RelativeLocationPath? # | '//' RelativeLocationPath def LocationPath path, parsed - path = path.strip + path = path.lstrip if path[0] == ?/ parsed << :document if path[1] == ?/ @@ -209,7 +209,12 @@ module REXML # | RelativeLocationPath '//' Step AXIS = /^(ancestor|ancestor-or-self|attribute|child|descendant|descendant-or-self|following|following-sibling|namespace|parent|preceding|preceding-sibling|self)::/ def RelativeLocationPath path, parsed - while path.size > 0 + loop do + original_path = path + path = path.lstrip + + return original_path if path.empty? + # (axis or @ or <child::>) nodetest predicate > # OR > / Step # (. or ..) > @@ -239,28 +244,25 @@ module REXML n = [] path = NodeTest( path, n) - if path[0] == ?[ - path = Predicate( path, n ) - end + path = Predicate( path, n ) parsed.concat(n) end - if path.size > 0 - if path[0] == ?/ - if path[1] == ?/ - parsed << :descendant_or_self - parsed << :node - path = path[2..-1] - else - path = path[1..-1] - end - else - return path - end + original_path = path + path = path.lstrip + return original_path if path.empty? + + return original_path if path[0] != ?/ + + if path[1] == ?/ + parsed << :descendant_or_self + parsed << :node + path = path[2..-1] + else + path = path[1..-1] end end - return path end # Returns a 1-1 map of the nodeset @@ -277,6 +279,8 @@ module REXML NODE_TYPE = /^(comment|text|node)\(\s*\)/m PI = /^processing-instruction\(/ def NodeTest path, parsed + original_path = path + path = path.lstrip case path when /^\*/ path = $' @@ -310,13 +314,17 @@ module REXML parsed << :qname parsed << prefix parsed << name + else + path = original_path end return path end # Filters the supplied nodeset on the predicate(s) def Predicate path, parsed - return nil unless path[0] == ?[ + original_path = path + path = path.lstrip + return original_path unless path[0] == ?[ predicates = [] while path[0] == ?[ path, expr = get_group(path) @@ -509,8 +517,7 @@ module REXML #| LocationPath #| FilterExpr ('/' | '//') RelativeLocationPath def PathExpr path, parsed - path =~ /^\s*/ - path = $' + path = path.lstrip n = [] rest = FilterExpr( path, n ) if rest != path @@ -530,7 +537,7 @@ module REXML def FilterExpr path, parsed n = [] path = PrimaryExpr( path, n ) - path = Predicate(path, n) if path and path[0] == ?[ + path = Predicate(path, n) parsed.concat(n) path end diff --git a/test/rexml/xpath/test_base.rb b/test/rexml/xpath/test_base.rb index f71be51e2f..935c8d54e4 100644 --- a/test/rexml/xpath/test_base.rb +++ b/test/rexml/xpath/test_base.rb @@ -632,29 +632,36 @@ module REXMLTests <c id='a'/> </b> <c id='b'/> + <c id='c'/> + <c/> </a>") - assert_equal( 1, REXML::XPath.match(doc, - "//*[local-name()='c' and @id='b']").size ) - assert_equal( 1, REXML::XPath.match(doc, - "//*[ local-name()='c' and @id='b' ]").size ) - assert_equal( 1, REXML::XPath.match(doc, - "//*[ local-name() = 'c' and @id = 'b' ]").size ) - assert_equal( 1, - REXML::XPath.match(doc, '/a/c[@id]').size ) - assert_equal( 1, - REXML::XPath.match(doc, '/a/c[(@id)]').size ) - assert_equal( 1, - REXML::XPath.match(doc, '/a/c[ @id ]').size ) - assert_equal( 1, - REXML::XPath.match(doc, '/a/c[ (@id) ]').size ) - assert_equal( 1, - REXML::XPath.match(doc, '/a/c[( @id )]').size ) - assert_equal( 1, REXML::XPath.match(doc.root, - '/a/c[ ( @id ) ]').size ) - assert_equal( 1, REXML::XPath.match(doc, - '/a/c [ ( @id ) ] ').size ) - assert_equal( 1, REXML::XPath.match(doc, - ' / a / c [ ( @id ) ] ').size ) + match = lambda do |xpath| + REXML::XPath.match(doc, xpath).collect(&:to_s) + end + assert_equal(["<c id='b'/>"], + match.call("//*[local-name()='c' and @id='b']")) + assert_equal(["<c id='b'/>"], + match.call("//*[ local-name()='c' and @id='b' ]")) + assert_equal(["<c id='b'/>"], + match.call("//*[ local-name() = 'c' and @id = 'b' ]")) + assert_equal(["<c id='b'/>", "<c id='c'/>"], + match.call('/a/c[@id]')) + assert_equal(["<c id='b'/>", "<c id='c'/>"], + match.call('/a/c[(@id)]')) + assert_equal(["<c id='b'/>", "<c id='c'/>"], + match.call('/a/c[ @id ]')) + assert_equal(["<c id='b'/>", "<c id='c'/>"], + match.call('/a/c[ (@id) ]')) + assert_equal(["<c id='b'/>", "<c id='c'/>"], + match.call('/a/c[( @id )]')) + assert_equal(["<c id='b'/>", "<c id='c'/>"], + match.call('/a/c[ ( @id ) ]')) + assert_equal(["<c id='b'/>", "<c id='c'/>"], + match.call('/a/c [ ( @id ) ] ')) + assert_equal(["<c id='b'/>", "<c id='c'/>"], + match.call(' / a / c [ ( @id ) ] ')) + assert_equal(["<c id='b'/>", "<c id='c'/>"], + match.call('/ a / child:: c [( @id )] /')) end def test_text_nodes |