41

I have an XML message like so:

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

I want to compare a message of this type produced by a method under test to an expected message, but I don't care about elementA. So, I'd like the above message to be considered equal to:

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

I'm using the latest version of XMLUnit.

I'm imagining that the answer involves creating a custom DifferenceListener; I just don't want to reinvent the wheel if there's something ready to use out there.

Suggestions that use a library other than XMLUnit are welcome.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Paul Morie
  • 15,528
  • 9
  • 52
  • 57

5 Answers5

39

I wound up implementing a DifferenceListener that takes a list of node names (with namespaces) to ignore textual differences for:

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

    }
}
Paul Morie
  • 15,528
  • 9
  • 52
  • 57
  • 14
    I'm surprised it's this complex - disappointing if xmlunit does not have something built in for ignoring specific elements? – bacar Jan 31 '12 at 17:14
  • This solution is quite old now. Apparently the new xmlunit programming model uses [ComparisonListener](http://www.xmlunit.org/api/java/2.4.0/org/xmlunit/diff/ComparisonListener.html), not DifferenceListener. – Cheeso Jul 25 '17 at 02:19
31

Things have changed a lot for XMLUnit since this question was answered.

You can now easily ignore a node when using a DiffBuilder:

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

If you then call documentDiff.hasDifferences() nodes added to filter will be ignored.

Jean-François Savard
  • 20,626
  • 7
  • 49
  • 76
9

I would use XSLT and the identity transform to filter out elements I want to ignore, and compare the results.

See XSL: how to copy a tree, but removing some nodes ? earlier on SO.

Community
  • 1
  • 1
lavinio
  • 23,931
  • 5
  • 55
  • 71
5

You can now try ${xmlunit.ignore} in XMLUnit 2.6.0 (add dependency xmlunit-placeholders). Sample code is as below.

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

Expected XML:

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

Actual XML:

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

Do notice that currently the ${xmlunit.ignore} only supports text node and attribute value ignorance, as can be seen from the unit tests.

Zheng Wang
  • 81
  • 1
  • 4
0

Lets make it simple, to ignore nodes irrespective of length of how many nodes you want to ignore or if you dont know how many number of nodes you want to ignore, follow these simple steps

This is just a XMLdiff method with two xml's as a string

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

add dependencies or jar from this link https://www.xmlunit.org/