Skip to content

Instantly share code, notes, and snippets.

@superfeedr
Created April 25, 2010 15:17
Show Gist options
  • Save superfeedr/378473 to your computer and use it in GitHub Desktop.
Save superfeedr/378473 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
def ===(_node)
if _node.name != self.name
false
elsif _node.text != self.text
false
elsif (
!_node.is_a?(Nokogiri::XML::Attr) and
!_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
_node.attributes.each do |n, a|
matched = false
self.attributes.each do |m, b|
if a === b
matched = true
end
end
return false unless matched
end
_node.children.each do |c|
matched = false
self.children.each do |d|
if d === c
matched = true
end
end
return false unless matched
end
true
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