From d34e4697de9fd38c9ea86622a5bf1ef44d5bb194 Mon Sep 17 00:00:00 2001 From: Yorick Peterse <yorickpeterse@gmail.com> Date: Thu, 14 Aug 2014 22:54:19 +0200 Subject: [PATCH] Match node types in node_matches? The method XPath::Evaluator#node_matches? now has a special case to handle "type-test" nodes. This in turn fixes a bunch of failing tests such as those for the XPath query "parent::node()". --- lib/oga/xpath/evaluator.rb | 26 ++++++++++++++++++++++-- spec/oga/xpath/evaluator/general_spec.rb | 19 +++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/lib/oga/xpath/evaluator.rb b/lib/oga/xpath/evaluator.rb index 730c27e..0ba6968 100644 --- a/lib/oga/xpath/evaluator.rb +++ b/lib/oga/xpath/evaluator.rb @@ -476,12 +476,19 @@ module Oga # Checks if a given {Oga::XML::Node} instance matches a {Oga::XPath::Node} # instance. # - # Checking if a node matches happens in two steps: + # This method can use both "test" and "type-test" nodes. In case of + # "type-test" nodes the procedure is as following: + # + # 1. Evaluate the expression + # 2. If the return value is non empty return `true`, otherwise return + # `false` + # + # For "test" nodes the procedure is as following instead: # # 1. Match the name # 2. Match the namespace # - # In both cases a star (`*`) can be used as a wildcard. + # For both the name and namespace a wildcard (`*`) can be used. # # @param [Oga::XML::Node] xml_node # @param [Oga::XPath::Node] ast_node @@ -490,6 +497,10 @@ module Oga def node_matches?(xml_node, ast_node) ns, name = *ast_node + if ast_node.type == :type_test + return type_matches?(xml_node, ast_node) + end + # If only the name is given and is a wildcard then we'll also want to # match the namespace as a wildcard. if !ns and name == '*' @@ -509,6 +520,17 @@ module Oga return name_matches && ns_matches end + ## + # @param [Oga::XML::Node] xml_node + # @param [Oga::XPath::Node] ast_node + # @return [TrueClass|FalseClass] + # + def type_matches?(xml_node, ast_node) + context = XML::NodeSet.new([xml_node]) + + return process(ast_node, context).length > 0 + end + ## # Returns `true` if the name of the XML node matches the given name *or* # matches a wildcard. diff --git a/spec/oga/xpath/evaluator/general_spec.rb b/spec/oga/xpath/evaluator/general_spec.rb index 382caf0..e4ed0f6 100644 --- a/spec/oga/xpath/evaluator/general_spec.rb +++ b/spec/oga/xpath/evaluator/general_spec.rb @@ -77,6 +77,25 @@ describe Oga::XPath::Evaluator do example 'return true if a node with a namespace is matched using a wildcard' do @evaluator.node_matches?(@name_ns_node, s(:test, nil, '*')).should == true end + + example 'return true if the node type matches' do + @evaluator.node_matches?(@name_node, s(:type_test, 'node')).should == true + end + end + + context '#type_matches?' do + before do + @element = Oga::XML::Element.new(:name => 'a') + @ns = Oga::XML::Namespace.new(:name => 'a') + end + + example 'return true if the type matches' do + @evaluator.type_matches?(@element, s(:type_test, 'node')).should == true + end + + example 'return false if the type does not match' do + @evaluator.type_matches?(@ns, s(:type_test, 'node')).should == false + end end context '#has_parent?' do