Cách tốt nhất để so sánh 2 tài liệu XML trong Java


198

Tôi đang cố gắng viết một bài kiểm tra tự động của một ứng dụng về cơ bản chuyển một định dạng thông điệp tùy chỉnh thành một thông điệp XML và gửi nó ra đầu kia. Tôi đã có một bộ các cặp thông báo đầu vào / đầu ra tốt, vì vậy tất cả những gì tôi cần làm là gửi các thông điệp đầu vào vào và lắng nghe thông điệp XML xuất hiện ở đầu kia.

Khi đến lúc so sánh sản lượng thực tế với sản lượng dự kiến ​​tôi đang gặp phải một số vấn đề. Suy nghĩ đầu tiên của tôi chỉ là thực hiện so sánh chuỗi trên các thông điệp dự kiến ​​và thực tế. Điều này không hoạt động tốt vì dữ liệu mẫu mà chúng tôi không phải lúc nào cũng được định dạng nhất quán và thường có các bí danh khác nhau được sử dụng cho không gian tên XML (và đôi khi không gian tên không được sử dụng.)

Tôi biết tôi có thể phân tích cả hai chuỗi và sau đó đi qua từng yếu tố và tự so sánh chúng và điều này sẽ không quá khó để làm, nhưng tôi có cảm giác có một cách tốt hơn hoặc một thư viện mà tôi có thể tận dụng.

Vì vậy, đun sôi xuống, câu hỏi là:

Đưa ra hai Chuỗi Java mà cả hai đều chứa XML hợp lệ, bạn sẽ xác định xem chúng có tương đương về mặt ngữ nghĩa không? Điểm thưởng nếu bạn có cách xác định sự khác biệt là gì.

Câu trả lời:


197

Nghe có vẻ như một công việc cho XMLUnit

Thí dụ:

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
Trước đây, tôi đã gặp vấn đề với XMLUNit, nó rất phức tạp với các phiên bản API XML và chưa được chứng minh là đáng tin cậy. Đã được một thời gian kể từ khi tôi bỏ nó cho XOM, vì vậy có lẽ nó đã bị thôi thúc kể từ đó.
skaffman

63
Đối với người mới bắt đầu sử dụng XMLUnit, lưu ý rằng, theo mặc định, myDiff.similar () sẽ trả về false nếu tài liệu kiểm soát và kiểm tra khác nhau về thụt lề / dòng mới. Tôi mong đợi hành vi này từ myDiff.identical () chứ không phải từ myDiff.similar (). Bao gồm XMLUnit.setIgnoreWhitespace (true); trong phương thức setUp của bạn để thay đổi hành vi cho tất cả các thử nghiệm trong lớp thử nghiệm của bạn hoặc sử dụng nó trong một phương thức thử nghiệm riêng lẻ để thay đổi hành vi chỉ cho thử nghiệm đó.
Hầm

1
@Stew cảm ơn vì nhận xét của bạn, chỉ cần bắt đầu với XMLUnit và chắc chắn sẽ phải đối mặt với vấn đề này. +1
Jay

2
Trong trường hợp bạn đang thử điều này với XMLUnit 2 trên github, phiên bản 2 là bản viết lại hoàn chỉnh, vì vậy ví dụ này dành cho XMLUnit 1 trên SourceForge. Ngoài ra, trang sourceforge nói "XMLUnit cho Java 1.x vẫn sẽ được duy trì".
Yngvar Kristiansen

1
phương thức là assertXMLEqual như từ XMLAssert.java .
dùng2818782

36

Sau đây sẽ kiểm tra xem các tài liệu có bằng nhau không khi sử dụng các thư viện JDK tiêu chuẩn.

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance ();
dbf.setNamespaceAware (đúng);
dbf.setCoalescing (đúng);
dbf.setIgnoringEuityContentWhitespace (true);
dbf.setIgnoringComments (đúng);
DocumentBuilder db = dbf.newDocumentBuilder ();

Tài liệu doc1 = db.parse (Tệp mới ("file1.xml"));
doc1.n normalizeDocument ();

Tài liệu doc2 = db.parse (Tệp mới ("file2.xml"));
doc2.n normalizeDocument ();

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

chuẩn hóa () ở đó để đảm bảo không có chu kỳ (về mặt kỹ thuật sẽ không có)

Đoạn mã trên sẽ yêu cầu các khoảng trắng giống nhau trong các phần tử, bởi vì nó bảo tồn và đánh giá nó. Trình phân tích cú pháp XML tiêu chuẩn đi kèm với Java không cho phép bạn thiết lập một tính năng để cung cấp một phiên bản chính tắc hoặc hiểu xml:spacenếu đó sẽ là một vấn đề thì bạn có thể cần một trình phân tích cú pháp XML thay thế như xerces hoặc sử dụng JDOM.


4
Điều này hoạt động hoàn hảo cho các XML không có không gian tên hoặc với các tiền tố không gian tên "chuẩn hóa". Tôi nghi ngờ rằng nó hoạt động nếu một XML là <ns1: a xmlns: ns1 = "ns" /> và cái kia là <ns2: a xmlns: ns2 = "ns" />
koppor

dbf.setIgnoringEuityContentWhitespace (true) không có kết quả Tôi mong đợi <root> name </ root> không bằng <root> name </ name> với giải pháp này (được đệm bằng hai khoảng trắng) nhưng XMLUnit cho kết quả như nhau trong trường hợp này (JDK8)
Miklos

Đối với tôi nó không bỏ qua ngắt dòng, đó là một vấn đề.
Flyout91

setIgnoringElementContentWhitespace(false)
Archimedes Trajano

28

Xom có tiện ích Canonicalizer biến DOM của bạn thành dạng thông thường, sau đó bạn có thể xâu chuỗi và so sánh. Vì vậy, bất kể khoảng trắng bất thường hoặc thứ tự thuộc tính, bạn có thể nhận được các so sánh thường xuyên, có thể dự đoán được của các tài liệu của bạn.

Điều này đặc biệt hiệu quả trong các IDE có các bộ so sánh Chuỗi trực quan chuyên dụng, như Eclipse. Bạn nhận được một đại diện trực quan về sự khác biệt ngữ nghĩa giữa các tài liệu.


21

Phiên bản mới nhất của XMLUnit có thể giúp công việc khẳng định hai XML bằng nhau. Ngoài ra XMLUnit.setIgnoreWhitespace()XMLUnit.setIgnoreAttributeOrder()có thể cần thiết cho trường hợp trong câu hỏi.

Xem mã làm việc của một ví dụ đơn giản về việc sử dụng Đơn vị XML bên dưới.

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

}

Nếu sử dụng Maven, hãy thêm phần này vào pom.xml:

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

Điều này là hoàn hảo cho những người cần so sánh từ một phương pháp tĩnh.
Andy B

Đây là câu trả lời hoàn hảo. Cảm ơn bạn .. Tuy nhiên tôi cần bỏ qua các nút không tồn tại. Vì tôi không muốn thấy trong kết quả đầu ra như vậy: Đầu ra dự kiến ​​của nút con "null" nhưng là ...... Làm thế nào tôi có thể làm điều đó? Trân trọng. @acdcjunior
limonik

1
XMLUnit.setIgnoreAttributionOrder (đúng); không hoạt động. Nếu một số nút có thứ tự khác, việc so sánh sẽ thất bại.
Bevor

[CẬP NHẬT] giải pháp này hoạt động: stackoverflow.com/questions/33695041/ từ
Bevor

Bạn có nhận ra "IgnoreAttributionOrder" có nghĩa là bỏ qua thứ tự thuộc tính và không bỏ qua thứ tự nút, phải không?
acdcjunior

7

Cảm ơn, tôi đã mở rộng cái này, thử cái này ...

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
Khá muộn, nhưng chỉ muốn lưu ý rằng đoạn mã này có lỗi: Trong diffNodes (), node2 không được tham chiếu - vòng lặp thứ hai sử dụng lại nút1 không chính xác (Tôi đã chỉnh sửa mã để sửa lỗi này). Ngoài ra, nó có 1 hạn chế: Do cách bản đồ con được khóa, khác biệt này không hỗ trợ trong trường hợp tên phần tử không phải là duy nhất, tức là các phần tử có chứa các phần tử con lặp lại.
aberrant80

7

Dựa trên câu trả lời của Tom , đây là một ví dụ sử dụng XMLUnit v2.

Nó sử dụng những phụ thuộc maven này

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

..và đây là mã kiểm tra

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

Tài liệu phác thảo này là https://github.com/xmlunit/xmlunit#compared-two-document


3

skaffman dường như đang đưa ra một câu trả lời tốt.

một cách khác có lẽ là định dạng XML bằng cách sử dụng tiện ích dòng commmand như xmlstarlet ( http://xmlstar.sourceforge.net/ ) và sau đó định dạng cả hai chuỗi và sau đó sử dụng bất kỳ tiện ích khác (thư viện) để tìm khác biệt các tệp đầu ra. Tôi không biết liệu đây có phải là một giải pháp tốt khi các sự cố xảy ra với không gian tên.


3

AssertJ 1.4+ có các xác nhận cụ thể để so sánh nội dung XML:

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

Đây là Tài liệu


2

Tôi đang sử dụng Altova DiffDog có các tùy chọn để so sánh các tệp XML theo cấu trúc (bỏ qua dữ liệu chuỗi).

Điều này có nghĩa là (nếu kiểm tra tùy chọn 'bỏ qua văn bản'):

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

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

đều bình đẳng theo nghĩa là chúng có sự bình đẳng về cấu trúc. Điều này rất hữu ích nếu bạn có các tệp ví dụ khác nhau về dữ liệu, nhưng không có cấu trúc!


3
Điểm trừ duy nhất là nó không miễn phí (99 € cho giấy phép pro), với bản dùng thử 30 ngày.
Pimin Konstantin Kefaloukos

2
Tôi chỉ tìm thấy tiện ích ( altova.com/diffdog/diff-merge-tool.html ); Rất vui khi có một thư viện.
dma_k

1

Điều này sẽ so sánh các chuỗi XML đầy đủ (định dạng lại chúng trên đường). Nó giúp bạn dễ dàng làm việc với IDE của bạn (IntelliJ, Eclipse), vì bạn chỉ cần nhấp và nhìn thấy sự khác biệt trong các tệp 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);
    }
}

Tôi thích điều này hơn XmlUnit vì mã máy khách (mã kiểm tra) sạch hơn.


1
Điều này hoạt động tốt trong hai thử nghiệm tôi đã làm bây giờ, với cùng một XML và với XML khác nhau. Với IntelliJ diff, sự khác biệt trong XML được so sánh rất dễ nhận ra.
Yngvar Kristiansen

1
Nhân tiện, bạn sẽ cần sự phụ thuộc này nếu bạn sử dụng Maven: <phụ thuộc> <groupId> org.apache.santuario </ groupId> <artifactId> xmlsec </ artifactId> <version> 2.0.6 </ version> </ version phụ thuộc>
Yngvar Kristiansen

1

Mã dưới đây làm việc cho tôi

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

1
Bất kỳ bối cảnh? Thư viện tham khảo?
Ben

0

Sử dụng JExamXML với ứng dụng 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

Tôi yêu cầu các chức năng tương tự như yêu cầu trong câu hỏi chính. Vì tôi không được phép sử dụng bất kỳ thư viện của bên thứ 3 nào, tôi đã tạo ra giải pháp của riêng mình dựa trên giải pháp @Archimedes Trajano.

Sau đây là giải pháp của tôi.

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

}

Nó so sánh hai chuỗi XML và quan tâm đến bất kỳ ánh xạ không gian tên không khớp nào bằng cách dịch chúng thành các giá trị duy nhất trong cả hai chuỗi đầu vào.

Có thể được tinh chỉnh tức là trong trường hợp dịch các không gian tên. Nhưng đối với yêu cầu của tôi chỉ làm công việc.


-2

Vì bạn nói "tương đương về mặt ngữ nghĩa", tôi giả sử bạn có nghĩa là bạn muốn làm nhiều hơn là chỉ xác minh theo nghĩa đen rằng các đầu ra xml bằng (chuỗi) bằng và bạn muốn một cái gì đó như

<foo> một số nội dung tại đây </ foo> </ code>

<foo> một số nội dung tại đây </ foo> </ code>

đọc như tương đương. Cuối cùng, vấn đề là bạn định nghĩa "tương đương về mặt ngữ nghĩa" như thế nào đối với bất kỳ đối tượng nào bạn đang khôi phục tin nhắn từ đó. Chỉ cần xây dựng đối tượng đó từ các tin nhắn và sử dụng một tùy chỉnh bằng () để xác định những gì bạn đang tìm kiếm.


4
Không phải là một câu trả lời mà là một câu hỏi.
Kartoch
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.