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()".
This commit is contained in:
Yorick Peterse 2014-08-14 22:54:19 +02:00
parent a437d67573
commit d34e4697de
2 changed files with 43 additions and 2 deletions

View File

@ -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.

View File

@ -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