Как различать XML на уровне элементов, а не атрибуты? - PullRequest
4 голосов
/ 24 июня 2011

Мне нужно выполнить сравнение между двумя XML-документами.Я смотрел на множество различных xml-diffing инструментов, которые обычно упоминаются здесь о переполнении стека, но мои потребности, конечно, очень специфические и поэтому они не совсем подходят.Короче говоря, мне нужно сравнить не документы в целом , а скорее элемент содержимое (принимая во внимание заказ ), и мне нужно оченьконкретный формат вывода, а не традиционный патч diff.

Прошу прощения за этот объем текста, но мне сложно объяснить его короче.

Во-первых, мои ограничения

Решение должно быть на основе Java или может быть интегрировано с Java-приложением командной строки.Он также должен быть бесплатным, потому что мне не разрешается тратить «реальные деньги» на это, только мое рабочее время (но не слишком много, конечно, у меня нависает крайний срок) ... звучит знакомо?Наконец, моя цель - не традиционный результат сравнения патчей, а непростая комбинация обоих исходных файлов.

Во-вторых, описание моих данных

Каждый документ содержитузлы типа text или section;Тексты - это простые строки, но разделы могут содержать как текст, так и несколько разделов (они также имеют имя, заданное в качестве атрибута).Кроме того, каждый узел помечен информацией о редакции.

Вот пример документа.Обратите внимание, что для краткости это выглядит как список;в действительности это больше похоже на прозу - то есть порядок элементов очень важен.

<document diff="=" revision="1">
  <text diff="=" revision="1">Apples</text>
  <text diff="=" revision="1">Chxrries</text>
  <section diff="=" revision="1" name="Blue ones">
    <text diff="=" revision="1">Grapes</text>
    <section diff="=" revision="1" name="More">
      <text diff="=" revision="1">Blueberries</text>
    </section>
    <text diff="=" revision="1">Oranges</text>
  </section>
</document>

Это нужно сравнить с новой версией, которая содержит изменения, но не содержит информации о ревизиях (пока!),В этом примере я исправил опечатку во 2-м элементе и переместил другой элемент, но возможны гораздо более значительные изменения, такие как добавление или удаление целых разделов.

<document>
  <text>Apples</text>
  <text>Oranges</text>
  <text>Cherries</text>
  <section name="Blue ones">
    <text>Grapes</text>
    <section name="More">
      <text>Blueberries</text>
    </section>
  </section>
</document>

Цель состоит в том, чтобы создать третий документ XML со всей информацией.Обратите внимание, что теги diff затронутых элементов были изменены («*» представляет изменение внутри элемента), а их номера revision были увеличены;неизмененные элементы сохраняют свою старую информацию о ревизии.

<document diff="*" revision="2">
  <text diff="=" revision="1">Apples</text>
  <text diff="+" revision="2">Oranges</text>
  <text diff="-" revision="2">Chxrries</text>
  <text diff="+" revision="2">Cherries</text>
  <sectio diff="*" revision="1"n name="Blue ones">
    <text diff="=" revision="1">Grapes</text>
    <section diff="=" revision="1" name="More">
      <text diff="=" revision="1">Blueberries</text>
    </section>
    <text diff="-" revision="2">Oranges</text>
  </section>
</document>

В результате получается не diff-патч, а полный документ с обновленной информацией о ревизии.

В-третьих, что яу меня есть работа - и моя проблема

У меня есть большая часть этой работы, с использованием пользовательской функции Java, которая выполняет построчное сравнение - за исключением того, что она терпит неудачу в одном конкретном случае использования, а именночто когда старая версия содержит определенный текст более одного раза , и не последняя из них изменяется в новой версии.Это «обмануло» компаратор, чтобы сопоставить текст старой версии с , следующим за текстом новой версии, вместо распознавания однотекстового изменения того, чем оно является.Хотя результат технически правильный, добавленный «шум» ненужных добавлений и удалений маскирует этот факт, и для людей это просто беспорядок (и, кстати, эта разметка предназначена для для удобочитаемость человека).Теперь, именно из-за моего построчного подхода, это очень трудно исправить.

Вот пример использования, который обманывает мой код.Во-первых, простая корзина с фруктами:

<document diff="=" revision="1">
  <text diff="=" revision="1">Apples</text>
  <text diff="=" revision="1">Oranges</text>
  <text diff="=" revision="1">Apples</text>
  <text diff="=" revision="1">Cherries</text>
  <text diff="=" revision="1">Apples</text>
</document>

Теперь давайте изменим 2-й элемент «Яблоки»:

<document>
  <text>Apples</text>
  <text>Oranges</text>
  <text>Bananas</text>   <--- I've only changed this
  <text>Cherries</text>
  <text>Apples</text>
  <text>Grapes</text>
</document>

Результат, неверно, становится:

<document diff="*" revision="2">
  <text diff="=" revision="1">Apples</text>
  <text diff="=" revision="1">Oranges</text>
  <text diff="+" revision="2">Bananas</text>   <--- Addition, okay
  <text diff="+" revision="2">Cherries</text>   <--- Incorrectly added
  <text diff="=" revision="1">Apples</text>   <--- Incorrectly matches the next occurrence
  <text diff="-" revision="2">Cherries</text>   <--- Incorrectly removed
  <text diff="-" revision="2">Apples</text>   <--- Incorrectly removed
  <text diff="=" revision="1">Grapes</text>   <--- Back on track, after the next occurrence of the changed element
</document>

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

... в заключение, я отчаянно нуждаюсь в инструменте xml diff, который позволяет мне анализировать содержимое данных и создавать именно этот вывод.Либо это, либо любые советы, как мне избежать этой конкретной ловушки.

Если у вас есть какие-либо предложения или вопросы для уточнения, я очень хочу услышать от вас.


Это перефразировка предыдущего вопроса .К сожалению, я не в состоянии предложить какую-либо награду за его рекламу, но, надеюсь, мое новое объяснение здесь будет лучше.Кажется, 1074 * перечислены на странице DiffAlgorithm , с которой @LarsH ссылается:

Сравните два списка: назовите их lL и lR для левой и правой сторон.Создайте два «первичных» указателя iL и iR и установите их для первых элементов каждого списка.Для цикла используйте эти первичные указатели, чтобы установить первичные элементы eL и eR, чтобы eL = lL (iL) и eR = lR (iR).Сравните eL и eR.Если eL совпадает с eR, мы можем скопировать eL в результат как совпадение и продвинуть оба основных указателя на один слот.Если eL и eR не совпадают, создайте вторичный указатель (iR2), инициализируйте его в слоте после iR (iR2 = iR + 1) и просканируйте оставшуюся часть lR (установив eR2 = lR (iR2), как мы это делаем).Если eL не совпадает в оставшейся части lR, eL должен быть удален, и мы можем добавить eL к результату как удаление и выдвигать только первичный указатель iL (так, чтобы при следующем сравнении следующий eL сравнивался с тем же eR).Если обнаружено, что eL соответствует eR2 (в положении iR2> iR), то все элементы в диапазоне [iR, iR2 [должны быть добавлены.Затем мы можем добавить каждый элемент в этом диапазоне lR к результату как дополнение и установить iR = iR2.Мы также можем добавить элемент eL к результату как совпадение (потому что он был сопоставлен в eR2) и, наконец, повторить сравнение в новых позициях первичного указателя.Сделайте все это, перебирая короткие списки;затем добавьте остаток от lL как исключения или добавьте остаток от lR как добавления.

Ответы [ 2 ]

1 голос
/ 09 марта 2012

Оказывается, моя потребность не имела решения в то время!Тем временем я разработал свою собственную процедуру xml-diff, которая специфична для моей проблемы, поэтому я получил рабочее решение.

Затем, в конце 2011 года, было опубликовано: Slashdot: ИсследователиРасширяя Diff, Grep Unix Tools

Дартмутские компьютерщики представили варианты утилит командной строки grep и diff Unix, которые могут обрабатывать более сложные типы данных.Новые программы, называемые Context-Free Grep и Hierarchical Diff, предоставят возможность разбирать блоки данных, а не отдельные строки.Исследование частично финансировалось Google и Министерством энергетики США.

0 голосов
/ 24 июня 2011

+ 1 хороший вопрос. Я не могу придумать иного обходного пути, кроме предвидения, но вы можете найти что-то в литературе по алгоритмам сравнения (проверьте http://c2.com/cgi/wiki?DiffAlgorithm). Основан ли используемый вами алгоритм на алгоритме, описанном на этой странице? Если нет, то вы Возможно, вы захотите попробовать алгоритм, описанный там (Myers 1986). Похоже, что он предназначен для оптимизации количества операций сравнения в пределах ограничения, основанного на размере ввода.

Я попробовал программу O diff для XML diff (после удаления атрибутов ревизии), но не получил лучших результатов, чем ваша, поэтому сомневаюсь, что решение тривиально.

...