Мне нужно выполнить сравнение между двумя 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 как добавления.