diff options
author | Kouhei Sutou <[email protected]> | 2019-05-25 17:06:53 +0900 |
---|---|---|
committer | Hiroshi SHIBATA <[email protected]> | 2019-08-04 11:55:31 +0900 |
commit | 6ef82943978ea5816a91c32e9ff822c73d1935f9 () | |
tree | f04b130680d6817b4941e74d212df6faccd02e9a /lib/rexml/xpath_parser.rb | |
parent | c46ba8e9a3b1b6c13232c1af3e9f2efd4a3eec98 (diff) |
[ruby/rexml] xpath: fix a bug for equality or relational expressions
: fix #17 There is a bug when they are used against node set. They should return boolean value but they returned node set. Reported by Mirko Budszuhn. Thanks!!! https://.com/ruby/rexml/commit/a02bf38440
-rw-r--r-- | lib/rexml/xpath_parser.rb | 163 |
1 files changed, 86 insertions, 77 deletions
@@ -5,7 +5,6 @@ require "pp" require_relative 'namespace' require_relative 'xmltokens' require_relative 'attribute' -require_relative 'syncenumerator' require_relative 'parsers/xpathparser' class Object @@ -141,7 +140,7 @@ module REXML when Array # nodeset unnode(result) else - result end end @@ -341,26 +340,24 @@ module REXML var_name = path_stack.shift return [@variables[var_name]] - # :and, :or, :eq, :neq, :lt, :lteq, :gt, :gteq - # TODO: Special case for :or and :and -- not evaluate the right - # operand if the left alone determines result (i.e. is true for - # :or and false for :and). - when :eq, :neq, :lt, :lteq, :gt, :gteq, :or left = expr( path_stack.shift, nodeset.dup, context ) right = expr( path_stack.shift, nodeset.dup, context ) res = equality_relational_compare( left, op, right ) trace(op, left, right, res) if @debug return res when :and - left = expr( path_stack.shift, nodeset.dup, context ) - return [] unless left - if left.respond_to?(:inject) and !left.inject(false) {|a,b| a | b} - return [] - end - right = expr( path_stack.shift, nodeset.dup, context ) - res = equality_relational_compare( left, op, right ) - return res when :div, :mod, :mult, :plus, :minus left = expr(path_stack.shift, nodeset, context) @@ -397,31 +394,34 @@ module REXML when :function func_name = path_stack.shift.tr('-','_') arguments = path_stack.shift - subcontext = context ? nil : { :size => nodeset.size } - - res = [] - cont = context - nodeset.each_with_index do |node, i| - if subcontext - if node.is_a?(XPathNode) - subcontext[:node] = node.raw_node - subcontext[:index] = node.position - else - subcontext[:node] = node - subcontext[:index] = i - end - cont = subcontext - end - arg_clone = arguments.dclone - args = arg_clone.collect do |arg| - result = expr( arg, [node], cont ) - result = unnode(result) if result.is_a?(Array) - result end - Functions.context = cont - res << Functions.send( func_name, *args ) end - return res else raise "[BUG] Unexpected path: <#{op.inspect}>: <#{path_stack.inspect}>" @@ -806,31 +806,28 @@ module REXML end end - def equality_relational_compare( set1, op, set2 ) set1 = unnode(set1) if set1.is_a?(Array) set2 = unnode(set2) if set2.is_a?(Array) if set1.kind_of? Array and set2.kind_of? Array - if set1.size == 0 or set2.size == 0 - nd = set1.size==0 ? set2 : set1 - rv = nd.collect { |il| compare( il, op, nil ) } - return rv - else - res = [] - SyncEnumerator.new( set1, set2 ).each { |i1, i2| - i1 = norm( i1 ) - i2 = norm( i2 ) - res << compare( i1, op, i2 ) - } - return res end - end - # If one is nodeset and other is number, compare number to each item - # in nodeset s.t. number op number(string(item)) - # If one is nodeset and other is string, compare string to each item - # in nodeset s.t. string op string(item) - # If one is nodeset and other is boolean, compare boolean to each item - # in nodeset s.t. boolean op boolean(item) - if set1.kind_of? Array or set2.kind_of? Array if set1.kind_of? Array a = set1 b = set2 @@ -841,15 +838,23 @@ module REXML case b when true, false - return unnode(a) {|v| compare( Functions::boolean(v), op, b ) } when Numeric - return unnode(a) {|v| compare( Functions::number(v), op, b )} - when /^\d+(\.\d+)?$/ - b = Functions::number( b ) - return unnode(a) {|v| compare( Functions::number(v), op, b )} else - b = Functions::string( b ) - return unnode(a) { |v| compare( Functions::string(v), op, b ) } end else # If neither is nodeset, @@ -880,13 +885,12 @@ module REXML set2 = Functions::number( set2 ) end end - return compare( set1, op, set2 ) end - return false end - def compare a, op, b - case op when :eq a == b when :neq @@ -899,22 +903,27 @@ module REXML a > b when :gteq a >= b - when :and - a and b - when :or - a or b else - false end end - def unnode(nodeset) - nodeset.collect do |node| if node.is_a?(XPathNode) unnoded = node.raw_node else unnoded = node end unnoded = yield(unnoded) if block_given? unnoded end |