Проверка дубликатов Python ElementTree - PullRequest
2 голосов
/ 14 марта 2011

Итак, мне нужно написать «дублирующую проверку», чтобы сравнить два XML-файла и посмотреть, совпадают ли они (содержат одинаковые данные). Теперь, поскольку они принадлежат одному и тому же классу и генерируются из XSD, структура, скорее всего, порядок элементов внутри будет одинаковым.

Лучший способ подумать о проверке дубликатов - это установить два словаря (dictLeft, dictRight) и сохранить значение xpath # в качестве ключа и количество раз, когда оно происходит. Примерно так:

Слева:

{ 'my/path/to/name#greg': 1, 'my/path/to/name#john': 2, 'my/path/to/car#toyota': 1}

правый

{ 'my/path/to/name#greg': 1, 'my/path/to/name#bill': 1, 'my/path/to/car#toyota': 1}

Сравнение этих двух словарей даст мне достаточно точное указание на то, являются ли эти два XML одинаковыми или нет (есть странный шанс, что я могу получить ложные результаты, но это очень далеко).

У кого-нибудь есть идея получше? Может быть, функция в ElementTree, о которой я не знаю?

РЕДАКТИРОВАТЬ: Чтобы лучше объяснить:

<root><person><name>Bob</name><surname>marley</surname></root>

и

<root><person><surname>marley</surname><name>Bob</name></root>

будет считаться тем же. Я игнорирую атрибуты. Идея состоит в том, чтобы сделать код как можно более простым, не сильно снижая производительность.

Ответы [ 4 ]

1 голос
/ 16 марта 2011

ОК, поэтому мне пришлось принять решение и пойти с этим:

foreach path in xpathlist
  find entries for path for both xml1 and xml2
  foreach entry in xmlentries1
    dict1[path#entry.value]++
  foreach entry in xmlentries2
    dict2[path#entry.value]++

  if dict1 and dict2 are not equal
    return false
return true

Надеюсь, это имеет смысл. Это позволяет мне проверять определенные / все xpaths. Если у кого-то есть лучший алгоритм, у меня все уши:)

0 голосов
/ 14 марта 2011

Если два XML-файла генерируются из одного и того же кода и содержат одинаковые значения (в одном и том же порядке), то вы можете просто выполнить сравнение строк данных XML.

Если это сработает, возможно, это простое решение, но могут быть причины, по которым это не сработает.

0 голосов
/ 14 марта 2011

Эта проблема начинается с определения того, что вы подразумеваете под «тем же».

Например, простое определение равенства для элементов XML состоит в том, что два элемента XML равны, если:

  • они находятся в одном пространстве имен,
  • они имеют одинаковое имя тега,
  • они имеют одинаковый набор атрибутов с одинаковыми значениями,
  • их соответствующие списки дочерних узлов, исключая комментарии и инструкции по обработке, и текстовые узлы только для пробелов, содержат одинаковые значения в том же порядке.

Существует множество причин, по которым этого тривиального определения может быть недостаточно:

  • вы можете захотеть игнорировать элементы, которые не находятся в пространствах имен, о которых вы знаете - то есть вы не хотите, чтобы тест на равенство вашего приложения провалился только потому, что другие приложения хранят данные в XML
  • Порядок следования дочерних элементов может быть незначительным или (что еще хуже) может быть значительным для некоторых элементов, но не для других
  • примечания, инструкции обработки и текстовые узлы только для пробелов могут быть значительными
  • вам может потребоваться нормализовать пробелы (см. Функцию normalize-space() в XSLT) в текстовых узлах перед их сравнением

Как только вы определили равенство, реализовать метод для его проверки относительно просто. Но сначала нужно определить равенство.

0 голосов
/ 14 марта 2011

Из вашего примера кажется, что вы должны иметь возможность использовать iterparse и использовать collection.Counter для подсчета появления каждого тега и его атрибутов в качестве ключей для счетчика.Пример:

from xml.etree import cElementTree as ElementTree
from collections import Counter

your_xml = get_xml()
count = Counter()
parser = ElementTree.iterparse(your_xml)
for event, element in parser:
    #joining string as key for ease of debugging, strictly speaking,
    #one could use a tuple and save the str() on the attrib dict
    key = "".join((element.tag, str(element.attrib), element.text))
    count[element.tag] += 1

альтернативно, сделайте подсчет нормальным и только сравните равенство двух (кажется мне концептуально проще).

...