¿Herramienta Diff para archivos XML?

Estoy buscando una herramienta de diferencias basada en Windows que me muestre las diferencias entre dos archivos XML, pero que se base en árboles, no en líneas .
Es decir, si una sección se ha movido a un lugar totalmente diferente en el archivo, no debería reportar diferencias.
Estos dos archivos deben informarse como "iguales":

<soapenv:Body>
  <mes:GetItem>
    <mes:ItemShape>
      <typ:BaseShape>IdOnly</typ:BaseShape>
      <typ:BodyType>Text</typ:BodyType>
      <typ:AdditionalProperties>
        <typ:FieldURI FieldURI="item:Subject" />
        <typ:FieldURI FieldURI="item:Categories" />
      </typ:AdditionalProperties>
    </mes:ItemShape>
    <mes:ItemIds>
      <typ:ItemId Id="AAMYAAA="/>
    </mes:ItemIds>
  </mes:GetItem>
</soapenv:Body>


<soapenv:Body>
  <mes:GetItem>
    <mes:ItemIds>
      <typ:ItemId Id="AAMYAAA="/>
    </mes:ItemIds>
    <mes:ItemShape>
      <typ:BodyType>Text</typ:BodyType>
      <typ:BaseShape>IdOnly</typ:BaseShape>
      <typ:AdditionalProperties>
        <typ:FieldURI FieldURI="item:Categories" />
        <typ:FieldURI FieldURI="item:Subject" />
      </typ:AdditionalProperties>
    </mes:ItemShape>
  </mes:GetItem>
</soapenv:Body>

Y, por supuesto, todas las diferencias deben marcarse, preferiblemente en una vista de lado a lado con indicadores o líneas que conectan las secciones que difieren.

Gratis estaría bien.
Opcionalmente, ignorar los espacios de nombres sería bueno.

@rrirower, sí, pero se cerró allí:/ Stack Exchange tiene esta tendencia a cerrarse en lugar de migrar.
Jan, ¿has probado los programas diff más comunes en Windows, como WinMerge2011, para ver si tienen una opción para esa funcionalidad? (Tenga en cuenta que WinMerge2011 tiene muchas actualizaciones desde la última actualización de WinMerge regular, incluso si el nombre implica lo contrario).
Altova, altova.com/xml_tools.html , hace el excelente XML Spy , que podría tener esa capacidad. No hay una versión gratuita actual, pero se puede descargar una prueba gratuita de 30 días. Consulte también alternativa a.net/software/altova-xmlspy .
Podría usar uno de estos también.
"informado como 'lo mismo'"... Estos archivos XML son "lo mismo" solo cierto si insiste en que el orden de algunas etiquetas es irrelevante. Para algunas personas, el orden importa. Necesita un esquema o alguna otra señal para indicar qué caso, para qué etiquetas.
Beyond Compare tiene características especiales para XML. Consulte Formatos de archivo adicionales para XML.
Solo pensé que al cargar ambos archivos xml en la memoria, incluso se podría crear un parche xmlstarlet, porque en la memoria, el orden no importa, y cada elemento será único (en caso de duplicidad). Si alguien hace esto, hágalo en Java o al menos en un código abierto compatible con Linux :)
3 años más tarde, ¿consiguió encontrar una solución a su problema por casualidad?
@Mast Mi trabajo actual ya no necesita esto, así que lo tengo en un segundo plano. Sin embargo, todavía planeo volver a visitar esta publicación, cuando pueda hacer algo de tiempo.

Respuestas (6)

Técnicamente, los XML son diferentes

  • si tienen espacios en blanco o no
  • si el orden es diferente
  • si tienen comentarios o no
  • si tienen instrucciones de procesamiento o no
  • si su codificación es diferente
  • si sus espacios de nombres son diferentes

pero, por supuesto, puede decidir ignorarlo o no, según la información semántica que un XML no tiene.

Microsoft ha desarrollado la herramienta XML Diff and Patch para este fin y puede integrarla en sus propias aplicaciones .

Nota: la herramienta se instala como "SQLXML Bulkload in .NET Code Sample" y viene con una solución de Visual Studio XmlDiffView.slnque debe compilar usted mismo. Algunos conocimientos básicos de programación en C# y Visual Studio Community Edition deberían estar bien.

Sin embargo, como se menciona en una de las respuestas sobre Stack Overflow , se ha compilado y puesto a disposición en Bitbucket .

Después de eso, viene con una interfaz de usuario que le permite elegir las diversas opciones de comparación de XML:

interfaz de usuario XMLDiff

Cuando lo aplico a los 2 XML de sus preguntas, arroja una excepción. Eso se debe a los espacios de nombres que no están definidos. Después de eliminar los espacios de nombres, dice:

Archivos idénticos para las opciones dadas

Gracias. Voté esta respuesta pero no la marqué como la correcta. Motivo: la interfaz de la ventana de resultados de la herramienta GUI es horrible: cuando se comparan dos archivos XML grandes, la ventana de diferencias tiene aproximadamente 3000 píxeles de ancho, contiene todos los XML idénticos y no tiene barras de desplazamiento. Luego intente encontrar las diferencias entre dos archivos de 55 MB ;-( No soy programador de Cx, por lo que no puedo adaptar el programa.
@JanDoggen: sí, estoy de acuerdo, está muy orientado al desarrollador. Difícilmente se puede utilizar sin conocimientos de programación.
@JanDoggen La barra de desplazamiento es una pequeña astilla de solo un par de píxeles de ancho en el borde derecho de la ventana. Estoy de acuerdo en que el resultado no es muy bonito, pero sigue siendo una herramienta útil.
@ThomasWeller +1 por el enlace a BitBucket. Compilé, pero no tuve suerte, consiguiendo que la fuente original funcionara.

Centrarse en la parte que movió las secciones debe informarse, ya que ninguna diferencia me hizo pensar en https://semanticmerge.com/ , que no compara archivos XML, sino código C# y C. Y como entiende esos idiomas, puede mostrar si el código se ha movido y no ha cambiado.

Esto lleva a un enfoque alternativo para esta pregunta: ¿Sería posible traducir el XML a clases de C# y luego hacer una combinación semántica en el código resultante?

Un enfoque posible, si esta herramienta aún no está escrita, podría ser traducir todos y cada uno de los elementos a clases, y cada atributo (y texto del cuerpo) a una propiedad de cadena dentro de esa clase. Si desea ignorar los espacios de nombres, deje que su traductor los elimine en el proceso de traducción.

Traduje el ejemplo XML dado como prueba de concepto y obtuve lo siguiente:

class soapenv__Body {
  class mes__GetItem {
    class mes__ItemShape {
      class typ__BaseShape {
          string body="IdOnly";
      }
      class typ__BodyType {
          string body="Textus";
      }
      class typ__AdditionalProperties {
        class typ__FieldURI  {
            string FieldURI="item:Subject";
        }
        class typ__FieldURI  {
            string FieldURI="item:Categories"; 
        }
      }
    }
    class mes__ItemIds {
      class typ__ItemId {
          string Id="AAMYAAA=";
      }
    }
  }
}

Luego cambié el mes:ItemIdsy mes:ItemShapey cambié el texto a Textus. Comparó los siguientes dos archivos en Semantic Merge y obtuvo la siguiente imagen:

Captura de pantalla de fusión semántica

En esta imagen se puede ver el movimiento, indicado por el Micono, y el cambio de texto indicado por el Cicono. Las líneas indican dónde se han movido/cambiado las diferentes partes y es posible ver las diferencias, si es que existen.

Tenga en cuenta que la combinación semántica, aunque comprenda el código C#, no es demasiado estricta con los nombres de clase idénticos de typ__FieldURI, lo que podría ser una buena característica, ya que XML puede contener varios nodos con el mismo nombre.

Summa summarum: Semantic Merge puede identificar correctamente el XML como idéntico (o no) aunque los elementos se muevan, si puede convertir el XML en una estructura de clase C#.

Solo por diversión, intenté mover los typ:FieldUrielementos y Semantic Merge los identificó correctamente como movidos. Entonces, el orden se detecta correctamente y puede rastrear el orden de los atributos si así lo desea.

Técnicamente, no son lo mismo (al menos en xml), el orden sí importa a menos que se haga explícito en el esquema.

Una combinación de xmlstarlet y utilidades normales basadas en línea puede hacer que el problema sea mucho más manejable.

Lo siguiente solo compara la estructura, pero podría extenderse para ver los atributos, sus valores y el texto.

xmlstarlet el snippet1-with-namespaces.xml | sort > structure1.txt

xmlstarlet el snippet2-with-namespaces.xml | sort > structure2.txt

diff structure.txt structure2.txt

Después de ejecutar esto en sus fragmentos, la diferencia no muestra diferencias, pero hubo un texto de error sobre los espacios de nombres (que sería seguro ignorar).

Recomendaría una herramienta XiMpLe que es principalmente el editor XML pero también puede comparar (y combinar) archivos xml de una manera bien organizada. Su ejemplo se compara y evalúa como idéntico. También hay una opción para resolver espacios de nombres.

Ejemplo de comparación de resultados

Actualmente estoy tratando de resolver un problema bastante similar para mí. Desafortunadamente, no encontré ninguna biblioteca que se adapte a mis necesidades para producir una visualización svg de una comparación xml.

Por lo tanto, comencé una biblioteca de código abierto inspirada en el algoritmo X-Diff . Entonces, solo por diversión y con la esperanza de encontrar a alguien que apoye la biblioteca XmlXdiff . Hasta ahora, no es una biblioteca de prueba de viñetas y todavía está en construcción, pero aquí está el resultado de su fragmento de código de ejemplo:

ingrese la descripción de la imagen aquí

Código que produce este resultado:

    from XmlXdiff.XReport import DrawXmlDiff

    _xml1 = """<frame xmlns:soapenv="sn" xmlns:mes="meas" xmlns:typ="type">
    <soapenv:Body>
      <mes:GetItem>
        <mes:ItemShape>
          <typ:BaseShape>IdOnly</typ:BaseShape>
          <typ:BodyType>Text</typ:BodyType>
          <typ:AdditionalProperties>
            <typ:FieldURI FieldURI="item:Subject" />
            <typ:FieldURI FieldURI="item:Categories" />
          </typ:AdditionalProperties>
        </mes:ItemShape>
        <mes:ItemIds>
          <typ:ItemId Id="AAMYAAA="/>
        </mes:ItemIds>
      </mes:GetItem>
    </soapenv:Body>
    </frame>"""
    _xml2 = """<frame xmlns:soapenv="sn" xmlns:mes="meas" xmlns:typ="type">
    <soapenv:Body>
      <mes:GetItem>
        <mes:ItemIds>
          <typ:ItemId Id="AAMYAAA="/>
        </mes:ItemIds>
        <mes:ItemShape>
          <typ:BodyType>Text</typ:BodyType>
          <typ:BaseShape>IdOnly</typ:BaseShape>
          <typ:AdditionalProperties>
            <typ:FieldURI FieldURI="item:Categories" />
            <typ:FieldURI FieldURI="item:Subject" />
          </typ:AdditionalProperties>
        </mes:ItemShape>
      </mes:GetItem>
    </soapenv:Body>
    </frame>"""

    _path1 = '{}\\..\\..\\tests\\simple\\xml1.xml'.format(getPath())
    _path2 = '{}\\..\\..\\tests\\simple\\xml2.xml'.format(getPath())
    _out = '{}\\..\\..\\tests\\simple\\xdiff.svg'.format(getPath())

    with open(_path1, "w") as f:
        f.write(_xml1)

    with open(_path2, "w") as f:
        f.write(_xml2)

    x = DrawXmlDiff(_path1, _path2)
    x.draw()
    x.saveSvg(_out)

En resumen, atendiendo a sus necesidades:

  1. Comparación estructuralmente consciente, no basada en líneas: Sí
  2. Puede ejecutarse en Windows: Sí
  3. Comparación sin pedidos/Gestión de movimientos: Sí
  4. Salida de comparación lado a lado: Sí
  5. Ignorar cambios esperados: Sí
  6. Gratis: No, pero hay una prueba gratuita disponible.

XML Compare , desarrollado por DeltaXML, es una herramienta de comparación XML estructuralmente consciente que se puede ejecutar en Windows , así como en Linux y Mac, utilizando Java. XML Compare se puede utilizar a través de la línea de comandos, REST API y Java API .

Los resultados diff de XML Compare son XML válidos, lo que significa que pueden ser procesados ​​fácilmente por otras aplicaciones y en otros formatos de salida a través de la configuración de procesamiento posterior. Los cambios se identifican mediante la adición de nuevos atributos en la salida diff que indican si el contenido o la estructura estaba presente en la entrada A, presente en la entrada B y si es el mismo en ambos o ha cambiado. Sigue un formato simple "A! = B", vea el fragmento de código de ejemplo a continuación.

<height deltaxml:deltaV2="A!=B">
           <deltaxml:textGroup deltaxml:deltaV2="A!=B">
              <deltaxml:text deltaxml:deltaV2="A">up to 1.4 meters</deltaxml:text>
              <deltaxml:text deltaxml:deltaV2="B">up to 1.3 meters</deltaxml:text>
           </deltaxml:textGroup>
        </height>

Con respecto a su requisito para contabilizar el contenido que se ha movido, XML Compare es altamente configurable. Hay docenas de filtros y procesadores de entrada y salida preconfigurados, y se pueden crear conductos y filtros personalizados mediante XSLT.

Específicamente para sus requisitos, existen funciones preconfiguradas para Comparar elementos sin orden en el caso de comparar donde el orden de los elementos no es significativo, Detectar y manejar movimientos e Ignorar cambios donde se esperan y no es necesario resaltarlos.

Finalmente, uno de los formatos de salida preconfigurados disponibles es un informe de diferencias HTML en paralelo que se basa en la salida delta. Sin embargo, en los casos en los que necesite una salida más específica, puede volver a configurar y procesar la salida utilizando XSLT o las opciones de configuración existentes. A continuación se muestra una captura de pantalla del informe de diferencias en paralelo:

DeltaXML lado a lado Informe de diferencias HTML

Divulgación: soy un empleado de DeltaXML.

Como está escrito actualmente, su respuesta no está clara. Edite para agregar detalles adicionales que ayudarán a otros a comprender cómo esto aborda la pregunta formulada. Puede encontrar más información sobre cómo escribir buenas respuestas en el centro de ayuda .