summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/rexml/parsers/xpathparser.rb51
-rw-r--r--test/rexml/xpath/test_base.rb51
2 files changed, 58 insertions, 44 deletions
diff --git a/lib/rexml/parsers/xpathparser.rb b/lib/rexml/parsers/xpathparser.rb
index 9577b6dcbee..304dc51698f 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 f71be51e2fc..935c8d54e40 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