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