From f1d574f3422aa606cc137edbff9fa94ce70f924b Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Sat, 15 Nov 2014 00:31:44 +0100 Subject: [PATCH] Evaluate XPath predicates for every context node. Instead of evaluating a predicate once for all context nodes, they should instead be evaluated separately per context node. --- lib/oga/xpath/evaluator.rb | 40 +++++++++++---------- spec/oga/xpath/evaluator/predicates_spec.rb | 23 +++++++----- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/lib/oga/xpath/evaluator.rb b/lib/oga/xpath/evaluator.rb index d503351..47c9644 100644 --- a/lib/oga/xpath/evaluator.rb +++ b/lib/oga/xpath/evaluator.rb @@ -188,30 +188,32 @@ module Oga # def on_predicate(ast_node, context) test, predicate = *ast_node + final_nodes = XML::NodeSet.new - initial_nodes = process(test, context) - final_nodes = XML::NodeSet.new - xpath_index = 1 + context.each do |context_node| + initial_nodes = process(test, XML::NodeSet.new([context_node])) + xpath_index = 1 - initial_nodes.each do |xml_node| - retval = with_node_set(initial_nodes) do - process(predicate, XML::NodeSet.new([xml_node])) - end - - # Numeric values are used as node set indexes. - if retval.is_a?(Numeric) - final_nodes << xml_node if retval.to_i == xpath_index - - # Node sets, strings, booleans, etc - elsif retval - if retval.respond_to?(:empty?) and retval.empty? - next + initial_nodes.each do |xml_node| + retval = with_node_set(initial_nodes) do + process(predicate, XML::NodeSet.new([xml_node])) end - final_nodes << xml_node - end + # Numeric values are used as node set indexes. + if retval.is_a?(Numeric) + final_nodes << xml_node if retval.to_i == xpath_index - xpath_index += 1 + # Node sets, strings, booleans, etc + elsif retval + if retval.respond_to?(:empty?) and retval.empty? + next + end + + final_nodes << xml_node + end + + xpath_index += 1 + end end return final_nodes diff --git a/spec/oga/xpath/evaluator/predicates_spec.rb b/spec/oga/xpath/evaluator/predicates_spec.rb index 1e1d10d..1643735 100644 --- a/spec/oga/xpath/evaluator/predicates_spec.rb +++ b/spec/oga/xpath/evaluator/predicates_spec.rb @@ -3,18 +3,23 @@ require 'spec_helper' describe Oga::XPath::Evaluator do context 'predicates' do before do - @document = parse('1020') + @document = parse(<<-EOF) + + 10 + + 20 + 30 + + + EOF - @b1 = @document.children[0].children[0] - @b2 = @document.children[0].children[1] + @a1 = @document.at_xpath('root/a[1]') + @a2 = @document.at_xpath('root/b/a[1]') end - example 'evaluate a predicate that returns the first node' do - evaluate_xpath(@document, 'root/b[1]').should == node_set(@b1) - end - - example 'evaluate a predicate that returns the second node' do - evaluate_xpath(@document, 'root/b[2]').should == node_set(@b2) + example 'return a node set containing all first nodes' do + evaluate_xpath(@document, 'descendant-or-self::node()/a[1]') + .should == node_set(@a1, @a2) end end end