Skip to content

Instantly share code, notes, and snippets.

@alexg0
Forked from superfeedr/node.rb
Created February 25, 2011 20:31
Show Gist options
  • Save alexg0/844439 to your computer and use it in GitHub Desktop.
Save alexg0/844439 to your computer and use it in GitHub Desktop.
require 'nokogiri'
module Nokogiri
module XML
class Node
##
# Returns true of the argument is semantically equivalent to self
# Equivalent is defined as follows :
# - same name
# - same attributes
# - same same default namespace (different definitions are ok)
# - same number of children
# - each child is equivalent to one child of the argument
# - the order of the children can be different
# - text content can be different by whitespace
def ===(_node)
_node = _node.root if _node.respond_to? :root
return root === _node if respond_to? :root
return false unless self.class == _node.class
if _node.name != self.name
false
# whitespace insensitive (not always accurate, but close)
elsif _node.text.gsub(/\s/,'') != self.text.gsub(/\s/,'')
false
elsif (
!_node.is_a?(Nokogiri::XML::Attr) and (
(!_node.namespace.nil? and self.namespace.nil?) or
(_node.namespace.nil? and !self.namespace.nil?) or
(!_node.namespace.nil? and !self.namespace.nil? and
_node.namespace.href != self.namespace.href)
)
)
false
elsif _node.attributes.count != self.attributes.count
false
elsif _node.children.count != self.children.count
false
else
attrs_match = _node.attributes.all? {|n,a|
attributes.any? {|m,b| a === b }
}
children_match = _node.children.all? { |c|
children.any? {|d| d === c }
}
attrs_match && children_match
end
end
end
end
end
require 'rubygems'
require 'node'
describe :=== do
before(:each) do
@doc = Nokogiri::XML::Document.new
end
describe "when comparing Attr" do
before(:each) do
@attr1 = Nokogiri::XML::Attr.new(@doc, "a")
@attr1.value = "a"
end
context "when the other attributes has a different name" do
before(:each) do
@attr2 = Nokogiri::XML::Attr.new(@doc, "b")
end
it "should return false" do
(@attr1 === @attr2).should be_false
end
end
context "when the other attributes has the same name but a different value" do
before(:each) do
@attr2 = Nokogiri::XML::Attr.new(@doc, "a")
@attr2.value = "b"
end
it "should return false" do
(@attr1 === @attr2).should be_false
end
end
context "when the other attributes has the same name and the same value" do
before(:each) do
@attr2 = Nokogiri::XML::Attr.new(@doc, "a")
@attr2.value = @attr1.value
end
it "should return false" do
(@attr1 === @attr2).should be_true
end
end
end
describe "when comparing Elements" do
context "when 2 nodes have different names" do
before(:each) do
@node1 = Nokogiri::XML::Node.new("node1", @doc)
@node2 = Nokogiri::XML::Node.new("node2", @doc)
end
it "should return false" do
(@node1 === @node2).should be_false
end
end
context "when 2 nodes have different set of attributes" do
before(:each) do
@node1 = Nokogiri::XML::Node.new("node1", @doc)
@node2 = Nokogiri::XML::Node.new("node1", @doc)
end
it "should return false if the 2 nodes don't have the same number of attributes" do
@node1["cool"] = "thegang"
@node1["jackson"] = "five"
@node2["jackson"] = "five"
(@node1 === @node2).should be_false
end
it "should return true if the 2 nodes have the same attributes but in a different order" do
@node1["cool"] = "thegang"
@node1["jackson"] = "five"
@node2["jackson"] = "five"
@node2["cool"] = "thegang"
(@node1 === @node2).should be_true
end
it "should return true if the 2 nodes have the same attributes but in the same order" do
@node1["cool"] = "thegang"
@node1["jackson"] = "five"
@node2["cool"] = "thegang"
@node2["jackson"] = "five"
(@node1 === @node2).should be_true
end
end
context "when 2 nodes have different default namespaces" do
before(:each) do
@node1 = Nokogiri::XML::Node.new("node1", @doc)
@node2 = Nokogiri::XML::Node.new("node1", @doc)
end
it "should return false if the 2 nodes don't have the same namespace" do
@node1.default_namespace= "http://mysupernamespace"
(@node1 === @node2).should be_false
end
it "should return true if the 2 have the same namespace" do
@node1.default_namespace= "http://mysupernamespace"
@node2.default_namespace= "http://mysupernamespace"
(@node1 === @node2).should be_true
end
it "should return true if the 2 have the same namespace, but then define different namespaces" do
@node1.default_namespace= "http://mysupernamespace"
@node1.add_namespace_definition("prefix", "http://anothernamespace")
@node2.default_namespace= "http://mysupernamespace"
(@node1 === @node2).should be_true
end
end
context "when 2 nodes have a different number of children" do
before(:each) do
@node1 = Nokogiri::XML::Node.new("node1", @doc)
@node1.add_child(Nokogiri::XML::Node.new("child1", @doc))
@node1.add_child(Nokogiri::XML::Node.new("child1", @doc))
@node2 = Nokogiri::XML::Node.new("node1", @doc)
@node2.add_child(Nokogiri::XML::Node.new("child1", @doc))
end
it "should return false" do
(@node1 === @node2).should be_false
end
end
context "when 2 nodes have a different text" do
before(:each) do
@node1 = Nokogiri::XML::Node.new("node1", @doc)
@node1.content= "hello world"
@node2 = Nokogiri::XML::Node.new("node1", @doc)
@node2.content= "Ciao"
end
it "should return false" do
(@node1 === @node2).should be_false
end
end
context "when 2 nodes have different children" do
before(:each) do
@node1 = Nokogiri::XML::Node.new("node1", @doc)
@node1.add_child(Nokogiri::XML::Node.new("child1", @doc))
@node1.add_child(Nokogiri::XML::Node.new("child2", @doc))
@node2 = Nokogiri::XML::Node.new("node1", @doc)
@node2.add_child(Nokogiri::XML::Node.new("child1", @doc))
@node2.add_child(Nokogiri::XML::Node.new("child2different", @doc))
end
it "should return false" do
(@node1 === @node2).should be_false
end
end
context "when 2 documents are identical" do
before(:each) do
@doc1 = Nokogiri::XML::Builder.new do |xml|
xml.root("age" => "23", "name" => "john Doe") {
xml.products {
xml.widget {
xml.id_ "10"
xml.name(:lang => "english") {
xml.text="Awesome widget"
}
}
xml.widget {
xml.id_ "11"
xml.name "Good widget"
}
}
}
end.doc
xml= <<-EOXML
<?xml version="1.0"?>
<root name='john Doe' age="23" >
<products>
<widget>
<id>11</id>
<name lang="english">Good widget</name>
</widget>
<widget>
<id>10</id>
<name>Awesome widget</name>
</widget>
</products>
</root>
EOXML
@doc2 = Nokogiri::XML(xml)
end
it "should return true" do
(@node1 === @node2).should be_true
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment