Если проблема в действительности заключается только в пробелах и порядке атрибутов, и вам не о чем беспокоиться, кроме текста и элементов, вы можете проанализировать строки с помощью стандартного анализатора XML и сравнить узлы вручную. Вот пример использования minidom, но вы можете написать то же самое в etree довольно просто:
def isEqualXML(a, b):
da, db= minidom.parseString(a), minidom.parseString(b)
return isEqualElement(da.documentElement, db.documentElement)
def isEqualElement(a, b):
if a.tagName!=b.tagName:
return False
if sorted(a.attributes.items())!=sorted(b.attributes.items()):
return False
if len(a.childNodes)!=len(b.childNodes):
return False
for ac, bc in zip(a.childNodes, b.childNodes):
if ac.nodeType!=bc.nodeType:
return False
if ac.nodeType==ac.TEXT_NODE and ac.data!=bc.data:
return False
if ac.nodeType==ac.ELEMENT_NODE and not isEqualElement(ac, bc):
return False
return True
Если вам нужно более тщательное сравнение эквивалентностей, охватывающее возможности других типов узлов, включая CDATA, PI, ссылки на сущности, комментарии, типы документов, пространства имен и т. Д., Вы можете использовать базовый метод DOM уровня 3 isEqualNode. Ни у minidom, ни у etree этого нет, но pxdom - это одна из реализаций, которая поддерживает это:
def isEqualXML(a, b):
da, db= pxdom.parseString(a), pxdom.parseString(a)
return da.isEqualNode(db)
(Вы можете изменить некоторые параметры DOMConfiguration при разборе, если вам нужно указать, соответствуют ли ссылки на сущности и разделы CDATA их замененным эквивалентам.)
Немного более окольный способ сделать это - проанализировать, затем повторно сериализовать в каноническую форму и выполнить сравнение строк. Снова pxdom поддерживает опцию DOM Level 3 LS «canonical-form», которую вы можете использовать для этого; альтернативный способ использования реализации минидома в stdlib - использование c14n. Однако для этого вам необходимо установить расширения PyXML, поэтому вы все еще не можете сделать это в stdlib:
from xml.dom.ext import c14n
def isEqualXML(a, b):
da, bd= minidom.parseString(a), minidom.parseString(b)
a, b= c14n.Canonicalize(da), c14n.Canonicalize(db)
return a==b