[前][次][番号順一覧][スレッド一覧]

ruby-changes:50997

From: kou <ko1@a...>
Date: Fri, 20 Apr 2018 06:34:46 +0900 (JST)
Subject: [ruby-changes:50997] kou:r63204 (trunk): rexml: Fix a XPath bug that white spaces aren't ignored

kou	2018-04-20 06:34:40 +0900 (Fri, 20 Apr 2018)

  New Revision: 63204

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=63204

  Log:
    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.

  Modified files:
    trunk/lib/rexml/parsers/xpathparser.rb
    trunk/test/rexml/xpath/test_base.rb
Index: test/rexml/xpath/test_base.rb
===================================================================
--- test/rexml/xpath/test_base.rb	(revision 63203)
+++ test/rexml/xpath/test_base.rb	(revision 63204)
@@ -632,29 +632,36 @@ module REXMLTests https://github.com/ruby/ruby/blob/trunk/test/rexml/xpath/test_base.rb#L632
           <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
Index: lib/rexml/parsers/xpathparser.rb
===================================================================
--- lib/rexml/parsers/xpathparser.rb	(revision 63203)
+++ lib/rexml/parsers/xpathparser.rb	(revision 63204)
@@ -185,7 +185,7 @@ module REXML https://github.com/ruby/ruby/blob/trunk/lib/rexml/parsers/xpathparser.rb#L185
       #  | '/' 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 https://github.com/ruby/ruby/blob/trunk/lib/rexml/parsers/xpathparser.rb#L209
       #  | 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 https://github.com/ruby/ruby/blob/trunk/lib/rexml/parsers/xpathparser.rb#L244
             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 https://github.com/ruby/ruby/blob/trunk/lib/rexml/parsers/xpathparser.rb#L279
       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 https://github.com/ruby/ruby/blob/trunk/lib/rexml/parsers/xpathparser.rb#L314
           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 https://github.com/ruby/ruby/blob/trunk/lib/rexml/parsers/xpathparser.rb#L517
       #| 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 https://github.com/ruby/ruby/blob/trunk/lib/rexml/parsers/xpathparser.rb#L537
       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

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]