REXML 3.1.6 has XPath problems

K

Kouhei Sutou

----Next_Part(Sat_Dec_30_13_00_32_2006_860)--
Content-Type: Multipart/Mixed;
boundary="--Next_Part(Sat_Dec_30_13_00_32_2006_860)--"

----Next_Part(Sat_Dec_30_13_00_32_2006_860)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi,

I found some bugs of REXML 3.1.6 related XPath.

The following code raises an exception:

require 'rexml/document'

source = <<-XML
<a>
<b number='1' str='abc'>TEXT1</b>
<c number='1'/>
<c number='2' str='def'>
<b number='3'/>
<d number='1' str='abc'>TEXT2</d>
<b number='2'><!--COMMENT--></b>
</c>
</a>
XML
doc = REXML::Document.new(source)

predicate = "count(child::node()|following-sibling::node()|preceding-sibling::node())=0"
p REXML::XPath.match(doc, "/descendant-or-self::node()[#{predicate}]")

The exception is the following:
/usr/lib/ruby/1.8/rexml/xpath_parser.rb:335:in `expr': undefined method `children' for nil:NilClass (NoMethodError)
from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:334:in `each'
from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:334:in `expr'
from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:422:in `expr'
from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:421:in `expr'
from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:447:in `expr'
from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:445:in `collect'
from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:445:in `expr'
from /usr/lib/ruby/1.8/rexml/encoding.rb:47:in `each_with_index'
... 14 levels...
from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:125:in `match'
from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:56:in `parse'
from /usr/lib/ruby/1.8/rexml/xpath.rb:63:in `match'
from rexml-3.1.6-xpath-bug.rb:21


I'll attach a patch of test case and fixing.

Thanks,
--
kou

----Next_Part(Sat_Dec_30_13_00_32_2006_860)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="rexml-3.1.6-siblings-bug.diff"

diff -ru rexml_3.1.6.orig/src/rexml/xpath_parser.rb rexml_3.1.6/src/rexml/xpath_parser.rb
--- rexml_3.1.6.orig/src/rexml/xpath_parser.rb 2006-11-28 22:54:57.000000000 +0900
+++ rexml_3.1.6/src/rexml/xpath_parser.rb 2006-12-30 12:55:45.000000000 +0900
@@ -351,7 +351,8 @@
when :following_sibling
#puts "FOLLOWING_SIBLING 1: nodeset = #{nodeset}"
results = []
- for node in nodeset
+ nodeset.each do |node|
+ next if node.parent.nil?
all_siblings = node.parent.children
current_index = all_siblings.index( node )
following_siblings = all_siblings[ current_index+1 .. -1 ]
@@ -362,13 +363,14 @@

when :preceding_sibling
results = []
- for node in nodeset
+ nodeset.each do |node|
+ next if node.parent.nil?
all_siblings = node.parent.children
current_index = all_siblings.index( node )
- preceding_siblings = all_siblings[ 0 .. current_index-1 ].reverse
- #results += expr( path_stack.dclone, preceding_siblings )
+ preceding_siblings = all_siblings[ 0, current_index ].reverse
+ results += preceding_siblings
end
- nodeset = preceding_siblings || []
+ nodeset = results
node_types = ELEMENTS

when :preceding
diff -ru rexml_3.1.6.orig/test/xpath_test_pred.rb rexml_3.1.6/test/xpath_test_pred.rb
--- rexml_3.1.6.orig/test/xpath_test_pred.rb 2006-11-28 22:54:56.000000000 +0900
+++ rexml_3.1.6/test/xpath_test_pred.rb 2006-12-30 12:53:44.000000000 +0900
@@ -54,4 +54,27 @@
#puts path, @parser.parse( path ).inspect
return m
end
+
+ def test_get_no_siblings_terminal_nodes
+ source = <<-XML
+<a>
+ <b number='1' str='abc'>TEXT1</b>
+ <c number='1'/>
+ <c number='2' str='def'>
+ <b number='3'/>
+ <d number='1' str='abc'>TEXT2</d>
+ <b number='2'><!--COMMENT--></b>
+ </c>
+</a>
+XML
+ doc = REXML::Document.new(source)
+ predicate = "count(child::node()|" +
+ "following-sibling::node()|" +
+ "preceding-sibling::node())=0"
+ m = REXML::XPath.match(doc, "/descendant-or-self::node()[#{predicate}]")
+ assert_equal( [REXML::Text.new("TEXT1"),
+ REXML::Text.new("TEXT2"),
+ REXML::Comment.new("COMMENT")],
+ m )
+ end
end

----Next_Part(Sat_Dec_30_13_00_32_2006_860)----
----Next_Part(Sat_Dec_30_13_00_32_2006_860)----
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top