¿Cómo puedo diferenciar dos archivos XML?

75

En Linux, ¿cómo podría generar una diferencia entre dos archivos XML?

Idealmente, me gustaría poder configurarlo para algunas cosas estrictas, o aflojar algunas cosas, como espacios en blanco u orden de atributos.

A menudo me importa que los archivos sean funcionalmente iguales, pero que difieran por sí mismos, sería molesto de usar, especialmente si el archivo XML no tiene muchos saltos de línea.

Por ejemplo, lo siguiente realmente debería estar bien para mí:

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

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

Respuestas:

86

Un enfoque sería convertir primero ambos archivos XML en XML canónico y comparar los resultados usando diff. Por ejemplo, xmllint se puede usar para canonicalizar XML.

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

O como una sola línea.

$ diff <(xmllint --c14n one.xml) <(xmllint --c14n two.xml)
Jukka Matilainen
fuente
1
Nunca supe sobre el modificador --c14n en xmllint. Eso es útil.
qedi
18
También puedes hacerlo en una líneavimdiff <(xmllint --c14n one.xml) <(xmllint --c14n two.xml)
Nathan Villaescusa
y xmllint se envía con OS X
ClintM
10
En caso de que no fuera obvio, c14n es una abreviatura de canonicalización .
Brandin el
3
Es mejor ejecutar un paso adicional antes del formato diferencial de ambos XML (xmllint --format). Porque he notado que sin este paso, diff muestra más diferencias de las necesarias.
ka3ak
23

La respuesta de Jukka no funcionó para mí, pero sí señaló a Canonical XML. Ni --c14n ni --c14n11 ordenaron los atributos, pero encontré que el modificador --exc-c14n clasificó los atributos. --exc-c14n no aparece en la página del manual, pero se describe en la línea de comandos como "formato canónico exclusivo del 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)

Advertencia --exc-c14n elimina el encabezado xml, mientras que --c14n antepone el encabezado xml si no está allí.

rjt
fuente
18

Intenté usar la respuesta de @Jukka Matilainen pero tuve problemas con el espacio en blanco (uno de los archivos era enorme). El uso --formatayuda a omitir las diferencias de espacios en blanco.

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

Nota: Use el vimdiffcomando para la comparación lado a lado de los xmls.

GuruM
fuente
En mi caso two.xmlfue generado one.xmlpor un script. Así que solo necesitaba verificar qué fue agregado / eliminado por el script.
GuruM
1
Esta era la opción que necesitaba. Supuestamente, la versión más canónica se puede obtener combinando --formatcon --exc-c14n; probablemente será aún más lento de procesar :(
ᴠɪɴᴄᴇɴᴛ
Ha pasado bastante tiempo desde que escribí la respuesta, pero apenas recuerdo haber usado la bandera --exc-c14n. Sin embargo, diferenciar la salida con / sin la bandera no mostró diferencias, así que simplemente dejé de usarla. Dejar caer banderas innecesarias / no utilizadas puede acelerar el proceso.
GuruM
55
La --exc-c14nopción especifica la clasificación de los atributos. En sus archivos específicos, los atributos probablemente ya estaban ordenados, pero el consejo general sería utilizar la combinación --format --exc-c14n.
ᴠɪɴᴄᴇɴᴛ
6

Diffxml obtiene la funcionalidad básica correcta, aunque no parece ofrecer muchas opciones de configuración.

Editar: Project Diffxml se ha migrado a GitHub desde 2013.

dsolimano
fuente
Todavía no está allí, pero parece prometedor al menos.
qedi
sin embargo, no es útil para archivos grandes, murió después de comer 40 GB (RAM + SWAP) al comparar dos archivos ~ 20k líneas cada uno
Grzegorz
tenga en cuenta que el proyecto parece estar muerto, con la última actualización en 2013
Mateusz Konieczny
4

Si desea ignorar también el orden de los elementos secundarios, escribí una herramienta simple de Python para esto llamada xmldiffs:

Compare dos archivos XML, ignorando el orden de los elementos y atributos.

Uso: xmldiffs [OPTION] FILE1 FILE2

Cualquier opción adicional se pasa al diffcomando.

Consíguelo en https://github.com/joh/xmldiffs

joh
fuente
1

Mi script Python xdiff.py para comparar archivos XML ignora las diferencias en el espacio en blanco o el orden de los atributos (en contraste con el orden de los elementos).

Para comparar dos archivos 1.xmly 2.xml, debería ejecutar el script de la siguiente manera:

xdiff.py 1.xml 2.xml

En el ejemplo del OP, no generará nada y devolverá el estado de salida 0(sin diferencias estructurales o textuales).

En casos donde 1.xmly 2.xmldifieren estructuralmente, imita la salida unificada de GNU diff y devuelve el estado de salida 1. Existen varias opciones para controlar la salida, como la -asalida de todo el contexto, la -nsalida sin contexto y la -qsupresión de la salida por completo (mientras se devuelve el estado de salida).

Andreas Nolda
fuente
0

Uso Beyond Compare para comparar todos los tipos de archivos basados ​​en texto. Producen versiones para Windows y Linux.

Alan
fuente
1
Las comparaciones de texto sin formato dirían que las dos líneas difieren, mientras que el OP quiere que se informen como iguales.
ChrisF
44
es decir, comparar canónicamente el XML.
Chris W. Rea
1
Beyond Compare realmente apesta para esto. Parece que simplemente no tiene en cuenta los elementos XML y solo hace una comparación de texto.
Rob K
Beyond Compare tiene un complemento XML pero nunca pude instalarlo correctamente, así que ... Nyeah ... Vine a esta página y me hice más sabio ...
Erk
-1

Nuestro SD Smart Differencer compara documentos basados ​​en la estructura en comparación con el diseño real.

Hay un XML Smart Differencer. Para XML, eso significa un orden coincidente de etiquetas y contenido. Debe tener en cuenta que la cadena de texto en el fragmento específico que indicó fue diferente. Actualmente no comprende la noción XML de los atributos de etiqueta que indican si el espacio en blanco está normalizado o no significativo.

Ira Baxter
fuente
1
En su perfil de SO, proporciona información completa sobre su empleador; También preferiría un breve descargo de responsabilidad dentro de su respuesta :) Por cierto, intenté descargar una copia de evaluación, pero el formulario de solicitud es 'inteligente' (a través de JS) lo suficiente como para deshabilitar la combinación XML con Smart Differencer (también este último en combinación con Python, aunque posible según la página del producto SD)?
ᴠɪɴᴄᴇɴᴛ
1
Ah Gracias por el recordatorio. Esta es una respuesta de un tiempo antes de que hubiera una política SO clara sobre esto. Estoy revisando la respuesta para señalar la relación en la respuesta conforme a la política SO.
Ira Baxter
Comprobaré la página de descarga; no todos nuestros productos en vivo entran en esa lista. Sí, estos existen.
Ira Baxter
Revisé la página de descarga. Sí, el diferenciador inteligente XML no está allí. Haré que los chicos de la trastienda trabajen en arreglar eso; debería estar allí en 1-2 semanas como máximo (tienen un retraso, ¿no es cierto?) Mientras tanto, si quieres probarlo, envía un correo electrónico (ver biografía).
Ira Baxter
1
La página vinculada no tiene la palabra "XML".
Mateusz Konieczny
-1

No estoy seguro de si (la dependencia de) una herramienta en línea cuenta como una solución, pero, por lo que vale, obtuve un buen resultado en esta herramienta de comparación de XML en línea . Simplemente funciona

RayLuo
fuente