1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

rexml: Fix a XPath bug that white spaces aren't ignored

lib/rexml/parsers/xpathparser.rb: Ignore white spaces in relative
location path.

test/rexml/xpath/test_base.rb: Add more test patterns and use more
debug friendly assertion style.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63204 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
kou 2018-04-19 21:34:40 +00:00
parent 632e10cad3
commit 9090241e61
2 changed files with 58 additions and 44 deletions

View file

@ -185,7 +185,7 @@ module REXML
# | '/' RelativeLocationPath? # | '/' RelativeLocationPath?
# | '//' RelativeLocationPath # | '//' RelativeLocationPath
def LocationPath path, parsed def LocationPath path, parsed
path = path.strip path = path.lstrip
if path[0] == ?/ if path[0] == ?/
parsed << :document parsed << :document
if path[1] == ?/ if path[1] == ?/
@ -209,7 +209,12 @@ module REXML
# | RelativeLocationPath '//' Step # | RelativeLocationPath '//' Step
AXIS = /^(ancestor|ancestor-or-self|attribute|child|descendant|descendant-or-self|following|following-sibling|namespace|parent|preceding|preceding-sibling|self)::/ AXIS = /^(ancestor|ancestor-or-self|attribute|child|descendant|descendant-or-self|following|following-sibling|namespace|parent|preceding|preceding-sibling|self)::/
def RelativeLocationPath path, parsed 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 > # (axis or @ or <child::>) nodetest predicate >
# OR > / Step # OR > / Step
# (. or ..) > # (. or ..) >
@ -239,15 +244,17 @@ module REXML
n = [] n = []
path = NodeTest( path, n) path = NodeTest( path, n)
if path[0] == ?[
path = Predicate( path, n ) path = Predicate( path, n )
end
parsed.concat(n) parsed.concat(n)
end end
if path.size > 0 original_path = path
if path[0] == ?/ path = path.lstrip
return original_path if path.empty?
return original_path if path[0] != ?/
if path[1] == ?/ if path[1] == ?/
parsed << :descendant_or_self parsed << :descendant_or_self
parsed << :node parsed << :node
@ -255,13 +262,8 @@ module REXML
else else
path = path[1..-1] path = path[1..-1]
end end
else
return path
end end
end end
end
return path
end
# Returns a 1-1 map of the nodeset # Returns a 1-1 map of the nodeset
# The contents of the resulting array are either: # The contents of the resulting array are either:
@ -277,6 +279,8 @@ module REXML
NODE_TYPE = /^(comment|text|node)\(\s*\)/m NODE_TYPE = /^(comment|text|node)\(\s*\)/m
PI = /^processing-instruction\(/ PI = /^processing-instruction\(/
def NodeTest path, parsed def NodeTest path, parsed
original_path = path
path = path.lstrip
case path case path
when /^\*/ when /^\*/
path = $' path = $'
@ -310,13 +314,17 @@ module REXML
parsed << :qname parsed << :qname
parsed << prefix parsed << prefix
parsed << name parsed << name
else
path = original_path
end end
return path return path
end end
# Filters the supplied nodeset on the predicate(s) # Filters the supplied nodeset on the predicate(s)
def Predicate path, parsed def Predicate path, parsed
return nil unless path[0] == ?[ original_path = path
path = path.lstrip
return original_path unless path[0] == ?[
predicates = [] predicates = []
while path[0] == ?[ while path[0] == ?[
path, expr = get_group(path) path, expr = get_group(path)
@ -509,8 +517,7 @@ module REXML
#| LocationPath #| LocationPath
#| FilterExpr ('/' | '//') RelativeLocationPath #| FilterExpr ('/' | '//') RelativeLocationPath
def PathExpr path, parsed def PathExpr path, parsed
path =~ /^\s*/ path = path.lstrip
path = $'
n = [] n = []
rest = FilterExpr( path, n ) rest = FilterExpr( path, n )
if rest != path if rest != path
@ -530,7 +537,7 @@ module REXML
def FilterExpr path, parsed def FilterExpr path, parsed
n = [] n = []
path = PrimaryExpr( path, n ) path = PrimaryExpr( path, n )
path = Predicate(path, n) if path and path[0] == ?[ path = Predicate(path, n)
parsed.concat(n) parsed.concat(n)
path path
end end

View file

@ -632,29 +632,36 @@ module REXMLTests
<c id='a'/> <c id='a'/>
</b> </b>
<c id='b'/> <c id='b'/>
<c id='c'/>
<c/>
</a>") </a>")
assert_equal( 1, REXML::XPath.match(doc, match = lambda do |xpath|
"//*[local-name()='c' and @id='b']").size ) REXML::XPath.match(doc, xpath).collect(&:to_s)
assert_equal( 1, REXML::XPath.match(doc, end
"//*[ local-name()='c' and @id='b' ]").size ) assert_equal(["<c id='b'/>"],
assert_equal( 1, REXML::XPath.match(doc, match.call("//*[local-name()='c' and @id='b']"))
"//*[ local-name() = 'c' and @id = 'b' ]").size ) assert_equal(["<c id='b'/>"],
assert_equal( 1, match.call("//*[ local-name()='c' and @id='b' ]"))
REXML::XPath.match(doc, '/a/c[@id]').size ) assert_equal(["<c id='b'/>"],
assert_equal( 1, match.call("//*[ local-name() = 'c' and @id = 'b' ]"))
REXML::XPath.match(doc, '/a/c[(@id)]').size ) assert_equal(["<c id='b'/>", "<c id='c'/>"],
assert_equal( 1, match.call('/a/c[@id]'))
REXML::XPath.match(doc, '/a/c[ @id ]').size ) assert_equal(["<c id='b'/>", "<c id='c'/>"],
assert_equal( 1, match.call('/a/c[(@id)]'))
REXML::XPath.match(doc, '/a/c[ (@id) ]').size ) assert_equal(["<c id='b'/>", "<c id='c'/>"],
assert_equal( 1, match.call('/a/c[ @id ]'))
REXML::XPath.match(doc, '/a/c[( @id )]').size ) assert_equal(["<c id='b'/>", "<c id='c'/>"],
assert_equal( 1, REXML::XPath.match(doc.root, match.call('/a/c[ (@id) ]'))
'/a/c[ ( @id ) ]').size ) assert_equal(["<c id='b'/>", "<c id='c'/>"],
assert_equal( 1, REXML::XPath.match(doc, match.call('/a/c[( @id )]'))
'/a/c [ ( @id ) ] ').size ) assert_equal(["<c id='b'/>", "<c id='c'/>"],
assert_equal( 1, REXML::XPath.match(doc, match.call('/a/c[ ( @id ) ]'))
' / a / c [ ( @id ) ] ').size ) 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 end
def test_text_nodes def test_text_nodes