Ripped out internal state of XPath::Evaluator.

Instead of keeping track of an internal state in @stack and @context the various
processing methods now take the context as an extra argument and return the
nodes they produced. This makes it easier to recursively call certain methods, a
requirement for processing XPath axes (e.g. the "ancestor" axis).
This commit is contained in:
Yorick Peterse 2014-07-14 00:07:43 +02:00
parent 56982dd543
commit 03f40d4024
1 changed files with 41 additions and 55 deletions

View File

@ -10,67 +10,51 @@ module Oga
# #
def initialize(document) def initialize(document)
@document = document @document = document
reset
end
def reset
@context = @document.children
@stack = XML::NodeSet.new
end end
def evaluate(string) def evaluate(string)
ast = Parser.new(string).parse ast = Parser.new(string).parse
context = @document.children
process(ast) return process(ast, context)
end
nodes = @stack def process(node, context)
handler = "on_#{node.type}"
reset return send(handler, node, context)
end
def on_absolute_path(node, context)
if @document.respond_to?(:root_node)
context = XML::NodeSet.new([@document.root_node])
end
return on_path(node, context)
end
def on_path(node, context)
last_node = node.children[-1]
nodes = XML::NodeSet.new
node.children.each do |test|
nodes = process(test, context)
if test != last_node and !nodes.empty?
context = child_nodes(context)
elsif nodes.empty?
break
end
end
return nodes return nodes
end end
def process(node) def on_test(node, context)
handler = "on_#{node.type}"
if respond_to?(handler)
send(handler, node)
end
end
def process_all(nodes)
nodes.each do |node|
process(node)
end
end
def on_absolute_path(node)
if @document.respond_to?(:root_node)
@context = XML::NodeSet.new([@document.root_node])
end
on_path(node)
end
def on_path(node)
last_node = node.children[-1]
node.children.each do |test|
process(test)
if test != last_node and !@stack.empty?
swap_context
elsif @stack.empty?
break
end
end
end
def on_test(node)
ns, name = *node ns, name = *node
nodes = XML::NodeSet.new
@context.each do |xml_node| context.each do |xml_node|
next unless xml_node.is_a?(XML::Element) next unless xml_node.is_a?(XML::Element)
name_matches = xml_node.name == name || name == '*' name_matches = xml_node.name == name || name == '*'
@ -86,21 +70,23 @@ module Oga
end end
if name_matches and ns_matches if name_matches and ns_matches
@stack << xml_node nodes << xml_node
end end
end end
return nodes
end end
def swap_context def child_nodes(nodes)
@context = XML::NodeSet.new children = XML::NodeSet.new
@stack.each do |xml_node| nodes.each do |xml_node|
xml_node.children.each do |child| xml_node.children.each do |child|
@context << child children << child
end end
end end
@stack = XML::NodeSet.new return children
end end
end # Evaluator end # Evaluator
end # XPath end # XPath