Cara terbaik untuk membandingkan 2 dokumen XML di Jawa

198

Saya mencoba untuk menulis tes otomatis aplikasi yang pada dasarnya menerjemahkan format pesan khusus menjadi pesan XML dan mengirimkannya ke ujung lainnya. Saya punya pasangan input / output pesan yang baik sehingga yang perlu saya lakukan hanyalah mengirim pesan input dan mendengarkan pesan XML untuk keluar dari ujung lainnya.

Ketika tiba saatnya untuk membandingkan output aktual dengan output yang diharapkan, saya mengalami beberapa masalah. Pikiran pertama saya adalah hanya melakukan perbandingan string pada pesan yang diharapkan dan aktual. Ini tidak berfungsi dengan baik karena contoh data yang kami miliki tidak selalu diformat secara konsisten dan sering ada alias berbeda yang digunakan untuk ruang nama XML (dan terkadang ruang nama tidak digunakan sama sekali.)

Saya tahu saya dapat mengurai kedua string dan kemudian berjalan melalui masing-masing elemen dan membandingkannya sendiri dan ini tidak akan terlalu sulit untuk dilakukan, tetapi saya merasa ada cara yang lebih baik atau perpustakaan yang bisa saya manfaatkan.

Jadi, lanjut, pertanyaannya adalah:

Diberikan dua String Java yang keduanya mengandung XML yang valid, bagaimana Anda menentukan apakah keduanya setara secara semantik? Poin bonus jika Anda memiliki cara untuk menentukan apa perbedaannya.

Mike Deck
sumber

Jawaban:

197

Kedengarannya seperti pekerjaan untuk XMLUnit

Contoh:

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
  }
}
Tom
sumber
1
Saya pernah mengalami masalah dengan XMLUNit di masa lalu, sudah terlalu berlebihan dengan versi XML API dan belum terbukti andal. Sudah lama sejak saya membuangnya untuk XOM, jadi mungkin itu sudah ada sejak itu.
skaffman
63
Untuk pemula ke XMLUnit, perhatikan bahwa, secara default, myDiff.similar () akan mengembalikan false jika kontrol dan dokumen uji berbeda dalam indentasi / baris baru. Saya mengharapkan perilaku ini dari myDiff.identical (), dan bukan dari myDiff.similar (). Sertakan XMLUnit.setIgnoreWhitespace (true); dalam metode setUp Anda untuk mengubah perilaku untuk semua tes di kelas tes Anda, atau menggunakannya dalam metode tes individu untuk mengubah perilaku hanya untuk tes itu.
Stew
1
@Stew, terima kasih atas komentar Anda, baru mulai dengan XMLUnit dan saya yakin akan menghadapi masalah ini. +1
Jay
2
Jika Anda mencoba ini dengan XMLUnit 2 di github, versi 2 itu adalah penulisan ulang yang lengkap, jadi contoh ini adalah untuk XMLUnit 1 di SourceForge. Juga, halaman sourceforge menyatakan "XMLUnit untuk Java 1.x akan tetap dipertahankan".
Yngvar Kristiansen
1
metode asertXMLE sama dengan dari XMLAssert.java .
user2818782
36

Berikut ini akan memeriksa apakah dokumen sama menggunakan perpustakaan JDK standar.

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

Document doc1 = db.parse (File baru ("file1.xml"));
doc1.normalizeDocument ();

Document doc2 = db.parse (File baru ("file2.xml"));
doc2.normalizeDocument ();

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

menormalkan () apakah ada untuk memastikan tidak ada siklus (secara teknis tidak akan ada)

Kode di atas akan membutuhkan ruang putih untuk menjadi sama di dalam elemen, karena mempertahankan dan mengevaluasinya. Parser XML standar yang datang dengan Java tidak memungkinkan Anda untuk mengatur fitur untuk menyediakan versi kanonik atau memahami xml:spacejika itu akan menjadi masalah maka Anda mungkin memerlukan pengurai XML pengganti seperti xerces atau menggunakan JDOM.

Archimedes Trajano
sumber
4
Ini berfungsi sempurna untuk XML tanpa spasi nama atau dengan awalan namespace "dinormalisasi". Saya ragu apakah itu berfungsi jika satu XML adalah <ns1: a xmlns: ns1 = "ns" /> dan yang lainnya adalah <ns2: a xmlns: ns2 = "ns" />
koppor
dbf.setIgnoringElementContentWhitespace (true) tidak memiliki hasil yang saya harapkan <root> nama </root> tidak sama dengan <root> nama </name> dengan solusi ini (diisi dengan dua spasi) tetapi XMLUnit memberikan hasil yang sama dalam hal ini (JDK8)
Miklos Krivan
Bagi saya itu tidak mengabaikan jeda baris, yang merupakan masalah.
Flyout91
setIgnoringElementContentWhitespace(false)
Archimedes Trajano
28

Xom memiliki utilitas Canonicalizer yang mengubah DOM Anda menjadi bentuk biasa, yang kemudian dapat Anda tegangkan dan bandingkan. Jadi, terlepas dari penyimpangan spasi putih atau pemesanan atribut, Anda bisa mendapatkan perbandingan dokumen Anda yang teratur dan dapat diprediksi.

Ini bekerja sangat baik di IDE yang telah mendedikasikan komparator String visual, seperti Eclipse. Anda mendapatkan representasi visual dari perbedaan semantik antara dokumen.

skaffman
sumber
21

Versi terbaru dari XMLUnit dapat membantu pekerjaan menyatakan dua XML sama. Juga XMLUnit.setIgnoreWhitespace()dan XMLUnit.setIgnoreAttributeOrder()mungkin perlu untuk kasus tersebut.

Lihat kode kerja dari contoh sederhana penggunaan Unit XML di bawah ini.

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

}

Jika menggunakan Maven, tambahkan ini ke pom.xml:

<dependency>
    <groupId>xmlunit</groupId>
    <artifactId>xmlunit</artifactId>
    <version>1.4</version>
</dependency>
acdcjunior
sumber
Ini sangat cocok untuk orang yang perlu membandingkan dari metode statis.
Andy B
Ini jawaban yang sempurna. Terima kasih .. Namun saya perlu mengabaikan node yang tidak ada. Karena saya tidak ingin melihat dalam hasil keluaran seperti keluaran: Diharapkan keberadaan simpul anak "null" tetapi ...... Bagaimana saya bisa melakukan itu? Salam. @acdcjunior
limonik
1
XMLUnit.setIgnoreAttributeOrder (true); tidak bekerja. Jika beberapa node memiliki urutan yang berbeda, perbandingannya akan gagal.
Bevor
[UPDATE] solusi ini berfungsi: stackoverflow.com/questions/33695041/…
Bevor
Anda menyadari "IgnoreAttributeOrder" berarti mengabaikan urutan atribut dan tidak mengabaikan urutan node, bukan?
acdcjunior
7

Terima kasih, saya memperpanjang ini, coba ini ...

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();
    }
}
Lembing
sumber
3
Cukup terlambat, tetapi hanya ingin mencatat bahwa bagian kode ini memiliki bug: Di diffNodes (), node2 tidak direferensikan - loop kedua menggunakan kembali node1 secara salah (saya mengedit kode untuk memperbaikinya). Juga, ada 1 batasan: Karena cara peta anak dikunci, perbedaan ini tidak mendukung kasus di mana nama elemen tidak unik, yaitu elemen yang mengandung elemen anak berulang.
aberrant80
7

Membangun jawaban Tom , inilah contoh menggunakan XMLUnit v2.

Menggunakan dependensi pakar ini

    <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>

..dan inilah kode tes

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

Dokumentasi yang menguraikan ini adalah https://github.com/xmlunit/xmlunit#comparing-two-documents

Tom Saleeba
sumber
3

skaffman tampaknya memberikan jawaban yang bagus.

Cara lain mungkin untuk memformat XML menggunakan utilitas commmand line seperti xmlstarlet ( http://xmlstar.sourceforge.net/ ) dan kemudian memformat kedua string dan kemudian menggunakan utilitas utilitas (pustaka) apa pun (pustaka) untuk membedakan file output yang dihasilkan. Saya tidak tahu apakah ini solusi yang baik ketika masalah dengan ruang nama.

anjanb
sumber
3

AssertJ 1.4+ memiliki pernyataan spesifik untuk membandingkan konten XML:

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

Ini Dokumentasi

Gian Marco Gherardi
sumber
2

Saya menggunakan Altova DiffDog yang memiliki opsi untuk membandingkan file XML secara struktural (mengabaikan data string).

Ini berarti bahwa (jika memeriksa opsi 'abaikan teks'):

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

dan

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

sama dalam arti bahwa mereka memiliki kesetaraan struktural. Ini berguna jika Anda memiliki contoh file yang berbeda dalam data, tetapi tidak terstruktur!

Pimin Konstantin Kefaloukos
sumber
3
Satu-satunya kekurangan adalah bahwa itu tidak gratis (€ 99 untuk lisensi pro), dengan uji coba 30 hari.
Pimin Konstantin Kefaloukos
2
Saya hanya menemukan utilitas ( altova.com/diffdog/diff-merge-tool.html ); senang memiliki perpustakaan.
dma_k
1

Ini akan membandingkan XML string lengkap (memformatnya kembali di jalan). Ini membuatnya mudah untuk bekerja dengan IDE Anda (IntelliJ, Eclipse), karena Anda cukup mengklik dan secara visual melihat perbedaan dalam file 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);
    }
}

Saya lebih suka ini daripada XmlUnit karena kode klien (kode uji) lebih bersih.

Wojtek
sumber
1
Ini berfungsi dengan baik dalam dua tes yang saya lakukan sekarang, dengan XML yang sama dan dengan XML yang berbeda. Dengan IntelliJ, perbedaan dalam XML yang dibandingkan mudah dikenali.
Yngvar Kristiansen
1
Ngomong-ngomong, Anda akan memerlukan dependensi ini jika menggunakan Maven: <dependency> <groupId> org.apache.santuario </groupId> <artifactId> xmlsec </artifactId> <version> 2.0.6 </version> </ ketergantungan>
Yngvar Kristiansen
1

Kode di bawah ini berfungsi untuk saya

String xml1 = ...
String xml2 = ...
XMLUnit.setIgnoreWhitespace(true);
XMLUnit.setIgnoreAttributeOrder(true);
XMLAssert.assertXMLEqual(actualxml, xmlInDb);
arunkumar sambu
sumber
1
Ada konteks? Referensi perpustakaan?
Ben
0

Menggunakan JExamXML dengan aplikasi 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
sumber
0

Saya membutuhkan fungsi yang sama seperti yang diminta dalam pertanyaan utama. Karena saya tidak diizinkan menggunakan pustaka pihak ketiga mana pun, saya telah membuat solusi sendiri berdasarkan pada solusi @Archimedes Trajano.

Berikut ini adalah solusi saya.

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

}

Ini membandingkan dua string XML dan menangani setiap pemetaan namespace yang tidak cocok dengan menerjemahkannya ke nilai unik di kedua string input.

Dapat diatur dengan baik yaitu dalam hal terjemahan ruang nama. Tetapi untuk persyaratan saya hanya melakukan pekerjaan.

TouDick
sumber
-2

Karena Anda mengatakan "setara secara semantik", saya berasumsi bahwa Anda ingin melakukan lebih dari sekadar memverifikasi bahwa output xml sama (string), dan Anda menginginkan sesuatu seperti

<foo> beberapa hal di sini </foo> </code>

dan

<foo> beberapa hal di sini </foo> </code>

baca sebagai setara. Pada akhirnya itu akan menjadi masalah bagaimana Anda mendefinisikan "setara semantik" pada objek apa pun yang Anda pesan. Cukup buat objek itu dari pesan dan gunakan custom equals () untuk menentukan apa yang Anda cari.

Steve B.
sumber
4
Bukan jawaban tetapi pertanyaan.
Kartoch