Meilleure façon de comparer 2 documents XML en Java

198

J'essaie d'écrire un test automatisé d'une application qui traduit essentiellement un format de message personnalisé en un message XML et l'envoie à l'autre extrémité. J'ai un bon ensemble de paires de messages d'entrée / sortie, donc tout ce que je dois faire est d'envoyer les messages d'entrée et d'écouter le message XML pour sortir de l'autre côté.

Quand vient le temps de comparer la sortie réelle à la sortie attendue, je rencontre des problèmes. Ma première pensée a été de faire des comparaisons de chaînes sur les messages attendus et réels. Cela ne fonctionne pas très bien car les données d'exemple que nous avons ne sont pas toujours formatées de manière cohérente et il y a souvent des alias différents utilisés pour l'espace de noms XML (et parfois les espaces de noms ne sont pas du tout utilisés.)

Je sais que je peux analyser les deux chaînes, puis parcourir chaque élément et les comparer moi-même et cela ne serait pas trop difficile à faire, mais j'ai l'impression qu'il existe une meilleure méthode ou une bibliothèque que je pourrais exploiter.

Donc, résumée, la question est:

Étant donné deux chaînes Java qui contiennent toutes deux du XML valide, comment allez-vous déterminer si elles sont sémantiquement équivalentes? Points bonus si vous avez un moyen de déterminer quelles sont les différences.

Mike Deck
la source

Réponses:

197

Cela ressemble à un travail pour XMLUnit

Exemple:

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
  }
}
À M
la source
1
J'ai eu des problèmes avec XMLUNit dans le passé, il a été hyper-tordu avec les versions d'API XML et n'a pas fait ses preuves. Cela fait un moment que je ne l'ai pas abandonné pour XOM, alors peut-être que c'est amélioré depuis.
skaffman
63
Pour les débutants à XMLUnit, notez que, par défaut, myDiff.similar () retournera false si les documents de contrôle et de test diffèrent par l'indentation / les nouvelles lignes. Je m'attendais à ce comportement de myDiff.identical (), et non de myDiff.similar (). Inclure XMLUnit.setIgnoreWhitespace (true); dans votre méthode setUp pour modifier le comportement de tous les tests de votre classe de test, ou utilisez-le dans une méthode de test individuelle pour modifier le comportement uniquement pour ce test.
Ragoût
1
@Stew merci pour votre commentaire, en commençant simplement par XMLUnit et je suis sûr qu'il aurait rencontré ce problème. +1
Jay
2
Dans le cas où vous essayez ceci avec XMLUnit 2 sur github, la version 2 c'est une réécriture complète, donc cet exemple est pour XMLUnit 1 sur SourceForge. De plus, la page sourceforge indique que "XMLUnit pour Java 1.x sera toujours maintenu".
Yngvar Kristiansen du
1
est assertXMLEqual à partir de XMLAssert.java .
user2818782
36

Les éléments suivants vérifieront si les documents sont égaux à l'aide des bibliothèques JDK standard.

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

Document doc1 = db.parse (nouveau fichier ("file1.xml"));
doc1.normalizeDocument ();

Document doc2 = db.parse (nouveau fichier ("file2.xml"));
doc2.normalizeDocument ();

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

normaliser () est là pour s'assurer qu'il n'y a pas de cycles (il n'y en aurait techniquement pas)

Le code ci-dessus exigera que les espaces blancs soient les mêmes dans les éléments, car il les conserve et les évalue. L'analyseur XML standard fourni avec Java ne vous permet pas de définir une fonctionnalité pour fournir une version canonique ou de comprendre xml:spacesi cela va être un problème, vous devrez peut-être un analyseur XML de remplacement tel que xerces ou utiliser JDOM.

Archimedes Trajano
la source
4
Cela fonctionne parfaitement pour les XML sans espaces de noms ou avec des préfixes d'espace de noms "normalisés". Je doute que cela fonctionne si un XML est <ns1: a xmlns: ns1 = "ns" /> et l'autre est <ns2: a xmlns: ns2 = "ns" />
koppor
dbf.setIgnoringElementContentWhitespace (true) n'a pas le résultat que je m'attendrais à ce que le <root> nom </root> ne soit pas égal à <root> nom </name> avec cette solution (rempli avec deux espaces) mais XMLUnit donne le résultat égal dans ce cas (JDK8)
Miklos Krivan
Pour moi, il n'ignore pas les sauts de ligne, ce qui est un problème.
Flyout91
setIgnoringElementContentWhitespace(false)
Archimedes Trajano
28

Xom possède un utilitaire Canonicalizer qui transforme vos DOM en une forme régulière, que vous pouvez ensuite filtrer et comparer. Ainsi, indépendamment des irrégularités des espaces blancs ou de l'ordre des attributs, vous pouvez obtenir des comparaisons régulières et prévisibles de vos documents.

Cela fonctionne particulièrement bien dans les IDE qui ont des comparateurs visuels de chaînes dédiés, comme Eclipse. Vous obtenez une représentation visuelle des différences sémantiques entre les documents.

skaffman
la source
21

La dernière version de XMLUnit peut aider à affirmer que deux XML sont égaux. Aussi XMLUnit.setIgnoreWhitespace()et XMLUnit.setIgnoreAttributeOrder()peut être nécessaire pour le cas en question.

Voir le code de travail d'un exemple simple d'utilisation d'unité XML ci-dessous.

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 vous utilisez Maven, ajoutez ceci à votre pom.xml:

<dependency>
    <groupId>xmlunit</groupId>
    <artifactId>xmlunit</artifactId>
    <version>1.4</version>
</dependency>
acdcjunior
la source
C'est parfait pour les gens qui ont besoin de comparer à partir d'une méthode statique.
Andy B
C'est une réponse parfaite. Merci .. Cependant je dois ignorer les nœuds qui n'existent pas. Puisque je ne veux pas voir dans le résultat de sortie une telle sortie: Présence attendue du nœud enfant "null" mais était ...... Comment faire? Cordialement. @acdcjunior
limonik
1
XMLUnit.setIgnoreAttributeOrder (true); ne marche pas. Si certains nœuds ont un ordre différent, la comparaison échouera.
Bevor
[MISE À JOUR] cette solution fonctionne: stackoverflow.com/questions/33695041/…
Bevor
Vous réalisez que "IgnoreAttributeOrder" signifie ignorer l'ordre des attributs et ne pas ignorer l'ordre des nœuds, non?
acdcjunior
7

Merci, j'ai étendu cela, essayez ceci ...

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();
    }
}
Javelot
la source
3
Assez tard, mais je voulais juste noter que ce morceau de code a un bogue: dans diffNodes (), node2 n'est pas référencé - la deuxième boucle réutilise node1 de manière incorrecte (j'ai édité le code pour résoudre ce problème). De plus, il a 1 limitation: en raison de la façon dont les cartes enfants sont incrustées, cette différence ne prend pas en charge le cas où les noms d'éléments ne sont pas uniques, c'est-à-dire les éléments contenant des éléments enfants répétables.
aberrant80
7

S'appuyer sur Tom la réponse de , voici un exemple utilisant XMLUnit v2.

Il utilise ces dépendances 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>

..et voici le code de test

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 documentation qui décrit cela est https://github.com/xmlunit/xmlunit#comparing-two-documents

Tom Saleeba
la source
3

skaffman semble donner une bonne réponse.

une autre façon est probablement de formater le XML à l'aide d'un utilitaire de ligne de commande comme xmlstarlet ( http://xmlstar.sourceforge.net/ ), puis de formater les deux chaînes, puis d'utiliser n'importe quel utilitaire diff (bibliothèque) pour différencier les fichiers de sortie résultants. Je ne sais pas si c'est une bonne solution lorsque les problèmes concernent les espaces de noms.

anjanb
la source
3

AssertJ 1.4+ a des assertions spécifiques pour comparer le contenu XML:

String expectedXml = "<foo />";
String actualXml = "<bar />";
assertThat(actualXml).isXmlEqualTo(expectedXml);

Voici la documentation

Gian Marco Gherardi
la source
2

J'utilise Altova DiffDog qui a des options pour comparer structurellement les fichiers XML (en ignorant les données de chaîne).

Cela signifie que (si vous cochez l'option «ignorer le texte»):

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

et

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

sont égaux dans le sens où ils ont une égalité structurelle. C'est pratique si vous avez des fichiers d'exemple qui diffèrent en données, mais pas en structure!

Pimin Konstantin Kefaloukos
la source
3
Seul bémol c'est qu'il n'est pas gratuit (99 € pour une licence pro), avec 30 jours d'essai.
Pimin Konstantin Kefaloukos
2
Je n'ai trouvé que l'utilitaire ( altova.com/diffdog/diff-merge-tool.html ); agréable d'avoir une bibliothèque.
dma_k
1

Cela comparera les XML de chaîne complète (en les reformatant en cours de route). Il facilite le travail avec votre IDE (IntelliJ, Eclipse), car il vous suffit de cliquer et de voir visuellement la différence dans les fichiers 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);
    }
}

Je préfère cela à XmlUnit car le code client (code de test) est plus propre.

Wojtek
la source
1
Cela fonctionne très bien dans deux tests que j'ai faits maintenant, avec le même XML et avec différents XML. Avec IntelliJ diff, les différences dans le XML comparé sont faciles à repérer.
Yngvar Kristiansen
1
Soit dit en passant, vous aurez besoin de cette dépendance si vous utilisez Maven: <dependency> <groupId> org.apache.santuario </groupId> <artifactId> xmlsec </artifactId> <version> 2.0.6 </version> </ dépendance>
Yngvar Kristiansen
1

Le code ci-dessous fonctionne pour moi

String xml1 = ...
String xml2 = ...
XMLUnit.setIgnoreWhitespace(true);
XMLUnit.setIgnoreAttributeOrder(true);
XMLAssert.assertXMLEqual(actualxml, xmlInDb);
arunkumar sambu
la source
1
Un contexte? Référence de la bibliothèque?
Ben
0

Utiliser JExamXML avec une application 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 ) );
sreehari
la source
0

J'ai exigé la même fonctionnalité que celle demandée dans la question principale. Comme je n'étais pas autorisé à utiliser des bibliothèques tierces, j'ai créé ma propre solution basée sur la solution @Archimedes Trajano.

Voici ma solution.

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));
            }
        }
    }

}

Il compare deux chaînes XML et prend en charge les mappages d'espaces de noms incompatibles en les convertissant en valeurs uniques dans les deux chaînes d'entrée.

Peut être affiné, c'est-à-dire en cas de traduction d'espaces de noms. Mais pour mes besoins fait juste le travail.

TouDick
la source
-2

Puisque vous dites «sémantiquement équivalent», je suppose que vous voulez dire que vous voulez faire plus que simplement vérifier que les sorties xml sont (chaîne) égales et que vous voudriez quelque chose comme

<foo> quelques trucs ici </foo> </code>

et

<foo> quelques trucs ici </foo> </code>

lire comme équivalent. En fin de compte, la façon dont vous définissez "sémantiquement équivalent" sur n'importe quel objet à partir duquel vous reconstituez le message aura de l'importance. Créez simplement cet objet à partir des messages et utilisez un égal personnalisé () pour définir ce que vous recherchez.

Steve B.
la source
4
Pas une réponse mais une question.
Kartoch