From 5adeae18d0e53fda3bcfb883b414dee8e3a9d87d Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 26 Mar 2015 01:13:55 +0100 Subject: [PATCH] XPath queries match nodes in the default namespace When querying an XML document that explicitly defines the default XML namespace the XPath evaluator now correctly matches all nodes within that namespace if no namespace prefix is given in the query. Previously this would always return an empty set. --- lib/oga/xpath/evaluator.rb | 5 + spec/oga/xpath/evaluator/general_spec.rb | 120 ++++++++++++++--------- 2 files changed, 79 insertions(+), 46 deletions(-) diff --git a/lib/oga/xpath/evaluator.rb b/lib/oga/xpath/evaluator.rb index ae154fb..2ba45ba 100644 --- a/lib/oga/xpath/evaluator.rb +++ b/lib/oga/xpath/evaluator.rb @@ -1657,6 +1657,11 @@ module Oga ns_matches = true end + if !ns and !ns_matches + ns_matches = xml_node.respond_to?(:default_namespace?) && + xml_node.default_namespace? + end + return name_matches && ns_matches end diff --git a/spec/oga/xpath/evaluator/general_spec.rb b/spec/oga/xpath/evaluator/general_spec.rb index 4ec3c90..b66eabb 100644 --- a/spec/oga/xpath/evaluator/general_spec.rb +++ b/spec/oga/xpath/evaluator/general_spec.rb @@ -62,61 +62,89 @@ describe Oga::XPath::Evaluator do end describe '#node_matches?' do - before do - @name_node = Oga::XML::Element.new(:name => 'a') - @name_ns_node = Oga::XML::Element.new(:name => 'b', :namespace_name => 'x') + describe 'without a namespace' do + before do + @node = Oga::XML::Element.new(:name => 'a') + end - @name_ns_node.register_namespace('x', 'y') + it 'returns true if a node is matched by its name' do + @evaluator.node_matches?(@node, s(:test, nil, 'a')).should == true + end + + it 'returns true if a node is matched by a wildcard name' do + @evaluator.node_matches?(@node, s(:test, nil, '*')).should == true + end + + it 'returns false if a node is not matched by its name' do + @evaluator.node_matches?(@node, s(:test, nil, 'foo')).should == false + end + + it 'returns true if a node is matched without having a namespace' do + @evaluator.node_matches?(@node, s(:test, '*', 'a')).should == true + end + + it 'returns true if the node type matches' do + @evaluator.node_matches?(@node, s(:type_test, 'node')).should == true + end + + it 'returns 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 - it 'returns true if a node is matched by its name' do - @evaluator.node_matches?(@name_node, s(:test, nil, 'a')).should == true + describe 'with a custom namespace' do + before do + @node = Oga::XML::Element.new(:name => 'b', :namespace_name => 'x') + + @node.register_namespace('x', 'y') + end + + it 'returns true if a node is matched by its name and namespace' do + @evaluator.node_matches?(@node, s(:test, 'x', 'b')).should == true + end + + it 'returns false if a node is not matched by its namespace' do + @evaluator.node_matches?(@node, s(:test, 'y', 'b')).should == false + end + + it 'returns true if a node is matched by a wildcard namespace' do + @evaluator.node_matches?(@node, s(:test, '*', 'b')).should == true + end + + it 'returns true if a node is matched by a full wildcard search' do + @evaluator.node_matches?(@node, s(:test, '*', '*')).should == true + end + + it 'returns false when the node has a namespace that is not given' do + @evaluator.node_matches?(@node, s(:test, nil, 'b')).should == false + end + + it 'returns true if a node with a namespace is matched using a wildcard' do + @evaluator.node_matches?(@node, s(:test, nil, '*')).should == true + end end - it 'returns true if a node is matched by a wildcard name' do - @evaluator.node_matches?(@name_node, s(:test, nil, '*')).should == true - end + describe 'using the default XML namespace' do + before do + @node = Oga::XML::Element.new(:name => 'a') + ns = Oga::XML::DEFAULT_NAMESPACE - it 'returns false if a node is not matched by its name' do - @evaluator.node_matches?(@name_node, s(:test, nil, 'foo')).should == false - end + @node.register_namespace(ns.name, ns.uri) + end - it 'returns true if a node is matched by its name and namespace' do - @evaluator.node_matches?(@name_ns_node, s(:test, 'x', 'b')).should == true - end + it 'returns true when the node name matches' do + @evaluator.node_matches?(@node, s(:test, nil, 'a')).should == true + end - it 'returns false if a node is not matched by its namespace' do - @evaluator.node_matches?(@name_ns_node, s(:test, 'y', 'b')).should == false - end + it 'returns true when the namespace prefix and node name match' do + @evaluator.node_matches?(@node, s(:test, 'xmlns', 'a')).should == true + end - it 'returns true if a node is matched by a wildcard namespace' do - @evaluator.node_matches?(@name_ns_node, s(:test, '*', 'b')).should == true - end - - it 'returns true if a node is matched by a full wildcard search' do - @evaluator.node_matches?(@name_ns_node, s(:test, '*', '*')).should == true - end - - it 'returns true if a node is matched without having a namespace' do - @evaluator.node_matches?(@name_node, s(:test, '*', 'a')).should == true - end - - it 'returns 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 - - it 'returns false when the node has a namespace that is not given' do - @evaluator.node_matches?(@name_ns_node, s(:test, nil, 'b')).should == false - end - - it 'returns true if a node with a namespace is matched using a wildcard' do - @evaluator.node_matches?(@name_ns_node, s(:test, nil, '*')).should == true - end - - it 'returns true if the node type matches' do - @evaluator.node_matches?(@name_node, s(:type_test, 'node')).should == true + it 'returns false when the node name does not match' do + @evaluator.node_matches?(@node, s(:test, nil, 'b')).should == false + end end end