La mejor manera de comparar 2 documentos XML en Java


198

Estoy tratando de escribir una prueba automatizada de una aplicación que básicamente traduce un formato de mensaje personalizado en un mensaje XML y lo envía al otro extremo. Tengo un buen conjunto de pares de mensajes de entrada / salida, por lo que todo lo que necesito hacer es enviar los mensajes de entrada y escuchar el mensaje XML que sale por el otro extremo.

Cuando llega el momento de comparar la salida real con la salida esperada, me encuentro con algunos problemas. Mi primer pensamiento fue hacer comparaciones de cadenas en los mensajes esperados y reales. Esto no funciona muy bien porque los datos de ejemplo que tenemos no siempre están formateados de manera consistente y a menudo se usan diferentes alias para el espacio de nombres XML (y a veces los espacios de nombres no se usan en absoluto).

Sé que puedo analizar ambas cadenas y luego recorrer cada elemento y compararlas yo mismo y esto no sería demasiado difícil de hacer, pero tengo la sensación de que hay una mejor manera o una biblioteca que podría aprovechar.

Entonces, resumido, la pregunta es:

Dadas dos cadenas de Java que contienen XML válido, ¿cómo determinaría si son semánticamente equivalentes? Puntos de bonificación si tiene una manera de determinar cuáles son las diferencias.

Respuestas:


197

Suena como un trabajo para XMLUnit

Ejemplo:

public class SomeTest extends XMLTestCase {
  @Test
  public void test() {
    String xml1 = ...
    String xml2 = ...

    XMLUnit.setIgnoreWhitespace(true); // ignore whitespace differences

    // can also compare xml Documents, InputSources, Readers, Diffs
    assertXMLEqual(xml1, xml2);  // assertXMLEquals comes from XMLTestCase
  }
}

1
He tenido problemas con XMLUNit en el pasado, ha estado muy nervioso con las versiones de API XML y no ha demostrado ser confiable. Sin embargo, ha pasado un tiempo desde que lo abandoné para XOM, por lo que tal vez haya mejorado desde entonces.
skaffman

63
Para principiantes en XMLUnit, tenga en cuenta que, de manera predeterminada, myDiff.similar () devolverá falso si los documentos de control y prueba difieren en sangría / líneas nuevas. Esperaba este comportamiento de myDiff.identical (), y no de myDiff.similar (). Incluir XMLUnit.setIgnoreWhitespace (true); en su método de configuración para cambiar el comportamiento de todas las pruebas en su clase de prueba, o usarlo en un método de prueba individual para cambiar el comportamiento solo de esa prueba.
Estofado

1
@Stew, gracias por tu comentario, recién comenzando con XMLUnit y estoy seguro de que habría enfrentado este problema. +1
Jay

2
En caso de que esté intentando esto con XMLUnit 2 en github, la versión 2 es una reescritura completa, por lo que este ejemplo es para XMLUnit 1 en SourceForge. Además, la página de sourceforge dice "XMLUnit for Java 1.x aún se mantendrá".
Yngvar Kristiansen

1
El método es afirmar XMLEqual a partir de XMLAssert.java .
user2818782

36

Lo siguiente verificará si los documentos son iguales utilizando las bibliotecas JDK estándar.

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance ();
dbf.setNamespaceAware (verdadero);
dbf.setCoalescing (verdadero);
dbf.setIgnoringElementContentWhitespace (true);
dbf.setIgnoringComments (true);
DocumentBuilder db = dbf.newDocumentBuilder ();

Documento doc1 = db.parse (nuevo archivo ("file1.xml"));
doc1.normalizeDocument ();

Documento doc2 = db.parse (nuevo archivo ("file2.xml"));
doc2.normalizeDocument ();

Assert.assertTrue (doc1.isEqualNode (doc2));

normalize () está ahí para asegurarse de que no haya ciclos (técnicamente no habría ninguno)

Sin embargo, el código anterior requerirá que los espacios en blanco sean los mismos dentro de los elementos, porque lo conserva y evalúa. El analizador XML estándar que viene con Java no le permite configurar una función para proporcionar una versión canónica o comprender xml:spacesi eso va a ser un problema, entonces es posible que necesite un analizador XML de reemplazo como xerces o usar JDOM.


44
Esto funciona perfectamente para XML sin espacios de nombres o con prefijos de espacio de nombres "normalizados". Dudo que funcione si un XML es <ns1: a xmlns: ns1 = "ns" /> y el otro es <ns2: a xmlns: ns2 = "ns" />
koppor

dbf.setIgnoringElementContentWhitespace (true) no tiene el resultado Esperaría que <root> name </root> no sea igual a <root> name </name> con esta solución (rellenado con dos espacios) pero XMLUnit da el mismo resultado en este caso (JDK8)
Miklos Krivan

Para mí no ignora los saltos de línea, lo cual es un problema.
Flyout91

setIgnoringElementContentWhitespace(false)
Arquímedes Trajano

28

Xom tiene una utilidad Canonicalizer que convierte sus DOM en una forma regular, que luego puede clasificar en cadena y comparar. Por lo tanto, independientemente de las irregularidades del espacio en blanco o el orden de los atributos, puede obtener comparaciones regulares y predecibles de sus documentos.

Esto funciona especialmente bien en IDE que tienen comparadores de cadenas visuales dedicados, como Eclipse. Obtiene una representación visual de las diferencias semánticas entre los documentos.


21

La última versión de XMLUnit puede ayudar a afirmar que dos XML son iguales. También XMLUnit.setIgnoreWhitespace()y XMLUnit.setIgnoreAttributeOrder()puede ser necesario para el caso en cuestión.

Vea el código de trabajo de un ejemplo simple de uso de la Unidad XML a continuación.

import org.custommonkey.xmlunit.DetailedDiff;
import org.custommonkey.xmlunit.XMLUnit;
import org.junit.Assert;

public class TestXml {

    public static void main(String[] args) throws Exception {
        String result = "<abc             attr=\"value1\"                title=\"something\">            </abc>";
        // will be ok
        assertXMLEquals("<abc attr=\"value1\" title=\"something\"></abc>", result);
    }

    public static void assertXMLEquals(String expectedXML, String actualXML) throws Exception {
        XMLUnit.setIgnoreWhitespace(true);
        XMLUnit.setIgnoreAttributeOrder(true);

        DetailedDiff diff = new DetailedDiff(XMLUnit.compareXML(expectedXML, actualXML));

        List<?> allDifferences = diff.getAllDifferences();
        Assert.assertEquals("Differences found: "+ diff.toString(), 0, allDifferences.size());
    }

}

Si usa Maven, agregue esto a su pom.xml:

<dependency>
    <groupId>xmlunit</groupId>
    <artifactId>xmlunit</artifactId>
    <version>1.4</version>
</dependency>

Esto es perfecto para las personas que necesitan comparar desde un método estático.
Andy B

Esta es la respuesta perfecta. Gracias ... Sin embargo, tengo que ignorar los nodos que no existen. Dado que no quiero ver en el resultado de salida tal salida: Presencia esperada del nodo hijo "nulo" pero fue ...... ¿Cómo puedo hacer eso? Saludos. @acdcjunior
limonik

1
XMLUnit.setIgnoreAttributeOrder (verdadero); No funciona. Si algunos nodos tienen un orden diferente, la comparación fallará.
Bevor

[ACTUALIZACIÓN] esta solución funciona: stackoverflow.com/questions/33695041/…
Bevor

Te das cuenta de que "IgnoreAttributeOrder" significa ignorar el orden de los atributos y no ignorar el orden de los nodos, ¿verdad?
acdcjunior

7

Gracias, extendí esto, prueba esto ...

import java.io.ByteArrayInputStream;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

public class XmlDiff 
{
    private boolean nodeTypeDiff = true;
    private boolean nodeValueDiff = true;

    public boolean diff( String xml1, String xml2, List<String> diffs ) throws Exception
    {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        dbf.setCoalescing(true);
        dbf.setIgnoringElementContentWhitespace(true);
        dbf.setIgnoringComments(true);
        DocumentBuilder db = dbf.newDocumentBuilder();


        Document doc1 = db.parse(new ByteArrayInputStream(xml1.getBytes()));
        Document doc2 = db.parse(new ByteArrayInputStream(xml2.getBytes()));

        doc1.normalizeDocument();
        doc2.normalizeDocument();

        return diff( doc1, doc2, diffs );

    }

    /**
     * Diff 2 nodes and put the diffs in the list 
     */
    public boolean diff( Node node1, Node node2, List<String> diffs ) throws Exception
    {
        if( diffNodeExists( node1, node2, diffs ) )
        {
            return true;
        }

        if( nodeTypeDiff )
        {
            diffNodeType(node1, node2, diffs );
        }

        if( nodeValueDiff )
        {
            diffNodeValue(node1, node2, diffs );
        }


        System.out.println(node1.getNodeName() + "/" + node2.getNodeName());

        diffAttributes( node1, node2, diffs );
        diffNodes( node1, node2, diffs );

        return diffs.size() > 0;
    }

    /**
     * Diff the nodes
     */
    public boolean diffNodes( Node node1, Node node2, List<String> diffs ) throws Exception
    {
        //Sort by Name
        Map<String,Node> children1 = new LinkedHashMap<String,Node>();      
        for( Node child1 = node1.getFirstChild(); child1 != null; child1 = child1.getNextSibling() )
        {
            children1.put( child1.getNodeName(), child1 );
        }

        //Sort by Name
        Map<String,Node> children2 = new LinkedHashMap<String,Node>();      
        for( Node child2 = node2.getFirstChild(); child2!= null; child2 = child2.getNextSibling() )
        {
            children2.put( child2.getNodeName(), child2 );
        }

        //Diff all the children1
        for( Node child1 : children1.values() )
        {
            Node child2 = children2.remove( child1.getNodeName() );
            diff( child1, child2, diffs );
        }

        //Diff all the children2 left over
        for( Node child2 : children2.values() )
        {
            Node child1 = children1.get( child2.getNodeName() );
            diff( child1, child2, diffs );
        }

        return diffs.size() > 0;
    }


    /**
     * Diff the nodes
     */
    public boolean diffAttributes( Node node1, Node node2, List<String> diffs ) throws Exception
    {        
        //Sort by Name
        NamedNodeMap nodeMap1 = node1.getAttributes();
        Map<String,Node> attributes1 = new LinkedHashMap<String,Node>();        
        for( int index = 0; nodeMap1 != null && index < nodeMap1.getLength(); index++ )
        {
            attributes1.put( nodeMap1.item(index).getNodeName(), nodeMap1.item(index) );
        }

        //Sort by Name
        NamedNodeMap nodeMap2 = node2.getAttributes();
        Map<String,Node> attributes2 = new LinkedHashMap<String,Node>();        
        for( int index = 0; nodeMap2 != null && index < nodeMap2.getLength(); index++ )
        {
            attributes2.put( nodeMap2.item(index).getNodeName(), nodeMap2.item(index) );

        }

        //Diff all the attributes1
        for( Node attribute1 : attributes1.values() )
        {
            Node attribute2 = attributes2.remove( attribute1.getNodeName() );
            diff( attribute1, attribute2, diffs );
        }

        //Diff all the attributes2 left over
        for( Node attribute2 : attributes2.values() )
        {
            Node attribute1 = attributes1.get( attribute2.getNodeName() );
            diff( attribute1, attribute2, diffs );
        }

        return diffs.size() > 0;
    }
    /**
     * Check that the nodes exist
     */
    public boolean diffNodeExists( Node node1, Node node2, List<String> diffs ) throws Exception
    {
        if( node1 == null && node2 == null )
        {
            diffs.add( getPath(node2) + ":node " + node1 + "!=" + node2 + "\n" );
            return true;
        }

        if( node1 == null && node2 != null )
        {
            diffs.add( getPath(node2) + ":node " + node1 + "!=" + node2.getNodeName() );
            return true;
        }

        if( node1 != null && node2 == null )
        {
            diffs.add( getPath(node1) + ":node " + node1.getNodeName() + "!=" + node2 );
            return true;
        }

        return false;
    }

    /**
     * Diff the Node Type
     */
    public boolean diffNodeType( Node node1, Node node2, List<String> diffs ) throws Exception
    {       
        if( node1.getNodeType() != node2.getNodeType() ) 
        {
            diffs.add( getPath(node1) + ":type " + node1.getNodeType() + "!=" + node2.getNodeType() );
            return true;
        }

        return false;
    }

    /**
     * Diff the Node Value
     */
    public boolean diffNodeValue( Node node1, Node node2, List<String> diffs ) throws Exception
    {       
        if( node1.getNodeValue() == null && node2.getNodeValue() == null )
        {
            return false;
        }

        if( node1.getNodeValue() == null && node2.getNodeValue() != null )
        {
            diffs.add( getPath(node1) + ":type " + node1 + "!=" + node2.getNodeValue() );
            return true;
        }

        if( node1.getNodeValue() != null && node2.getNodeValue() == null )
        {
            diffs.add( getPath(node1) + ":type " + node1.getNodeValue() + "!=" + node2 );
            return true;
        }

        if( !node1.getNodeValue().equals( node2.getNodeValue() ) )
        {
            diffs.add( getPath(node1) + ":type " + node1.getNodeValue() + "!=" + node2.getNodeValue() );
            return true;
        }

        return false;
    }


    /**
     * Get the node path
     */
    public String getPath( Node node )
    {
        StringBuilder path = new StringBuilder();

        do
        {           
            path.insert(0, node.getNodeName() );
            path.insert( 0, "/" );
        }
        while( ( node = node.getParentNode() ) != null );

        return path.toString();
    }
}

3
Muy tarde, pero solo quería señalar que este fragmento de código tiene un error: en diffNodes (), no se hace referencia al nodo2: el segundo bucle reutiliza el nodo1 incorrectamente (edité el código para solucionarlo). Además, tiene 1 limitación: debido a la forma en que se asignan los mapas secundarios, esta diferencia no es compatible con el caso en que los nombres de elementos no son únicos, es decir, elementos que contienen elementos secundarios repetibles.
aberrante80

7

Sobre la base de la respuesta de Tom , aquí hay un ejemplo usando XMLUnit v2.

Utiliza estas dependencias de Maven

    <dependency>
        <groupId>org.xmlunit</groupId>
        <artifactId>xmlunit-core</artifactId>
        <version>2.0.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.xmlunit</groupId>
        <artifactId>xmlunit-matchers</artifactId>
        <version>2.0.0</version>
        <scope>test</scope>
    </dependency>

..y aquí está el código de prueba

import static org.junit.Assert.assertThat;
import static org.xmlunit.matchers.CompareMatcher.isIdenticalTo;
import org.xmlunit.builder.Input;
import org.xmlunit.input.WhitespaceStrippedSource;

public class SomeTest extends XMLTestCase {
    @Test
    public void test() {
        String result = "<root></root>";
        String expected = "<root>  </root>";

        // ignore whitespace differences
        // https://github.com/xmlunit/user-guide/wiki/Providing-Input-to-XMLUnit#whitespacestrippedsource
        assertThat(result, isIdenticalTo(new WhitespaceStrippedSource(Input.from(expected).build())));

        assertThat(result, isIdenticalTo(Input.from(expected).build())); // will fail due to whitespace differences
    }
}

La documentación que describe esto es https://github.com/xmlunit/xmlunit#comparing-two-documents


3

skaffman parece estar dando una buena respuesta.

Otra forma es probablemente formatear el XML utilizando una utilidad de línea de comando como xmlstarlet ( http://xmlstar.sourceforge.net/ ) y luego formatear ambas cadenas y luego usar cualquier utilidad diff (biblioteca) para diferenciar los archivos de salida resultantes. No sé si esta es una buena solución cuando hay problemas con los espacios de nombres.



2

Estoy usando Altova DiffDog que tiene opciones para comparar archivos XML estructuralmente (ignorando los datos de cadena).

Esto significa que (si marca la opción 'ignorar texto'):

<foo a="xxx" b="xxx">xxx</foo>

y

<foo b="yyy" a="yyy">yyy</foo> 

son iguales en el sentido de que tienen igualdad estructural. ¡Esto es útil si tiene archivos de ejemplo que difieren en datos, pero no en estructura!


3
Lo único negativo es que no es gratis (99 € para una licencia profesional), con 30 días de prueba.
Pimin Konstantin Kefaloukos

2
Solo he encontrado la utilidad ( altova.com/diffdog/diff-merge-tool.html ); Es bueno tener una biblioteca.
dma_k

1

Esto comparará los XML de cadena completa (formateándolos en el camino). Facilita el trabajo con su IDE (IntelliJ, Eclipse), ya que simplemente hace clic y visualmente ve la diferencia en los archivos XML.

import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.c14n.InvalidCanonicalizerException;
import org.w3c.dom.Element;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import java.io.IOException;
import java.io.StringReader;

import static org.apache.xml.security.Init.init;
import static org.junit.Assert.assertEquals;

public class XmlUtils {
    static {
        init();
    }

    public static String toCanonicalXml(String xml) throws InvalidCanonicalizerException, ParserConfigurationException, SAXException, CanonicalizationException, IOException {
        Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
        byte canonXmlBytes[] = canon.canonicalize(xml.getBytes());
        return new String(canonXmlBytes);
    }

    public static String prettyFormat(String input) throws TransformerException, ParserConfigurationException, IOException, SAXException, InstantiationException, IllegalAccessException, ClassNotFoundException {
        InputSource src = new InputSource(new StringReader(input));
        Element document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(src).getDocumentElement();
        Boolean keepDeclaration = input.startsWith("<?xml");
        DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
        DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");
        LSSerializer writer = impl.createLSSerializer();
        writer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE);
        writer.getDomConfig().setParameter("xml-declaration", keepDeclaration);
        return writer.writeToString(document);
    }

    public static void assertXMLEqual(String expected, String actual) throws ParserConfigurationException, IOException, SAXException, CanonicalizationException, InvalidCanonicalizerException, TransformerException, IllegalAccessException, ClassNotFoundException, InstantiationException {
        String canonicalExpected = prettyFormat(toCanonicalXml(expected));
        String canonicalActual = prettyFormat(toCanonicalXml(actual));
        assertEquals(canonicalExpected, canonicalActual);
    }
}

Prefiero esto a XmlUnit porque el código del cliente (código de prueba) es más limpio.


1
Esto funciona bien en dos pruebas que hice ahora, con el mismo XML y con XML diferente. Con IntelliJ diff, las diferencias en el XML comparado son fáciles de detectar.
Yngvar Kristiansen

1
Por cierto, necesitará esta dependencia si usa Maven: <dependency> <groupId> org.apache.santuario </groupId> <artifactId> xmlsec </artifactId> <version> 2.0.6 </version> </ dependencia>
Yngvar Kristiansen

1

El siguiente código me funciona

String xml1 = ...
String xml2 = ...
XMLUnit.setIgnoreWhitespace(true);
XMLUnit.setIgnoreAttributeOrder(true);
XMLAssert.assertXMLEqual(actualxml, xmlInDb);

1
Cualquier contexto? Referencia de la biblioteca?
Ben

0

Usando JExamXML con la aplicación java

    import com.a7soft.examxml.ExamXML;
    import com.a7soft.examxml.Options;

       .................

       // Reads two XML files into two strings
       String s1 = readFile("orders1.xml");
       String s2 = readFile("orders.xml");

       // Loads options saved in a property file
       Options.loadOptions("options");

       // Compares two Strings representing XML entities
       System.out.println( ExamXML.compareXMLString( s1, s2 ) );

0

Requerí la misma funcionalidad solicitada en la pregunta principal. Como no se me permitió usar bibliotecas de terceros, he creado mi propia solución basada en la solución @Archimedes Trajano.

Lo siguiente es mi solución.

import java.io.ByteArrayInputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.junit.Assert;
import org.w3c.dom.Document;

/**
 * Asserts for asserting XML strings.
 */
public final class AssertXml {

    private AssertXml() {
    }

    private static Pattern NAMESPACE_PATTERN = Pattern.compile("xmlns:(ns\\d+)=\"(.*?)\"");

    /**
     * Asserts that two XML are of identical content (namespace aliases are ignored).
     * 
     * @param expectedXml expected XML
     * @param actualXml actual XML
     * @throws Exception thrown if XML parsing fails
     */
    public static void assertEqualXmls(String expectedXml, String actualXml) throws Exception {
        // Find all namespace mappings
        Map<String, String> fullnamespace2newAlias = new HashMap<String, String>();
        generateNewAliasesForNamespacesFromXml(expectedXml, fullnamespace2newAlias);
        generateNewAliasesForNamespacesFromXml(actualXml, fullnamespace2newAlias);

        for (Entry<String, String> entry : fullnamespace2newAlias.entrySet()) {
            String newAlias = entry.getValue();
            String namespace = entry.getKey();
            Pattern nsReplacePattern = Pattern.compile("xmlns:(ns\\d+)=\"" + namespace + "\"");
            expectedXml = transletaNamespaceAliasesToNewAlias(expectedXml, newAlias, nsReplacePattern);
            actualXml = transletaNamespaceAliasesToNewAlias(actualXml, newAlias, nsReplacePattern);
        }

        // nomralize namespaces accoring to given mapping

        DocumentBuilder db = initDocumentParserFactory();

        Document expectedDocuemnt = db.parse(new ByteArrayInputStream(expectedXml.getBytes(Charset.forName("UTF-8"))));
        expectedDocuemnt.normalizeDocument();

        Document actualDocument = db.parse(new ByteArrayInputStream(actualXml.getBytes(Charset.forName("UTF-8"))));
        actualDocument.normalizeDocument();

        if (!expectedDocuemnt.isEqualNode(actualDocument)) {
            Assert.assertEquals(expectedXml, actualXml); //just to better visualize the diffeences i.e. in eclipse
        }
    }


    private static DocumentBuilder initDocumentParserFactory() throws ParserConfigurationException {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(false);
        dbf.setCoalescing(true);
        dbf.setIgnoringElementContentWhitespace(true);
        dbf.setIgnoringComments(true);
        DocumentBuilder db = dbf.newDocumentBuilder();
        return db;
    }

    private static String transletaNamespaceAliasesToNewAlias(String xml, String newAlias, Pattern namespacePattern) {
        Matcher nsMatcherExp = namespacePattern.matcher(xml);
        if (nsMatcherExp.find()) {
            xml = xml.replaceAll(nsMatcherExp.group(1) + "[:]", newAlias + ":");
            xml = xml.replaceAll(nsMatcherExp.group(1) + "=", newAlias + "=");
        }
        return xml;
    }

    private static void generateNewAliasesForNamespacesFromXml(String xml, Map<String, String> fullnamespace2newAlias) {
        Matcher nsMatcher = NAMESPACE_PATTERN.matcher(xml);
        while (nsMatcher.find()) {
            if (!fullnamespace2newAlias.containsKey(nsMatcher.group(2))) {
                fullnamespace2newAlias.put(nsMatcher.group(2), "nsTr" + (fullnamespace2newAlias.size() + 1));
            }
        }
    }

}

Compara dos cadenas XML y se encarga de las asignaciones de espacio de nombres que no coinciden al traducirlas a valores únicos en ambas cadenas de entrada.

Se puede ajustar, es decir, en caso de traducción de espacios de nombres. Pero para mis requisitos solo hace el trabajo.


-2

Como usted dice "semánticamente equivalente", supongo que quiere decir que quiere hacer algo más que verificar literalmente que las salidas xml son (string) iguales, y que desea algo como

<foo> algunas cosas aquí </foo> </code>

y

<foo> algunas cosas aquí </foo> </code>

lee como equivalente. En última instancia, va a importar cómo se defina "semánticamente equivalente" en cualquier objeto desde el que se reconstituya el mensaje. Simplemente construya ese objeto a partir de los mensajes y use un igual () personalizado para definir lo que está buscando.


44
No es una respuesta sino una pregunta.
Kartoch
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.