0

I have googled for this and I know there are like 10 other questions like this but I can't seem to get it to work..

I want to compare 2 xml strings and only get the differences in spelling errors or stuff like that, while ignoring child order. This is my code atm:

    public void xmlCompare() {

    try {
        // First XML-read
        InputStream is = new FileInputStream("xmlTestCorrect.xml");
        String xmlText = IOUtils.toString(is);

        // Second XML-read
        InputStream is2 = new FileInputStream("xmlTestFalse.xml");
        String xmlText2 = IOUtils.toString(is2);

        Diff diff = DiffBuilder.compare(Input.fromString(xmlText)).withTest(Input.fromString(xmlText2))
                .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byName)).ignoreWhitespace()
                .ignoreComments().checkForSimilar().build();

        System.out.println(diff.hasDifferences());
        System.out.println(diff.getDifferences());

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

}

And my result....

 Expected text value 'commons-io' but was 'org.json'
 Expected text value 'commons-io' but was 'json'

etc.. I have just switched around some dependencies in the xmlTestFalse.xml file (also added some spelling errors which successfully shows). And the switched dependencies are still noticed. Why?? I tried doing something like this since I have the same version of xmlunit: like this

Community
  • 1
  • 1
BananaBackend
  • 95
  • 1
  • 1
  • 13

1 Answers1

0

You need to ask yourself "what identifies the XML trees that should be compared to each others" - and then explain it to XMLUnit :-)

Please have a look at https://github.com/xmlunit/user-guide/wiki/SelectingNodes

You don't show the XML that you are trying to compare so I'm guessing it is something like a Maven POM.

Let's assume you want to have

<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
</dependency>
<dependency>
  <groupId>org.json</groupId>
  <artifactId>json</artifactId>
</dependency>

and

<dependency>
  <groupId>org.json</groupId>
  <artifactId>json</artifactId>
</dependency>
<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
</dependency>

as "similar" results.

What is important to realize here is that you need to pick the correct dependency elements. If you tried to match the correct groupId elements, that would be too late. Once XMLUnit has settled on a dependency element, there only is a single groupId element inside that subtree.

You've told XMLUnit to match the nodes by their element name. This means the dependency elements are matched in document order, which is not what you want. You probably want something like "match on the element name and the text value of the child element named artifactId".

For the rest of your POM a selector like this would be useless, though. Most other elements won't have an artifactId child at all. This is where conditional selectors come in to play. You need to replace ElementSelectors.byName with something "a bit more complex". This

ElementSelectors.conditionalBuilder()
   .whenElementIsNamed("dependency")
   .thenUse(ElementSelectors.byXPath("./artifactId",
                                     ElementSelectors.byNameAndText))
   .elseUse(ElementSelectors.byName)
   .build()

should work for dependency and all "simple" cases of XML elements. If there are more complex cases you'll need to add more conditions.

Stefan Bodewig
  • 3,260
  • 15
  • 22
  • Yes I figured this was the problem since I tried with less complex xml documents and it worked. I will try your solution. Thank you for answering! – BananaBackend Jul 01 '16 at 08:24
  • I tried this and it will probably work. The problem is that I need to compare xml files with ~ 300 rows, and the elements are sometimes very deep (up to 3 layers). It will be very hard to write it manually for all cases. Is there a simpler way to do this? Maybe compare small parts of the document (node for node) or something? – BananaBackend Jul 01 '16 at 14:21
  • If there are no simpler rules that doing it for the whole document won't become any simpler. `DifferenceEngine` works at the node level, so it is certainly possible to compare subtrees. – Stefan Bodewig Jul 01 '16 at 17:34
  • Hi @Stefan Bodewig, I followed your idea, but as I compare two xml files where child nodes get matched by a conditionalBuilder, I think I loose the information that some node is missing, since it can't be compared with another -> thus no differences. Do you get what I mean? Can I fix it somehow? – Rafał May 15 '20 at 14:30
  • Sorry I just saw the comment right now. No you should still see `CHILD_LOOKUP` differences even with a conditional `ElementSelector` as these are created by the difference engine for each node that has not been matched at all. – Stefan Bodewig Jun 02 '20 at 15:09