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:
parent
56982dd543
commit
03f40d4024
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue