Как игнорировать определенные элементы при сравнении XML?

У меня есть сообщение XML, например, так:

<root>
  <elementA>something</elementA>
  <elementB>something else</elementB>
  <elementC>yet another thing</elementC>
</root>

Я хочу сравнить сообщение этого типа, созданное тестируемым методом, с ожидаемым сообщением, но меня не волнует elementA, Итак, я хотел бы, чтобы вышеуказанное сообщение считалось равным:

<root>
  <elementA>something different</elementA>
  <elementB>something else</elementB>
  <elementC>yet another thing</elementC>
</root>

Я использую последнюю версию XMLUnit.

Я представляю, что ответ включает в себя создание пользовательских DifferenceListener; Я просто не хочу изобретать велосипед, если есть что-то готовое для использования.

Предложения, которые используют библиотеку, отличную от XMLUnit, приветствуются.

6 ответов

Решение

С момента ответа на этот вопрос многое изменилось для XMLUnit.

Теперь вы можете легко игнорировать узел при использовании DiffBuilder:

final Diff documentDiff = DiffBuilder
            .compare(expectedSource)
            .withTest(actualSource)
            .withNodeFilter(node -> !node.getNodeName().equals(someName))
            .build();

Если вы тогда позвоните documentDiff.hasDifferences() узлы, добавленные в фильтр, будут игнорироваться.

Я завел реализацию DifferenceListener это берет список имен узлов (с пространствами имен), чтобы игнорировать текстовые различия для:

public class IgnoreNamedElementsDifferenceListener implements DifferenceListener {
    private Set<String> blackList = new HashSet<String>();

    public IgnoreNamedElementsDifferenceListener(String ... elementNames) {
        for (String name : elementNames) {
            blackList.add(name);
        }
    }

    public int differenceFound(Difference difference) {
        if (difference.getId() == DifferenceConstants.TEXT_VALUE_ID) {
            if (blackList.contains(difference.getControlNodeDetail().getNode().getParentNode().getNodeName())) {
                return DifferenceListener.RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
            }
        }

        return DifferenceListener.RETURN_ACCEPT_DIFFERENCE;
    }

    public void skippedComparison(Node node, Node node1) {

    }
}

Я бы использовал XSLT и преобразование идентичности, чтобы отфильтровать элементы, которые я хочу игнорировать, и сравнить результаты.

Смотрите XSL: как скопировать дерево, но удалив некоторые узлы? ранее ТАК.

Теперь вы можете попробовать ${xmlunit.ignore} в XMLUnit 2.6.0 (добавить зависимость xmlunit-placeholder). Пример кода, как показано ниже.

Diff diff = DiffBuilder
    .compare(expectedXML)
    .withTest(actualXML)
    .withDifferenceEvaluator(new PlaceholderDifferenceEvaluator())
    .build();

Ожидаемый XML:

<root>
  <elementA>${xmlunit.ignore}</elementA>
  <elementB>something else</elementB>
  <elementC>yet another thing</elementC>
</root>

Фактический XML:

<root>
  <elementA>anything</elementA>
  <elementB>something else</elementB>
  <elementC>yet another thing</elementC>
</root>

Обратите внимание, что в настоящее время ${xmlunit.ignore} поддерживает только незнание текстовых узлов и значений атрибутов, как это видно из модульных тестов.

Давайте упростим игнорирование узлов независимо от длины того, сколько узлов вы хотите игнорировать, или если вы не знаете, сколько узлов вы хотите игнорировать , выполните следующие простые шаги.

Это просто метод XMLdiff с двумя xml в виде строки

      public static void XMLdiff(String XML1, String XML2){
               
 //nodes you wanted to ignore
        String[] ignoreNodes = {"nodeX", "nodeY", "nodeZ"};
      
//testnode(node,ignoreNodes) is handled below for finding and ignoring multiple nodes
        final Diff documentDiff = DiffBuilder.compare(XML1)
                                  .withTest(XML2)
                                  .withNodeFilter(node->testnode(node,ignoreNodes))
                                  .build();
}

private static boolean testnode(Node node, String[] name) {

        for (int i = 0; i < name.length; i++) {

            if (node.getNodeName().toString().equals(name[i])) {
                return false;
            }
            if (name.length == 0) {
                break;
            }
        }
        return true;
    }

добавить зависимости или jar по этой ссылке https://www.xmlunit.org/

public class IgnoreNamedElementsDifferenceListener implements DifferenceListener {
    private Set<String> blackList = new HashSet<String>();

    public IgnoreNamedElementsDifferenceListener(String ... elementNames) {
        for (String name : elementNames) {
            blackList.add(name);
        }
    }

    public int differenceFound(Difference difference) {
        if (difference.getId() == DifferenceConstants.TEXT_VALUE_ID) {
            if (blackList.contains(difference.getControlNodeDetail().getNode().getParentNode().getNodeName())) {
                return DifferenceListener.RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
            }
        }

        return DifferenceListener.RETURN_ACCEPT_DIFFERENCE;
    }

    public void skippedComparison(Node node, Node node1) {

    }
}

Как вызвать эту собственную реализацию для моего метода, чтобы увидеть различия после того, как конкретный узел игнорируется для сравнения.

Другие вопросы по тегам