Могу ли я использовать алгоритм сравнения с открытым текстом для отслеживания изменений XML?

Я работаю в Flex / AS3 над (для простоты) редактором XML. Мне нужно предоставить функцию отмены / повтора.

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


У меня вопрос: могу ли я использовать алгоритм сравнения текстов для отслеживания этих изменений XML?

Мои исследования в Интернете показывают, что я не могу этого сделать. Однако мне явно чего-то не хватает. Открытый текст diff обеспечивает следующие функциональные возможности:

diff(text, text') -> diffs
patch(text, diffs) -> text'

XML - это просто текст, так почему я не могу просто использовать diff () и patch () для надежного преобразования текста?

Например: допустим, я поэт. Когда я пишу стихи, я использую много необычных знаков препинания ... Вы знаете, например, ‹, / и>. (Вы можете увидеть, к чему я клоню ...) Если я пишу свои стихи в приложении, которое использует различия для обеспечения функциональности отмены / повтора, искажаются ли мои стихи, когда я отменяю / повторяю свои правки? Это просто текст! Почему это имеет значение для алгоритма?

Я здесь явно чего-то не понимаю ... Спасибо за объяснение! :)

ОБНОВЛЕНИЕ:

Некоторое обсуждение, с которым я столкнулся относительно различий XML с алгоритмом открытого текста:


Кроме того, я понимаю, что шаблон Command, вероятно, лучший способ реализовать Undo / Redo. Я упростил свой вариант использования для простоты и по-прежнему считаю, что сравнение XML - лучший подход.


person rinogo    schedule 12.03.2010    source источник
comment
Укажите, что заставляет вас думать, что вы не можете использовать этот подход. Единственная причина, которую я вижу при кратком рассмотрении, это если вы пытались частично или не в порядке отменить / повторить. Я могу придумать более лаконичные подходы, но это другой вопрос.   -  person msw    schedule 12.03.2010
comment
@rinogo: обе опубликованные вами ссылки посвящены сравнению HTML. Другое дело, если вы сравниваете правильно сформированный XML, поскольку инструмент diff может делать предположения.   -  person John Saunders    schedule 12.03.2010
comment
Джон, я думаю, ты что-то понял. Если подумать, все, что я прочитал, похоже, предполагает, что проблемы возникают, когда HTML / XML / что-то еще искажено. К счастью, мой XML хорошо сформирован. Однако возникает вопрос: почему именно искаженный XML вызывает проблемы с diff / patch? Diff / patch ничего не знает о XML / HTML / спецификации любого формата ...?   -  person rinogo    schedule 12.03.2010
comment
P.S. Если кто-то может предоставить конкретный пример, если XML (или даже искаженный HTML) каким-то образом не сработает в сценарии сравнения / исправления, я был бы в восторге! Страница code.google.com представляет собой полу-пример, но он слишком расплывчатый, чтобы иметь для меня смысл. Спасибо!   -  person rinogo    schedule 12.03.2010
comment
@rinogo: большинство программ, которые я когда-либо писал для обработки XML, выдают исключение для искаженного XML. Считается ли это неудачей в сценарии сравнения / исправления?   -  person John Saunders    schedule 12.03.2010
comment
Джон, если diff / patch приводит к неверному искаженному XML, тогда да, это считается ошибкой. Однако мое понимание различий / исправлений заключается в том, что преобразование текста всегда выполняется точно так, как указано. (Другими словами, он не вводит спонтанно недопустимый XML)   -  person rinogo    schedule 12.03.2010


Ответы (4)


Я являюсь автором библиотеки diff / match / patch для обычного текста от Google.

Ключевой вопрос - точны ли ваши патчи. В идеальном мире:

  diff(old_text, new_text) -> edits
  patch(edits, old_text) -> new_text

Обратите внимание, что базовый текст (old_text) одинаков в обеих операциях. В этом идеальном случае простой текстовый diff и patch будут работать отлично, независимо от типа содержимого. Если этот случай относится к вам, то все готово.

Проблема заключается в нечетком исправлении ошибок. Вот соответствующий пример:

  diff(old_text, new_text) -> edits
  patch(edits, old_forked_text) -> new_forked_text

Обратите внимание, что основной текст в обеих операциях неодинаков. Они должны быть похожи, но операция исправления теперь должна использовать «суждение» о том, что она должна делать. Некоторые патчи могут идеально подходить, как указано в редактировании, другие могут нуждаться в корректировке положения, другие могут потребоваться корректировки для измененного контекста, другие могут вообще не соответствовать, и их следует удалить. Если ваш алгоритм исправления не учитывает структуру XML при принятии решений, вы вполне можете получить искаженный XML. Вот образец:

  old_text = Jabberwock<SPAN>Hello<SPAN>World</SPAN></SPAN>
  new_text = Jabberwock<DIV>Hello<SPAN>World</SPAN></DIV>
  diff(old_text, new_text) -> edits
  edits = ["SPAN" -> "DIV" @ character 11,
           "SPAN" -> "DIV" @ character 41]
  old_forked_text = <SPAN>Hello<SPAN>World</SPAN></SPAN>
  patch(edits, old_forked_text) -> new_forked_text
  new_forked_text = <SPAN>Hello<DIV>World</SPAN></DIV>

Давайте внимательно посмотрим на это. Исходный diff вернул две правки, измените самый внешний SPAN на DIV. Простое изменение. К сожалению, текст, к которому применяется это редактирование, был изменен по сравнению с оригиналом. Слово «Бармаглот» было удалено. Теперь первое изменение SPAN-> DIV соответствует второму тегу SPAN, а не первому. Поскольку алгоритм исправления не знает правил XML, он приводит к незаконно вложенным тегам.

Есть несколько приемов, которые позволяют гарантировать корректный XML при использовании текстового патча, но они приводят к некоторой потере гибкости (в исходном вопросе уже есть ссылка на вики-страницу, о которой я писал). Конечным решением для исправления XML, конечно же, является использование алгоритма различий и исправлений, учитывающего XML. Они значительно сложнее и дороже, но они существуют. Погуглите имена Танкреда Линдхольма и Себастьяна Рённау за огромную работу, проделанную ими в области XML (особенно в отношении DocEng).

Дайте мне знать, если я могу еще что-нибудь добавить.

- Нил Фрейзер

person Neil Fraser    schedule 12.03.2010
comment
Великолепно, Нил, просто великолепно! Спасибо, мой друг, за регистрацию здесь, чтобы ответить на этот вопрос. Всем добрых выходных! -Богатый - person rinogo; 12.03.2010
comment
Может ли diff / match / patch работать с некоторым специфичным для XML подмножеством чего-то вроде вывода ESIS из nsgmls? jclark.com/sp/sgmlsout.htm - person sdupton; 07.01.2014
comment
Это старый-старый вопрос, но спасибо вам за развернутый ответ тогда. Вы ссылаетесь на ссылку в исходном вопросе - я считаю, что это соответствующая ссылка на GitHub, верно? github.com/google/diff-match -patch / wiki / Есть ли у вас предложение (нечеткой) техники исправления для применения и повторного применения вашего собственного набора обновлений к программе, которая регулярно обновляется другими? То есть, работая с движущейся целью, и где базовой единицей изменения является одна или несколько полных строк текста, ни в коем случае не меньше. И никакого окончательного слияния не ожидается. - person RenniePet; 27.03.2018

Я все время использую Beyond Compare для сравнения XML-документов. В определенной степени он понимает XML.

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

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

person John Saunders    schedule 12.03.2010

Если вы являетесь единственным «владельцем» данных между точками отмены / повтора, то, конечно, вы можете использовать для них разницу в открытом тексте. Как вы отметили, это набор преобразований.

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

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

Я бы продолжил отмену / повторение как в сеансе редактирования и запретил внешнее редактирование, пока файл открыт. Это позволяет вам оптимизировать запись команд для широких случаев, как я сказал выше.

Помимо этого, либо используйте обычное управление версиями (подумайте о том, чтобы обернуть git), либо реализовать свой собственный способ справиться с файлами, изменяемыми вне вашего редактора.

person Andy Dent    schedule 12.03.2010

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

person Codism    schedule 12.03.2010