Support for the "following-sibling" axis.
This also comes with some small cleanups regarding XPath::Evaluator#node_matches?. This change removes the need to, every time, also use can_match_node?() to prevent NoMethodError errors from popping up.
This commit is contained in:
parent
57c0f4b35e
commit
a1f80b4995
|
@ -101,9 +101,7 @@ module Oga
|
|||
nodes = XML::NodeSet.new
|
||||
|
||||
context.each do |xml_node|
|
||||
if can_match_node?(xml_node) and node_matches?(xml_node, ast_node)
|
||||
nodes << xml_node
|
||||
end
|
||||
nodes << xml_node if node_matches?(xml_node, ast_node)
|
||||
end
|
||||
|
||||
return nodes
|
||||
|
@ -144,7 +142,7 @@ module Oga
|
|||
while has_parent?(xml_node)
|
||||
xml_node = xml_node.parent
|
||||
|
||||
if can_match_node?(xml_node) and node_matches?(xml_node, ast_node)
|
||||
if node_matches?(xml_node, ast_node)
|
||||
nodes << xml_node
|
||||
break
|
||||
end
|
||||
|
@ -265,8 +263,43 @@ module Oga
|
|||
|
||||
next unless check
|
||||
|
||||
if can_match_node?(doc_node) and node_matches?(doc_node, ast_node)
|
||||
nodes << doc_node if node_matches?(doc_node, ast_node)
|
||||
end
|
||||
end
|
||||
|
||||
return nodes
|
||||
end
|
||||
|
||||
##
|
||||
# Evaluates the `following-sibling` axis.
|
||||
#
|
||||
# @param [Oga::XPath::Node] ast_node
|
||||
# @param [Oga::XML::NodeSet] context
|
||||
# @return [Oga::XML::NodeSet]
|
||||
#
|
||||
def on_axis_following_sibling(ast_node, context)
|
||||
nodes = XML::NodeSet.new
|
||||
|
||||
context.each do |context_node|
|
||||
check = false
|
||||
parent = context_node.respond_to?(:parent) ? context_node.parent : nil
|
||||
|
||||
@document.each_node do |doc_node|
|
||||
# Skip child nodes of the current context node, compare all
|
||||
# following nodes.
|
||||
if doc_node == context_node
|
||||
check = true
|
||||
throw :skip_children
|
||||
end
|
||||
|
||||
if !check or parent != doc_node.parent
|
||||
next
|
||||
end
|
||||
|
||||
if node_matches?(doc_node, ast_node)
|
||||
nodes << doc_node
|
||||
|
||||
throw :skip_children
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -307,6 +340,8 @@ module Oga
|
|||
# @return [Oga::XML::NodeSet]
|
||||
#
|
||||
def node_matches?(xml_node, ast_node)
|
||||
return false unless can_match_node?(xml_node)
|
||||
|
||||
ns, name = *ast_node
|
||||
|
||||
name_matches = xml_node.name == name || name == '*'
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Oga::XPath::Evaluator do
|
||||
context 'following-sibling axis' do
|
||||
before do
|
||||
# Strip whitespace so it's easier to retrieve/compare elements.
|
||||
@document = parse(<<-EOF.strip.gsub(/\s+/m, ''))
|
||||
<root>
|
||||
<foo>
|
||||
<bar></bar>
|
||||
<baz>
|
||||
<baz></baz>
|
||||
</baz>
|
||||
</foo>
|
||||
<baz></baz>
|
||||
</root>
|
||||
EOF
|
||||
|
||||
@first_baz = @document.children[0].children[0].children[1]
|
||||
@second_baz = @first_baz.children[0]
|
||||
@third_baz = @document.children[0].children[1]
|
||||
@evaluator = described_class.new(@document)
|
||||
end
|
||||
|
||||
# This should return an empty set since the document doesn't have any
|
||||
# following nodes.
|
||||
context 'using a document as the root' do
|
||||
before do
|
||||
@set = @evaluator.evaluate('following-sibling::foo')
|
||||
end
|
||||
|
||||
it_behaves_like :empty_node_set
|
||||
end
|
||||
|
||||
context 'matching nodes in the current context' do
|
||||
before do
|
||||
@set = @evaluator.evaluate('root/foo/following-sibling::baz')
|
||||
end
|
||||
|
||||
it_behaves_like :node_set, :length => 1
|
||||
|
||||
example 'return the third <baz> node' do
|
||||
@set[0].should == @third_baz
|
||||
end
|
||||
end
|
||||
|
||||
context 'matching nodes in other contexts' do
|
||||
before do
|
||||
@set = @evaluator.evaluate('root/foo/bar/following-sibling::baz')
|
||||
end
|
||||
|
||||
it_behaves_like :node_set, :length => 1
|
||||
|
||||
example 'return the first <baz> node' do
|
||||
@set[0].should == @first_baz
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -61,6 +61,12 @@ describe Oga::XPath::Evaluator do
|
|||
example 'return true if a node is matched without having a namespace' do
|
||||
@evaluator.node_matches?(@name_node, s(:test, '*', 'a')).should == true
|
||||
end
|
||||
|
||||
example 'return false when trying to match an XML::Text instance' do
|
||||
text = Oga::XML::Text.new(:text => 'Foobar')
|
||||
|
||||
@evaluator.node_matches?(text, s(:test, nil, 'a')).should == false
|
||||
end
|
||||
end
|
||||
|
||||
context '#can_match_node?' do
|
||||
|
|
Loading…
Reference in New Issue