import unittest
import xml.parsers.expat
from itertools import starmap
try:
from itertools import zip_longest
except ImportError: # python 2.x
from itertools import izip_longest as zip_longest
from xml.dom.minidom import Document
from xml.dom.minidom import parse
from xml.dom.minidom import parseString
def convert_to_node(doc):
return doc.documentElement if isinstance(doc, Document) else doc
def xml_compare(left_doc, right_doc):
left_dom = convert_to_node(left_doc)
right_dom = convert_to_node(right_doc)
def compare_attributes(left, right):
return dict(left.items()) == dict(right.items())
def node_compare(left_node, right_node):
if left_node is None and right_node is None:
return True
elif left_node is None or right_node is None:
return False
if left_node.tagName != right_node.tagName:
return False
if not compare_attributes(left_node.attributes, right_node.attributes):
return False
nodes = zip_longest(left_node.childNodes, right_node.childNodes)
return all(starmap(node_compare, nodes))
return node_compare(left_dom, right_dom)
class TestDiffXML(unittest.TestCase):
def test_node_with_ordered_attributes(self):
dom1 = parseString(' ')
dom2 = parseString(' ')
self.assertTrue(xml_compare(dom1, dom2))
def test_node_with_unordered_attributes(self):
dom1 = parseString(' ')
dom2 = parseString(' ')
self.assertTrue(xml_compare(dom1, dom2))
def test_node_with_different_attributes(self):
dom1 = parseString('')
dom2 = parseString(' ')
self.assertFalse(xml_compare(dom1, dom2))
def test_xml_only_root(self):
dom1 = parseString("")
dom2 = parseString("")
self.assertTrue(xml_compare(dom1, dom2))
def test_none_node(self):
self.assertTrue(xml_compare(None, None))
self.assertFalse(xml_compare(None, parseString("")))
self.assertFalse(xml_compare(parseString(""), None))
def test_different_xml(self):
self.assertFalse(
xml_compare(parseString(""), parseString(""))
)
def test_malformed_xml(self):
with self.assertRaises(xml.parsers.expat.ExpatError):
xml_compare(parseString(""), parseString(""))
if __name__ == "__main__":
unittest.main(verbosity=2)