Найкращий спосіб порівняння двох документів XML на Java


198

Я намагаюся написати автоматизований тест програми, яка в основному переводить користувальницький формат повідомлення в повідомлення XML і надсилає його з іншого кінця. У мене є гарний набір пар вхідних / вихідних повідомлень, тому все, що мені потрібно зробити, це надсилати вхідні повідомлення та слухати, щоб повідомлення XML виходило з іншого кінця.

Коли настає час порівняти фактичний вихід із очікуваним випуском, у мене виникають деякі проблеми. Перша моя думка полягала лише в тому, щоб порівняти рядки на очікуваних та фактичних повідомленнях. Це не дуже добре, тому що наведені нами приклади не завжди форматуються послідовно і часто є різні псевдоніми, які використовуються для простору імен XML (а іноді простори імен взагалі не використовуються.)

Я знаю, що можу проаналізувати обидва рядки, а потім пройти кожен елемент і порівняти їх самостійно, і це було б не надто складно, але я відчуваю, що є кращий спосіб або бібліотека, яку я міг би використовувати.

Тож, закипівши, питання:

З огляду на два рядки Java, які містять дійсний 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 в минулому, він був дуже хитрий з версіями API XML і не виявився надійним. Минув час, коли я викинув його для XOM, хоча, можливо, з тих пір він збіднів.
skaffman

63
Для початківців XMLUnit зауважте, що за замовчуванням myDiff.s подобни () поверне помилкове значення, якщо контрольні та тестові документи відрізняються відступами / новими рядками. Я очікував такої поведінки від myDiff.identical (), а не від myDiff.s подобни (). Включити XMLUnit.setIgnoreWhitespace (вірно); у вашому методі setUp, щоб змінити поведінку для всіх тестів у вашому тестовому класі або використовувати її в індивідуальному методі тестування, щоб змінити поведінку лише для цього тесту.
Тушковане

1
@Дякую, дякую за ваш коментар, тільки починаючи з XMLUnit і впевнений, що зіткнувся б з цією проблемою. +1
Jay

2
Якщо ви намагаєтеся це зробити з XMLUnit 2 на github, 2 версія - це повне перезапис, тому цей приклад - для XMLUnit 1 у SourceForge. Також на сторінці sourceforge зазначено, що "XMLUnit для Java 1.x як і раніше буде підтримуватися".
Інгвар Крістіансен

1
метод assrtXMLEqual від XMLAssert.java .
користувач2818782

36

Далі буде перевірено, чи документи рівні, використовуючи стандартні бібліотеки JDK.

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance ();
dbf.setNamespaceAware (вірно);
dbf.setCoalescing (вірно);
dbf.setIgnoringElementContentWhitespace (вірно);
dbf.setIgnoringComments (true);
DocumentBuilder db = dbf.newDocumentBuilder ();

Документ doc1 = db.parse (новий файл ("file1.xml"));
doc1.normalizeDocument ();

Документ doc2 = db.parse (новий файл ("file2.xml"));
doc2.normalizeDocument ();

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

normalize () є, щоб переконатися, що немає циклів (технічно їх не було б)

Вищевказаний код вимагає, щоб білі пробіли були однаковими в межах елементів, оскільки він зберігає та оцінює їх. Стандартний аналізатор XML, що постачається з Java, не дозволяє встановити функцію для надання канонічної версії або зрозуміти, xml:spaceчи це буде проблемою, тоді вам може знадобитися замінюючий аналізатор XML, такий як xerces або використовувати JDOM.


4
Це прекрасно працює для XML без просторів імен або з "нормалізованими" префіксами простору імен. Я сумніваюся, що це працює, якщо одна XML - <ns1: a xmlns: ns1 = "ns" />, а інша <ns2: a xmlns: ns2 = "ns" />
koppor

dbf.setIgnoringElementContentWhitespace (true) не має результату, я б очікував, що ім'я <root> </root> не дорівнює <root> ім'я </name> з цим рішенням (з двома пробілами), але XMLUnit дає рівний результат у цьому випадку (JDK8)
Miklos Krivan

Для мене він не ігнорує розриви рядків, що є проблемою.
Flyout91

setIgnoringElementContentWhitespace(false)
Архімед Траяно

28

Xom має утиліту Canonicalizer, яка перетворює ваші DOM в звичайну форму, яку ви можете потім упорядкувати та порівняти. Таким чином, незалежно від порушень пробілів або впорядкування атрибутів, ви можете отримувати регулярні передбачувані порівняння своїх документів.

Це особливо добре працює в IDE, які мають спеціальні візуальні порівняння струн, наприклад 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>

Це ідеально для людей, яким потрібно порівняти зі статичним методом.
Енді Б

Це ідеальна відповідь. Дякую .. Однак мені потрібно ігнорувати вузли, яких немає. Оскільки я не хочу бачити в результаті результат такий вихід: Очікувана наявність дочірнього вузла "null", але було ...... Як я можу це зробити? З повагою @acdcjunior
limonik

1
XMLUnit.setIgnoreAttributeOrder (вірно); не працює. Якщо деякі вузли мають інший порядок, порівняння не вдасться.
Бевор

[UPDATE] це рішення працює: stackoverflow.com/questions/33695041 / ...
бувігер

Ви розумієте, що "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

Спираючись на відповідь Тома , ось приклад використання XMLUnit v2.

Він використовує ці основні залежності

    <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

Скафман, здається, дає хорошу відповідь.

інший спосіб - це, ймовірно, відформатувати XML за допомогою утиліти командної лінії, наприклад xmlstarlet ( http://xmlstar.sourceforge.net/ ), а потім відформатувати обидва рядки, а потім використати будь-яку різну утиліту (бібліотеку) для розмежування отриманих вихідних файлів. Я не знаю, чи це хороше рішення, коли проблеми з просторами імен.



2

Я використовую Altova DiffDog, який має варіанти структурно порівняти XML-файли (ігноруючи рядкові дані).

Це означає, що (якщо ви перевіряєте опцію "ігнорувати текст"):

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

і

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

рівні в тому сенсі, що мають структурну рівність. Це зручно, якщо у вас є приклади файлів, які відрізняються між собою даними, але не структурою!


3
Єдиним мінусом є те, що він не є безкоштовним (99 € за професійну ліцензію) з 30-денним пробним періодом.
Пімін Костянтин Кефалукос

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 легко помітити.
Інгвар Крістіансен

1
До речі, ця залежність вам буде потрібна, якщо ви використовуєте Maven: <dependency> <groupId> org.apache.santuario </groupId> <artifactId> xmlsec </artifactId> <version> 2.0.6 </version> </ залежність>
Інгвар Крістіансен

1

Нижче код працює для мене

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

1
Будь-який контекст? Довідка про бібліотеку?
Бен

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.

Далі йде моє рішення.

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

Оскільки ви говорите "семантично еквівалентний", я вважаю, що ви маєте на увазі, що ви хочете зробити більше, ніж просто дослівно переконатися, що вихідні дані XML (рядкові) дорівнюють, і що ви хочете чогось подібного

<foo> деякі речі тут </foo> </code>

і

<foo> деякі речі тут </foo> </code>

читай як еквівалент. Зрештою, буде важливо, як ви визначаєте "семантично еквівалент" для будь-якого об'єкта, з якого ви відновлюєте повідомлення. Просто побудуйте цей об’єкт із повідомлень і використовуйте користувальницьку рівність (), щоб визначити, що шукаєте.


4
Не відповідь, а питання.
Картох
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.