Search code examples
javaxml-parsingxmlunit-2

XML comparison using XMLunit not working when elements are reordered


I have two XMLs

<books><book language="English"><authors><author>Niklaus Wirth</author></authors></book><book language="English"><authors><author>Mark Twain</author></authors></book><book language="English"><authors><author>O.-J. Dahl</author></authors></book></books>


<books><book language="English"><authors><author>Niklaus Wirth</author></authors></book><book language="English"><authors><author>O.-J. Dahl</author></authors></book><book language="English"><authors><author>Mark Twain</author></authors></book></books>

The order of the last two <author> tags are different and they should be similar. This is the code

public static void compare() throws FileNotFoundException{
        String sourceXML=convertXMLtoString(source);
        String targetXML=convertXMLtoString(target);
        System.out.println(sourceXML);
        System.out.println(targetXML);
        Diff mydiff=DiffBuilder.compare(sourceXML)
        .withTest(targetXML)
        .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText))
        .checkForSimilar()
        //.withNodeMatcher()
        .build();
        Iterable<Difference> differences = mydiff.getDifferences();
        for(Difference d:differences){
            System.out.println(d.toString());
        }
    }

This is the ouput.

Expected child 'author' but was 'null' - comparing <author...> at /books[1]/book[2]/authors[1]/author[1] to <NULL> (DIFFERENT)
Expected child 'null' but was 'author' - comparing <NULL> to <author...> at /books[1]/book[2]/authors[1]/author[1] (DIFFERENT)
Expected child 'author' but was 'null' - comparing <author...> at /books[1]/book[3]/authors[1]/author[1] to <NULL> (DIFFERENT)
Expected child 'null' but was 'author' - comparing <NULL> to <author...> at /books[1]/book[3]/authors[1]/author[1] (DIFFERENT)

Can anyone please tell me how to ignore this?I thought using NameandText with Element selector should ignore the order. Thanks


Solution

  • Using byNameAndText you make sure you pick the correct author tags, but this is far too late as XMLUnit needs to select the correct book for your comparison to succeed. Once it has settled on which book element to compare it is never going to search for elements in a different subtree.

    I don't think author is what distinguishes the books in the end, but in absence of any other hints something like

    ElementSelectors.conditionalBuilder()
        .whenElementIsNamed("book").thenUse(ElementSelectors.byXPath("./authors/author", ElementSelectors.byNameAndText))
        .elseUse(ElementSelectors.byNameAndText)
        .build();
    

    should probably work.