Skip to content

Commit

Permalink
Implement XML deep equal function (#3)
Browse files Browse the repository at this point in the history
* Implement XML deep equal function

* More tests

* More tests
  • Loading branch information
thms-rmb authored Oct 7, 2020
1 parent 48e9c65 commit 166b056
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 0 deletions.
85 changes: 85 additions & 0 deletions tind_commons/tests/test_xmlutils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import unittest
import xml.etree.ElementTree as ET

from tind_commons.xmlutils import deep_equal

class DeepEqualTests(unittest.TestCase):
def test_obviously_equal_documents(self):
doc = "<a>1<b>2</b>d</a>"

a_element = ET.fromstring(doc)
b_element = ET.fromstring(doc)

self.assertTrue(deep_equal(a_element, b_element))

def test_different_contents(self):
a_doc = "<a>1<b>2</b></a>"
b_doc = "<a>2<b>2</b></a>"

a_element = ET.fromstring(a_doc)
b_element = ET.fromstring(b_doc)

self.assertFalse(deep_equal(a_element, b_element))

def test_different_tails(self):
a_doc = "<a>1<b>2</b></a>"
b_doc = "<a>1<b>2</b> </a>"

a_element = ET.fromstring(a_doc)
b_element = ET.fromstring(b_doc)

self.assertFalse(deep_equal(a_element, b_element))

def test_attribute_order_is_insignificant(self):
a_doc = """<a b="c" d="e"></a>"""
b_doc = """<a d="e" b="c"></a>"""

a_element = ET.fromstring(a_doc)
b_element = ET.fromstring(b_doc)

self.assertTrue(deep_equal(a_element, b_element))

def test_all_attributes(self):
a_doc = """<a b="c" d="e"></a>"""
b_doc = """<a b="c"></a>"""

a_element = ET.fromstring(a_doc)
b_element = ET.fromstring(b_doc)

self.assertFalse(deep_equal(a_element, b_element))

def test_attribute_contents(self):
a_doc = """<a b="c"></a>"""
b_doc = """<a b="d"></a>"""

a_element = ET.fromstring(a_doc)
b_element = ET.fromstring(b_doc)

self.assertFalse(deep_equal(a_element, b_element))

def test_namespace_aware(self):
a_doc = """<a xmlns="foo"></a>"""
b_doc = """<a xmlns="bar"></a>"""

a_element = ET.fromstring(a_doc)
b_element = ET.fromstring(b_doc)

self.assertFalse(deep_equal(a_element, b_element))

def test_namespace_prefix_aware(self):
a_doc = """<x:a xmlns:x="foo"></x:a>"""
b_doc = """<a xmlns="foo"></a>"""

a_element = ET.fromstring(a_doc)
b_element = ET.fromstring(b_doc)

self.assertTrue(deep_equal(a_element, b_element))

def test_comments_are_insignificant(self):
a_doc = """<a><!-- This is a comment --></a>"""
b_doc = """<a></a>"""

a_element = ET.fromstring(a_doc)
b_element = ET.fromstring(b_doc)

self.assertTrue(deep_equal(a_element, b_element))
33 changes: 33 additions & 0 deletions tind_commons/xmlutils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
def deep_equal(a_element, b_element):
"""Computes whether two different elements are deep equal.
Two elements are considered deep equal if:
1. Their tag names are equal
2. Their attributes are equal
3. Their text contents (including the tail contents) are equal
3. Their children are pairwise deep equal
"""
if a_element.tag != b_element.tag:
return False

if len(a_element.items()) != len(b_element.items()):
return False

for key in a_element.keys():
if a_element.get(key) != b_element.get(key):
return False

if a_element.tail != b_element.tail:
return False

if a_element.text != b_element.text:
return False

if len(a_element) != len(b_element):
return False

for pair in zip(a_element, b_element):
if not deep_equal(*pair):
return False

return True

0 comments on commit 166b056

Please sign in to comment.