From 23441bb5a4a0bf50451f56b20e3376a468c71afb Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 14 Aug 2014 18:17:08 +0200 Subject: [PATCH] Basic support for the XPath node() function. --- lib/oga/xpath/evaluator.rb | 53 +++++++++++++++++++ .../xpath/evaluator/functions/node_spec.rb | 50 +++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 spec/oga/xpath/evaluator/functions/node_spec.rb diff --git a/lib/oga/xpath/evaluator.rb b/lib/oga/xpath/evaluator.rb index 148c79a..dbafa39 100644 --- a/lib/oga/xpath/evaluator.rb +++ b/lib/oga/xpath/evaluator.rb @@ -420,6 +420,59 @@ module Oga return nodes end + ## + # Dispatches function calls to specific handlers. + # + # @param [Oga::XPath::Node] ast_node + # @param [Oga::XML::NodeSet] context + # @return [Oga::XML::NodeSet] + # + def on_call(ast_node, context) + name, test = *ast_node + + handler = name.gsub('-', '_') + + return send("on_call_#{handler}", test, context) + end + + ## + # Processes the `node` function call. The W3 was apparently too lazy to + # properly document this function in their official specification. From + # Wikipedia: + # + # node() + # finds any node at all. + # + # Based on trial and error this function appears to match the following: + # + # * elements + # * text nodes + # * comments + # * CDATA nodes + # + # In Oga this translates to the following two classes: + # + # * {Oga::XML::Element} + # * {Oga::XML::Text} + # + # @param [Oga::XPath::Node] ast_node + # @param [Oga::XML::NodeSet] context + # @return [Oga::XML::NodeSet] + # + def on_call_node(ast_node, context) + nodes = XML::NodeSet.new + + context.each do |context_node| + context_node.children.each do |child| + if child.is_a?(XML::Element) or child.is_a?(XML::Text) + nodes << child + end + 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/functions/node_spec.rb b/spec/oga/xpath/evaluator/functions/node_spec.rb new file mode 100644 index 0000000..1e9f145 --- /dev/null +++ b/spec/oga/xpath/evaluator/functions/node_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' + +describe Oga::XPath::Evaluator do + context 'node function' do + before do + @document = parse('foo') + @evaluator = described_class.new(@document) + end + + context 'matching elements' do + before do + @set = @evaluator.evaluate('node()') + end + + it_behaves_like :node_set, :length => 1 + + example 'return the node' do + @set[0].name.should == 'a' + end + end + + context 'matching nested elements' do + before do + @set = @evaluator.evaluate('a/node()') + end + + it_behaves_like :node_set, :length => 1 + + example 'return the node' do + @set[0].name.should == 'b' + end + end + + context 'matching text nodes' do + before do + @set = @evaluator.evaluate('a/b/node()') + end + + it_behaves_like :node_set, :length => 1 + + example 'return a Text instance' do + @set[0].is_a?(Oga::XML::Text).should == true + end + + example 'include the text' do + @set[0].text.should == 'foo' + end + end + end +end