Лучший способ сравнить 2 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 в прошлом, он был очень нервным с версиями XML API и не доказал свою надежность. Прошло уже много времени с тех пор, как я отказался от него для XOM, так что, возможно, с тех пор это стало лучше.
Скаффман

63
Обратите внимание, что для начинающих пользователей XMLUnit по умолчанию myDiff.simil () будет возвращать значение false, если контрольный и тестовый документы отличаются отступами / переводами строки. Я ожидал такого поведения от myDiff.identical (), а не от myDiff.s Similar (). Включить XMLUnit.setIgnoreWhitespace (true); в вашем методе setUp, чтобы изменить поведение для всех тестов в вашем классе тестов, или используйте его в отдельном методе тестов, чтобы изменить поведение только для этого теста.
Рагу

1
@ Спасибо за ваш комментарий, только начиная с XMLUnit, и я уверен, что столкнулся бы с этой проблемой. +1
Джей

2
В случае, если вы пытаетесь сделать это с XMLUnit 2 на github, версия 2 будет полностью переписана, поэтому этот пример для XMLUnit 1 на SourceForge. Кроме того, на странице sourceforge говорится: «XMLUnit для Java 1.x будет по-прежнему поддерживаться».
Ингвар Кристиансен

1
метод assertXMLEqual как из XMLAssert.java .
user2818782

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

Документ 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 (true) не имеет результата. Я ожидаю, что <root> name </ root> не равно <root> name </ name> с этим решением (дополнено двумя пробелами), но XMLUnit дает равный результат в этом случае (JDK8)
Миклос Криван

Для меня это не игнорирует разрывы строк, что является проблемой.
Flyout91

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

28

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

Это особенно хорошо работает в средах разработки, в которых есть специальные компараторы визуальных строк, например 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>

Это идеально подходит для людей, которые должны сравнивать статическим методом.
Энди Б,

Это идеальный ответ. Спасибо .. Однако мне нужно игнорировать узлы, которые не существуют. Так как я не хочу видеть в результате вывода такой вывод: ожидаемое присутствие дочернего узла "ноль", но был ...... Как я могу это сделать? С уважением. @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 (я исправил код, чтобы это исправить). Кроме того, у него есть одно ограничение: из-за того, что ключи дочерних карт имеют ключ, эта разница не поддерживает случай, когда имена элементов не являются уникальными, то есть элементы, содержащие повторяющиеся дочерние элементы.
aberrant80

7

Основываясь на ответе Тома , вот пример использования XMLUnit v2.

Он использует эти зависимости 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

Скаффман, кажется, дает хороший ответ.

Другой способ - это, вероятно, отформатировать XML с помощью утилиты командной строки, такой как 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-дневной пробной версией.
Пимин Константин Кефалукос

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 diff легко заметить различия в сравниваемом XML.
Ингвар Кристиансен

1
Кстати, эта зависимость понадобится вам, если вы используете Maven: <зависимость> <groupId> org.apache.santuario </ groupId> <artifactId> xmlsec </ artifactId> <версия> 2.0.6 </ version> </ 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>

читать как эквивалент. В конечном счете, будет иметь значение, как вы определяете «семантически эквивалентный» для любого объекта, из которого вы восстанавливаете сообщение. Просто создайте этот объект из сообщений и используйте пользовательский equals (), чтобы определить, что вы ищете.


4
Не ответ, а вопрос.
Kartoch
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.