diff --git a/lib/oga/xpath/evaluator.rb b/lib/oga/xpath/evaluator.rb index d1112b8..4d6e68d 100644 --- a/lib/oga/xpath/evaluator.rb +++ b/lib/oga/xpath/evaluator.rb @@ -13,8 +13,13 @@ module Oga end def evaluate(string) - ast = Parser.new(string).parse - context = @document.children + ast = Parser.new(string).parse + + if @document.is_a?(XML::Document) + context = @document.children + else + context = XML::NodeSet.new([@document]) + end return process(ast, context) end @@ -51,25 +56,12 @@ module Oga end def on_test(node, context) - ns, name = *node - nodes = XML::NodeSet.new + nodes = XML::NodeSet.new context.each do |xml_node| - next unless xml_node.is_a?(XML::Element) - - name_matches = xml_node.name == name || name == '*' - ns_matches = false - - if ns - ns_matches = xml_node.namespace == ns || ns == '*' - - # If there's no namespace given but the name matches we'll also mark - # the namespace as matching. - elsif name_matches - ns_matches = true - end - - if name_matches and ns_matches + # TODO: change this when attribute tests are implemented since those + # are not XML::Element instances. + if xml_node.is_a?(XML::Element) and node_matches?(xml_node, node) nodes << xml_node end end @@ -77,6 +69,29 @@ module Oga return nodes end + def on_axis(node, context) + name, test = *node + + return send("on_axis_#{name}", test, context) + end + + def on_axis_ancestor(node, context) + nodes = XML::NodeSet.new + + context.each do |xml_node| + while xml_node.respond_to?(:parent) and xml_node.parent + xml_node = xml_node.parent + + if node_matches?(xml_node, node) + nodes << xml_node + break + end + end + end + + return nodes + end + def child_nodes(nodes) children = XML::NodeSet.new @@ -88,6 +103,24 @@ module Oga return children end + + def node_matches?(xml_node, ast_node) + ns, name = *ast_node + + name_matches = xml_node.name == name || name == '*' + ns_matches = false + + if ns + ns_matches = xml_node.namespace == ns || ns == '*' + + # If there's no namespace given but the name matches we'll also mark + # the namespace as matching. + elsif name_matches + ns_matches = true + end + + return name_matches && ns_matches + end end # Evaluator end # XPath end # Oga