XPath compiler support for ancestor-or-self
This also comes with some changes to the specs as the old behaviour of the Evaluator was incorrect. The Evaluator would bail after matching a single node but instead it's meant to continue until it runs out of parent nodes.
This commit is contained in:
parent
d8fbaf75d8
commit
db39b25546
|
@ -27,6 +27,8 @@ module Oga
|
|||
# @private
|
||||
#
|
||||
class Node < BasicObject
|
||||
undef_method :!, :!=
|
||||
|
||||
# @return [Symbol]
|
||||
attr_reader :type
|
||||
|
||||
|
|
|
@ -16,7 +16,11 @@ module Oga
|
|||
STAR = '*'
|
||||
|
||||
# Node types that require a NodeSet to push nodes into.
|
||||
USE_NODESET = [:path, :absolute_path, :axis]
|
||||
USE_NODESET = [:path, :absolute_path, :axis, :predicate]
|
||||
|
||||
# Node types that require "compile" to define a block to call upon
|
||||
# matching a node.
|
||||
ADD_PUSH_BLOCK = [:axis, :predicate]
|
||||
|
||||
##
|
||||
# Compiles and caches an AST.
|
||||
|
@ -37,7 +41,7 @@ module Oga
|
|||
document = node_literal
|
||||
matched = matched_literal
|
||||
|
||||
if ast.type == :axis
|
||||
if ADD_PUSH_BLOCK.include?(ast.type)
|
||||
ruby_ast = process(ast, document) { |node| matched.push(node) }
|
||||
else
|
||||
ruby_ast = process(ast, document)
|
||||
|
@ -167,6 +171,30 @@ module Oga
|
|||
input.get(string(query))
|
||||
end
|
||||
|
||||
##
|
||||
# Processes the `ancestor-or-self` axis.
|
||||
#
|
||||
# @param [AST::Node] ast
|
||||
# @param [Oga::Ruby::Node] input
|
||||
# @return [Oga::Ruby::Node]
|
||||
#
|
||||
def on_axis_ancestor_or_self(ast, input, &block)
|
||||
parent_var = literal('parent')
|
||||
assign = parent_var.assign(input)
|
||||
has_parent = parent_var.respond_to?(symbol(:parent))
|
||||
.and(parent_var.parent)
|
||||
|
||||
body = has_parent.while_true do
|
||||
if_statement = process(ast, parent_var, &block).if_true do
|
||||
yield parent_var
|
||||
end
|
||||
|
||||
if_statement.followed_by(parent_var.assign(parent_var.parent))
|
||||
end
|
||||
|
||||
assign.followed_by(body)
|
||||
end
|
||||
|
||||
##
|
||||
# Processes a node test predicate.
|
||||
#
|
||||
|
|
|
@ -26,6 +26,11 @@ describe Oga::XPath::Compiler do
|
|||
evaluate_xpath(@c1, 'ancestor-or-self::*[1]').should == node_set(@c1)
|
||||
end
|
||||
|
||||
it 'returns a node set containing all ancestors' do
|
||||
evaluate_xpath(@c1, 'ancestor-or-self::*')
|
||||
.should == node_set(@c1, @b1, @a1)
|
||||
end
|
||||
|
||||
it 'returns an empty node set for non existing ancestors' do
|
||||
evaluate_xpath(@c1, 'ancestor-or-self::foo').should == node_set
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue