Сравнение строк не всегда работает. Порядок атрибутов не должен иметь значения для рассмотрения двух узлов эквивалентными. Однако, если вы выполняете сравнение строк, порядок, очевидно, имеет значение.
Я не уверен, является ли это проблемой или функцией, но моя версия lxml.etree сохраняет порядок атрибутов, если они анализируются из файла или строки:
>>> from lxml import etree
>>> h1 = etree.XML('<hat color="blue" price="39.90"/>')
>>> h2 = etree.XML('<hat price="39.90" color="blue"/>')
>>> etree.tostring(h1) == etree.tostring(h2)
False
Это может зависеть от версии (я использую Python 2.7.3 с lxml.etree 2.3.2 в Ubuntu); Я помню, что не мог найти способ контролировать порядок атрибутов год назад или около того, когда я хотел (из соображений читабельности).
Поскольку мне нужно сравнить XML-файлы, созданные разными сериализаторами, я не вижу другого способа, кроме рекурсивного сравнения тега, текста, атрибутов и дочерних элементов каждого узла. И, конечно, хвост, если там есть что-нибудь интересное.
Сравнение lxml и xml.etree.ElementTree
Правда в том, что это может зависеть от реализации. По-видимому, lxml использует упорядоченный dict или что-то в этом роде, стандартный xml.etree.ElementTree не сохраняет порядок атрибутов:
Python 2.7.1 (r271:86832, Nov 27 2010, 17:19:03) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from lxml import etree
>>> h1 = etree.XML('<hat color="blue" price="39.90"/>')
>>> h2 = etree.XML('<hat price="39.90" color="blue"/>')
>>> etree.tostring(h1) == etree.tostring(h2)
False
>>> etree.tostring(h1)
'<hat color="blue" price="39.90"/>'
>>> etree.tostring(h2)
'<hat price="39.90" color="blue"/>'
>>> etree.dump(h1)
<hat color="blue" price="39.90"/>>>> etree.dump(h2)
<hat price="39.90" color="blue"/>>>>
(Да, новые строки отсутствуют. Но это небольшая проблема.)
>>> import xml.etree.ElementTree as ET
>>> h1 = ET.XML('<hat color="blue" price="39.90"/>')
>>> h1
<Element 'hat' at 0x2858978>
>>> h2 = ET.XML('<hat price="39.90" color="blue"/>')
>>> ET.dump(h1)
<hat color="blue" price="39.90" />
>>> ET.dump(h2)
<hat color="blue" price="39.90" />
>>> ET.tostring(h1) == ET.tostring(h2)
True
>>> ET.dump(h1) == ET.dump(h2)
<hat color="blue" price="39.90" />
<hat color="blue" price="39.90" />
True
Другим вопросом может быть то, что считается неважным при сравнении. Например, некоторые фрагменты могут содержать лишние пробелы, и мы не хотим заботиться. Таким образом, всегда лучше написать некоторую сериализационную функцию, которая работает именно так, как нам нужно.