Jak mogę różnicować dwa pliki XML?

75

W systemie Linux, jak mogę wygenerować różnicę między dwoma plikami XML?

Idealnie chciałbym być w stanie skonfigurować to do pewnych ścisłych rzeczy, lub poluzować niektóre rzeczy, takie jak białe znaki lub kolejność atrybutów.

Często dbam o to, że pliki są funkcjonalnie takie same, ale same w sobie różnią się, byłoby denerwujące w użyciu, szczególnie jeśli plik XML nie ma wielu podziałów liniowych.

Na przykład, naprawdę powinno być dla mnie w porządku:

<tag att1="one" att2="two">
  content
</tag>

<tag att2="two" att1="one">
  content
</tag>
qedi
źródło

Odpowiedzi:

86

Jednym z rozwiązań byłoby najpierw przekształcenie obu plików XML w Canonical XML i porównanie wyników za pomocą diff. Na przykład xmllint może być użyty do kanonizacji XML.

$ xmllint --c14n one.xml > 1.xml
$ xmllint --c14n two.xml > 2.xml
$ diff 1.xml 2.xml

Lub jako jedna linijka.

$ diff <(xmllint --c14n one.xml) <(xmllint --c14n two.xml)
Jukka Matilainen
źródło
1
Nigdy nie wiedziałem o przełączniku --c14n w Xmllint. To się przydaje.
qedi,
18
Możesz to zrobić w jednym wierszuvimdiff <(xmllint --c14n one.xml) <(xmllint --c14n two.xml)
Nathan Villaescusa
a xmllint jest dostarczany z OS X
ClintM
10
W przypadku, gdy nie było to oczywiste, c14n jest skrótem od kanonizacji .
Brandin,
3
Lepiej wykonać dodatkowy krok przed sformatowaniem różnicowym obu plików XML (xmllint --format). Ponieważ zauważyłem, że bez tego kroku diff pokazuje więcej różnic niż to konieczne.
ka3ak
23

Odpowiedź Jukki nie działała dla mnie, ale wskazywała na Canonical XML. Ani --c14n ani --c14n11 klasyfikowane atrybuty, ale zrobiłem znaleźć --exc-c14n przełącznik zrobił porządek atrybutów. --exc-c14n nie jest wymieniony na stronie podręcznika, ale jest opisany w wierszu poleceń jako „wyłączny format kanoniczny W3C”.

$ xmllint --exc-c14n one.xml > 1.xml
$ xmllint --exc-c14n two.xml > 2.xml
$ diff 1.xml 2.xml

$ xmllint | grep c14
    --c14n : save in W3C canonical format v1.0 (with comments)
    --c14n11 : save in W3C canonical format v1.1 (with comments)
    --exc-c14n : save in W3C exclusive canonical format (with comments)

$ rpm -qf /usr/bin/xmllint
libxml2-2.7.6-14.el6.x86_64
libxml2-2.7.6-14.el6.i686

$ cat /etc/system-release
CentOS release 6.5 (Final)

Ostrzeżenie --exc-c14n usuwa nagłówek xml, podczas gdy --c14n poprzedza nagłówek xml, jeśli go nie ma.

rjt
źródło
18

Próbowałem użyć odpowiedzi @Jukka Matilainen, ale miałem problemy z białą spacją (jeden z plików był ogromną jednostronną linią). Używanie --formatpomaga pominąć różnice białych znaków.

xmllint --format one.xml > 1.xml  
xmllint --format two.xml > 2.xml  
diff 1.xml 2.xml  

Uwaga: Użyj vimdiffpolecenia do porównania plików XML.

GuruM
źródło
W moim przypadku two.xmlzostał wygenerowany one.xmlprzez skrypt. Musiałem więc tylko sprawdzić, co zostało dodane / usunięte przez skrypt.
GuruM
1
To była opcja, której potrzebowałem. Podobno najbardziej kanoniczną wersję można uzyskać przez połączenie --formatz --exc-c14n; prawdopodobnie będzie jeszcze wolniej przetwarzać :(
ᴠɪɴᴄᴇɴᴛ
Minęło sporo czasu, odkąd napisałem odpowiedź, ale słabo pamiętam użycie flagi --exc-c14n. Jednak różnicowanie wyjścia z / bez flagi nie wykazało żadnych różnic, więc po prostu przestałem z niego korzystać. Upuszczenie niepotrzebnych / nieużywanych flag może przyspieszyć proces.
GuruM,
5
--exc-c14nOpcja określa sortowania atrybutów. W twoich konkretnych plikach atrybuty prawdopodobnie były już posortowane, ale ogólna rada byłaby taka kombinacja --format --exc-c14n.
ᴠɪɴᴄᴇɴᴛ
6

Diffxml poprawnie dostosowuje podstawową funkcjonalność, choć wydaje się, że nie oferuje wielu opcji konfiguracji.

Edycja: Project Diffxml jest migrowany do GitHub od 2013 roku.

dsolimano
źródło
Nie jest jeszcze tam, ale wygląda obiecująco.
qedi,
nie przydaje się jednak w przypadku dużych plików, zmarł po zjedzeniu 40 GB (RAM + SWAP) podczas porównywania dwóch plików po ok. 20 tys. linii
Grzegorz,
zauważ, że projekt wydaje się być martwy, a ostatnia aktualizacja w 2013 r.
Mateusz Konieczny
4

Jeśli chcesz również zignorować kolejność elementów potomnych, napisałem do tego proste narzędzie pythonowe o nazwie xmldiffs:

Porównaj dwa pliki XML, ignorując kolejność elementów i atrybutów.

Stosowanie: xmldiffs [OPTION] FILE1 FILE2

Wszelkie dodatkowe opcje są przekazywane do diffpolecenia.

Pobierz na https://github.com/joh/xmldiffs

joh
źródło
1

Mój skrypt xdiff.py w Pythonie do porównywania plików XML ignoruje różnice w spacji i kolejności atrybutów (w przeciwieństwie do kolejności elementów).

W celu porównania dwóch plików 1.xmli 2.xml, by uruchomić skrypt w następujący sposób:

xdiff.py 1.xml 2.xml

W przykładzie PO nie wyprowadziłby nic i zwrócił status wyjścia 0(bez różnic strukturalnych lub tekstowych).

W przypadkach, gdzie 1.xmli 2.xmlróżnią się strukturalnie, to naśladuje jednolitą wyjście GNU diff i zwraca kod zakończenia 1. Istnieją różne opcje sterowania wyjściem, takie jak -awyprowadzanie całego kontekstu, -nwyprowadzanie bez kontekstu i -qcałkowite tłumienie wyjścia (przy jednoczesnym zwracaniu statusu wyjścia).

Andreas Nolda
źródło
0

Używam Beyond Compare do porównywania wszystkich typów plików tekstowych. Tworzą wersje dla systemu Windows i Linux.

Alan
źródło
1
Porównania zwykłego tekstu wykazałyby, że dwie linie różniły się, podczas gdy PO chce, aby były one zgłaszane jako takie same.
ChrisF,
4
tzn. kanonicznie porównaj XML.
Chris W. Rea,
1
Beyond Compare naprawdę jest do bani. Wygląda na to, że po prostu nie zdaje sobie sprawy z elementów XML i robi głównie porównanie tekstu.
Rob K
Beyond Compare ma wtyczkę XML, ale nigdy nie byłem w stanie zainstalować jej poprawnie, więc ... Nyeah ... Przyszedłem na tę stronę i zrobiłem się mądrzejszy ...
Erk
-1

Nasz SD Smart Differencer porównuje dokumenty na podstawie struktury, a nie faktycznego układu.

Jest XML Smart Differencer. W przypadku XML oznacza to dopasowanie kolejności znaczników i treści. Należy zauważyć, że ciąg tekstowy we wskazanym fragmencie był inny. Obecnie nie rozumie pojęcia XML atrybutów znacznika wskazującego, czy białe znaki są znormalizowane czy znaczące.

Ira Baxter
źródło
1
W swoim profilu SO podajesz pełne informacje o swoim pracodawcy; Wolałbym również krótkie zrzeczenie się odpowiedzialności w twojej odpowiedzi :) BTW, próbowałem pobrać kopię testową, ale formularz zapytania jest „inteligentny” (przez JS) na tyle, aby wyłączyć kombinację XML z Smart Differencer (także tym ostatnim) w połączeniu z Pythonem, chociaż możliwe według strony produktu SD)?
ᴠɪɴᴄᴇɴᴛ
1
Ach Dzięki za przypomnienie. To jest odpowiedź z czasów, gdy istniała jasna polityka SO. Poprawiam odpowiedź, aby zasygnalizować związek w odpowiedzi zgodnej z zasadami SO.
Ira Baxter
Sprawdzę stronę pobierania; nie wszystkie nasze produkty na żywo znajdują się na tej liście. Tak, one istnieją.
Ira Baxter
Sprawdziłem stronę pobierania. Tak, nie ma inteligentnego mechanizmu różnicowego XML. Poproszę facetów z zaplecza, żeby naprawili to; powinno być tam za 1-2 tygodnie (mają zaległości, prawda?) W międzyczasie, jeśli chcesz spróbować, wyślij e-mail (patrz biografia).
Ira Baxter,
1
Na połączonej stronie nie ma słowa „XML”.
Mateusz Konieczny