วิธีที่ดีที่สุดในการเปรียบเทียบ 2 เอกสาร XML ใน Java


198

ฉันกำลังพยายามเขียนการทดสอบอัตโนมัติของแอปพลิเคชันซึ่งโดยทั่วไปจะแปลงรูปแบบข้อความที่กำหนดเองเป็นข้อความ XML และส่งออกไปยังส่วนอื่น ๆ ฉันมีชุดข้อความอินพุต / เอาต์พุตที่ดีดังนั้นสิ่งที่ฉันต้องทำคือส่งข้อความอินพุตและฟังข้อความ XML เพื่อให้ออกมาอีกด้าน

เมื่อถึงเวลาเปรียบเทียบผลลัพธ์จริงกับผลลัพธ์ที่คาดหวังฉันพบปัญหาบางอย่าง ความคิดแรกของฉันคือการเปรียบเทียบข้อความที่คาดหวังและข้อความจริง สิ่งนี้ทำงานได้ไม่ดีนักเนื่องจากข้อมูลตัวอย่างที่เรามีไม่ได้จัดรูปแบบเสมอและมักมีชื่อแทนที่ต่างกันที่ใช้สำหรับเนมสเปซ XML (และบางครั้งเนมสเปซไม่ได้ใช้เลย)

ฉันรู้ว่าฉันสามารถแยกทั้งสองสายแล้วเดินผ่านแต่ละองค์ประกอบและเปรียบเทียบกับตัวเองและสิ่งนี้จะไม่ยากเกินไปที่จะทำ แต่ฉันรู้สึกว่ามันมีวิธีที่ดีกว่าหรือห้องสมุดที่ฉันสามารถใช้ประโยชน์ได้

ดังนั้นต้มคำถามคือ:

กำหนด Java Strings สองรายการซึ่งทั้งคู่มี XML ที่ถูกต้องคุณจะทราบได้อย่างไรว่ามีความหมายเทียบเท่า คะแนนโบนัสหากคุณมีวิธีพิจารณาความแตกต่าง

คำตอบ:


197

ดูเหมือนงานสำหรับ XMLUnit

ตัวอย่าง:

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
ฉันเคยมีปัญหากับ XMLUNit ในอดีตมันเป็นปัญหาที่กระตุกอย่างมากกับเวอร์ชัน XML API และไม่ได้รับการพิสูจน์ว่าเชื่อถือได้ เป็นเวลานานแล้วที่ฉันทิ้งมันไว้สำหรับ XOM ดังนั้นบางทีมันอาจจะไม่ดีตั้งแต่
skaffman

63
สำหรับผู้เริ่มต้นถึง XMLUnit โปรดทราบว่าโดยค่าเริ่มต้น myDiff.similar () จะส่งคืนค่าfalseหากเอกสารควบคุมและทดสอบแตกต่างกันในการเยื้อง / ขึ้นบรรทัดใหม่ ฉันคาดหวังพฤติกรรมนี้จาก myDiff.identical () และไม่ใช่จาก myDiff.similar () รวม XMLUnit.setIgnoreWhitespace (จริง); ในเมธอด setUp ของคุณเพื่อเปลี่ยนพฤติกรรมสำหรับการทดสอบทั้งหมดในคลาสทดสอบของคุณหรือใช้ในวิธีการทดสอบเดี่ยวเพื่อเปลี่ยนพฤติกรรมสำหรับการทดสอบนั้นเท่านั้น
สตูว์

1
@Stew ขอบคุณสำหรับความคิดเห็นของคุณเพียงแค่เริ่มต้นด้วย XMLUnit และฉันแน่ใจว่าจะพบปัญหานี้ +1
Jay

2
ในกรณีที่คุณพยายามทำสิ่งนี้ด้วย XMLUnit 2 บน github เวอร์ชัน 2 เป็นการเขียนซ้ำที่สมบูรณ์ดังนั้นตัวอย่างนี้สำหรับ XMLUnit 1 บน SourceForge นอกจากนี้หน้าเพจของ sourceforge ยังระบุว่า "XMLUnit สำหรับ Java 1.x จะยังคงอยู่"
Yngvar Kristiansen

1
วิธีการคือ assertXMLEqual จากXMLAssert.java
2818782

36

ต่อไปนี้จะตรวจสอบว่าเอกสารมีความเท่าเทียมกันโดยใช้ไลบรารี JDK มาตรฐานหรือไม่

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance ();
dbf.setNamespaceAware (จริง);
dbf.setCoalescing (จริง);
dbf.setIgnoringElementContentWhitespace (จริง);
dbf.setIgnoringComments (จริง);
DocumentBuilder db = dbf.newDocumentBuilder ();

เอกสาร doc1 = db.parse (ไฟล์ใหม่ ("file1.xml"));
doc1.normalizeDocument ();

Document doc2 = db.parse (ไฟล์ใหม่ ("file2.xml"));
doc2.normalizeDocument ();

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

ทำให้ปกติ () อยู่ที่นั่นเพื่อให้แน่ใจว่าไม่มีรอบ (ในทางเทคนิคจะไม่มีใด ๆ )

รหัสข้างต้นจะต้องใช้ช่องว่างสีขาวเหมือนกันภายในองค์ประกอบแม้ว่าจะรักษาและประเมินผล ตัวแยกวิเคราะห์ XML มาตรฐานที่มาพร้อมกับ Java ไม่อนุญาตให้คุณตั้งค่าคุณสมบัติเพื่อให้เป็นรุ่นมาตรฐานหรือเข้าใจxml:spaceว่าจะเป็นปัญหาหรือไม่คุณอาจต้องเปลี่ยน XML แยกวิเคราะห์เช่น xerces หรือใช้ JDOM


4
สิ่งนี้ทำงานได้อย่างสมบูรณ์แบบสำหรับ XML ที่ไม่มีเนมสเปซหรือด้วยคำนำหน้าเนมสเปซ "ปกติ" ฉันสงสัยว่ามันใช้งานได้หาก XML หนึ่ง <ns1: a xmlns: ns1 = "ns" /> และอีกอันคือ <ns2: a xmlns: ns2 = "ns" />
koppor

dbf.setIgnoringElementContentWhitespace (จริง) ไม่มีผลลัพธ์ที่ฉันคาดหวังว่า <root> ชื่อ </root> ไม่เท่ากับ <root> ชื่อ </name> ด้วยวิธีนี้ (บุด้วยสองช่องว่าง) แต่ XMLUnit ให้ผลลัพธ์เท่ากัน ในกรณีนี้ (JDK8)
Miklos Krivan

สำหรับฉันมันจะไม่เพิกเฉยต่อการขึ้นบรรทัดใหม่ซึ่งเป็นปัญหา
Flyout91

setIgnoringElementContentWhitespace(false)
Archimedes Trajano

28

Xomมียูทิลิตี้ Canonicalizer ซึ่งเปลี่ยน DOM ของคุณเป็นรูปแบบปกติซึ่งคุณสามารถทำให้เป็นสตริงและเปรียบเทียบได้ ดังนั้นไม่ว่าจะมีช่องว่างที่ผิดปกติหรือการสั่งซื้อแอททริบิวต์คุณสามารถรับเอกสารของคุณได้อย่างสม่ำเสมอ

วิธีนี้ทำงานได้ดีโดยเฉพาะใน IDEs ที่มีตัวเปรียบเทียบ String แบบวิชวลเฉพาะเช่น Eclipse คุณได้รับการแสดงภาพของความแตกต่างทางความหมายระหว่างเอกสาร


21

เวอร์ชันล่าสุดของXMLUnitสามารถช่วยงานยืนยันสอง XML ได้เท่ากัน นอกจากนี้XMLUnit.setIgnoreWhitespace()และXMLUnit.setIgnoreAttributeOrder()อาจมีความจำเป็นในกรณีที่มีปัญหา

ดูรหัสการทำงานของตัวอย่างง่ายๆของการใช้หน่วย XML ด้านล่าง

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

}

หากใช้ Maven ให้เพิ่มสิ่งนี้ในpom.xml:

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

เหมาะสำหรับผู้ที่ต้องการเปรียบเทียบจากวิธีการคงที่
Andy B

นี่คือคำตอบที่สมบูรณ์แบบ ขอบคุณ .. อย่างไรก็ตามฉันต้องไม่สนใจโหนดที่ไม่มีอยู่จริง เนื่องจากฉันไม่ต้องการที่จะเห็นในผลลัพธ์ผลลัพธ์เช่นเอาท์พุท: การมีอยู่ของโหนดลูก "โมฆะ" แต่เป็น ...... ฉันจะทำอย่างไร? ความนับถือ. @acdcjunior
limonik

1
XMLUnit.setIgnoreAttributeOrder (จริง); ไม่ทำงาน, ไม่เป็นผล. หากบางโหนดมีลำดับที่แตกต่างกันการเปรียบเทียบจะล้มเหลว
Bevor

[อัปเดต] โซลูชันนี้ใช้งานได้: stackoverflow.com/questions/33695041/…
Bevor

คุณตระหนักถึง "IgnoreAttributeOrder" หมายถึงเพิกเฉยคำสั่งแอตทริบิวต์และไม่สนใจคำสั่งโหนดใช่ไหม
acdcjunior

7

ขอบคุณฉันขยายสิ่งนี้ลองสิ่งนี้ ...

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
ค่อนข้างช้า แต่ต้องการทราบว่าส่วนของรหัสนี้มีจุดบกพร่อง: ใน diffNodes (), node2 ไม่ได้อ้างอิง - ลูปที่สองใช้ซ้ำ node1 อย่างไม่ถูกต้อง (ฉันแก้ไขโค้ดเพื่อแก้ไขปัญหานี้) นอกจากนี้ยังมีข้อ จำกัด 1 ข้อ: เนื่องจากวิธีการแมปลูกด์จะถูกใส่คีย์ต่างกันนี้ไม่รองรับกรณีที่ชื่อองค์ประกอบไม่ซ้ำกันเช่นองค์ประกอบที่มีองค์ประกอบลูกที่ทำซ้ำได้
aberrant80

7

อาคารทอมคำตอบ 's นี่เป็นตัวอย่างการใช้ v2 XMLUnit

มันใช้การพึ่งพา 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>

.. และนี่คือรหัสทดสอบ

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

เอกสารที่สรุปนี้คือhttps://github.com/xmlunit/xmlunit#comparing-two-documents


3

skaffman ดูเหมือนจะให้คำตอบที่ดี

อีกวิธีหนึ่งอาจจัดรูปแบบ XML โดยใช้ยูทิลิตีบรรทัด commmand เช่น xmlstarlet ( http://xmlstar.sourceforge.net/ ) แล้วจัดรูปแบบทั้งสตริงแล้วใช้ยูทิลิตี diff (ไลบรารี) เพื่อกระจายไฟล์เอาต์พุตที่ได้ ฉันไม่รู้ว่านี่เป็นวิธีแก้ปัญหาที่ดีหรือไม่เมื่อมีปัญหากับเนมสเปซ



2

ฉันใช้Altova DiffDogซึ่งมีตัวเลือกในการเปรียบเทียบไฟล์ XML แบบโครงสร้าง (ไม่สนใจข้อมูลสตริง)

ซึ่งหมายความว่า (หากทำเครื่องหมายที่ตัวเลือก 'ละเว้นข้อความ'):

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

และ

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

มีความเสมอภาคในแง่ที่ว่าพวกเขามีความเท่าเทียมกันทางโครงสร้าง สิ่งนี้มีประโยชน์ถ้าคุณมีไฟล์ตัวอย่างที่แตกต่างกันในข้อมูล แต่ไม่ใช่โครงสร้าง!


3
ลบอย่างเดียวคือมันไม่ฟรี (99 €สำหรับสิทธิ์ใช้งานแบบโปร) พร้อมการทดลอง 30 วัน
Pimin Konstantin Kefaloukos

2
ฉันพบเฉพาะยูทิลิตี้ ( altova.com/diffdog/diff-merge-tool.html ); ดีที่มีห้องสมุด
dma_k

1

สิ่งนี้จะเปรียบเทียบ XML สตริงเต็ม (จัดรูปแบบใหม่ระหว่างทาง) มันทำให้ง่ายต่อการทำงานกับ IDE (IntelliJ, Eclipse) ของคุณเพราะคุณเพียงแค่คลิกและเห็นความแตกต่างในไฟล์ 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);
    }
}

ฉันชอบสิ่งนี้กับ XmlUnit เพราะรหัสลูกค้า (รหัสทดสอบ) นั้นสะอาดกว่า


1
วิธีนี้ใช้ได้ดีในการทดสอบสองแบบที่ฉันทำตอนนี้ด้วย XML เดียวกันและ XML ที่แตกต่างกัน ด้วย IntelliJ ทำให้ความแตกต่างใน XML ที่เปรียบเทียบนั้นง่ายต่อการมองเห็น
Yngvar Kristiansen

1
อย่างไรก็ตามคุณจะต้องมีการพึ่งพานี้หากคุณใช้ Maven: <dependency> <groupId> org.apache.santuario </groupId> <artifactId> xmlsec </artifactId> <version> 2.0.6 </version> </ การพึ่งพา>
Yngvar Kristiansen

1

รหัสด้านล่างใช้งานได้สำหรับฉัน

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

1
บริบทใด ๆ การอ้างอิงห้องสมุด?
Ben

0

การใช้ JExamXML กับแอ็พพลิเคชัน 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

ฉันต้องการฟังก์ชั่นเดียวกับที่ร้องขอในคำถามหลัก เนื่องจากฉันไม่ได้รับอนุญาตให้ใช้ห้องสมุดบุคคลที่สามฉันได้สร้างโซลูชันของตัวเองโดยอ้างอิงจาก @Archimedes Trajano 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));
            }
        }
    }

}

มันเปรียบเทียบสองสตริง XML และดูแลการแมปเนมสเปซที่ไม่ตรงกันใด ๆ โดยการแปลให้เป็นค่าที่ไม่ซ้ำกันในทั้งสตริงอินพุต

สามารถปรับได้เช่นในกรณีของการแปลเนมสเปซ แต่สำหรับความต้องการของฉันทำงานได้


-2

เนื่องจากคุณพูดว่า "semantically สมมูล" ฉันถือว่าคุณหมายความว่าคุณต้องการทำมากกว่าแค่การยืนยันว่า xml outputs (string) เท่ากับและคุณต้องการอะไรที่คล้ายกัน

<foo> บางสิ่งที่นี่ </foo> </code>

และ

<foo> บางสิ่งที่นี่ </foo> </code>

อ่านเท่ากัน ในที่สุดมันก็จะสำคัญว่าคุณจะนิยาม "สิ่งที่เทียบเท่ากับความหมาย" ในสิ่งใดก็ตามที่คุณสร้างข้อความขึ้นมาใหม่ เพียงสร้างวัตถุนั้นจากข้อความและใช้เท่ากับที่กำหนดเอง () เพื่อกำหนดสิ่งที่คุณกำลังมองหา


4
ไม่ใช่คำตอบ แต่เป็นคำถาม
Kartoch
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.