简体   繁体   中英

Compare XML ignore child order

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM