diff --git a/lib/oga/xpath/evaluator.rb b/lib/oga/xpath/evaluator.rb index 438a9e2..9f161f8 100644 --- a/lib/oga/xpath/evaluator.rb +++ b/lib/oga/xpath/evaluator.rb @@ -241,6 +241,35 @@ module Oga return on_test(node, context) + on_axis_descendant(node, context) end + ## + # Evaluates the `following` axis. + # + # @param [Oga::XPath::Node] node + # @param [Oga::XML::NodeSet] context + # @return [Oga::XML::NodeSet] + # + def on_axis_following(node, context) + nodes = XML::NodeSet.new + + context.each do |context_node| + current = context_node + + while current.respond_to?(:next) + next_node = current.next + + if can_match_node?(next_node) and node_matches?(next_node, node) + nodes << next_node + end + + # When this returns nil the loop automaticall breaks since `nil` + # doesn't respond to `next`. + current = next_node + end + end + + return nodes + end + ## # Returns a node set containing all the child nodes of the given set of # nodes. diff --git a/spec/oga/xpath/evaluator/axes/following_spec.rb b/spec/oga/xpath/evaluator/axes/following_spec.rb new file mode 100644 index 0000000..a701b10 --- /dev/null +++ b/spec/oga/xpath/evaluator/axes/following_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe Oga::XPath::Evaluator do + context 'following axis' do + before do + document = parse('') + + @first_c = document.children[0].children[1] + @second_c = document.children[0].children[2] + @evaluator = described_class.new(document) + end + + # This should return an empty set since the document doesn't have any + # following nodes. + context 'using a document as the root' do + before do + @set = @evaluator.evaluate('following::a') + end + + it_behaves_like :empty_node_set + end + + context 'matching following elements using a name' do + before do + @set = @evaluator.evaluate('a/b/following::c') + end + + it_behaves_like :node_set, :length => 2 + + example 'return the first node' do + @set[0].should == @first_c + end + + example 'return the second node' do + @set[1].should == @second_c + end + end + + context 'matching following elements using a wildcard' do + before do + @set = @evaluator.evaluate('a/b/following::*') + end + + it_behaves_like :node_set, :length => 2 + end + end +end