1 Reply Latest reply: Jul 24, 2013 12:55 PM by 858567 RSS

    XMLUnit: Element and Attribute ordering problem

    928518
      I have a question regarding “Similar” and “Identical”. In the following example given on XMLUnit help page:
      <author>Dan Brown</author>
      <category></category>
      And
      <category></category>
      <author>Dan Brown</author>
      The output comes out to be:

      Similar? true
      Identical? false
      ***********************
      Expected sequence of child nodes ’5′ but was ’7′ – comparing at /books[1]/book[1]/author[1] to at /books[1]/book[1]/author[1]
      ***********************
      ***********************
      Expected sequence of child nodes ’7′ but was ’5′ – comparing at /books[1]/book[1]/category[1] to at /books[1]/book[1]/category[1]
      ***********************


      My question how can we “NOT” include in the output such non-identical information? My problem is that I have a long xml documents to compare. There are cases, where the differences are related to orderring and in addition to others.

      But when I get the total output, it gets kind of difficult to find the actual differences (non-orderring) related.

      I have to manually skip the non-important information (orderring differences) from the actual differences for example if anything is missing in the reference documents or have different content etc.

      Have said that, I read somewhere that such "orderring" problems can be solved with my own "custom DifferenceListener".

      So I did the following, (the whole class):
      import java.io.FileNotFoundException;
      import java.io.FileReader;
      import java.io.IOException;
      import java.io.StringWriter;
      import java.net.URL;
      import java.util.List;
      
      import org.w3c.dom.Node;
      import javax.xml.transform.OutputKeys;
      import javax.xml.transform.Transformer;
      import javax.xml.transform.TransformerException;
      import javax.xml.transform.TransformerFactory;
      import javax.xml.transform.dom.DOMSource;
      import javax.xml.transform.stream.StreamResult;
      
      import org.custommonkey.xmlunit.DetailedDiff;
      import org.custommonkey.xmlunit.Diff;
      import org.custommonkey.xmlunit.Difference;
      import org.custommonkey.xmlunit.DifferenceConstants;
      import org.custommonkey.xmlunit.DifferenceListener;
      import org.custommonkey.xmlunit.ElementNameAndAttributeQualifier;
      import org.custommonkey.xmlunit.ElementNameAndTextQualifier;
      import org.custommonkey.xmlunit.ElementNameQualifier;
      import org.custommonkey.xmlunit.MatchTracker;
      import org.custommonkey.xmlunit.NodeDetail;
      import org.custommonkey.xmlunit.XMLUnit;
      import org.custommonkey.xmlunit.examples.MultiLevelElementNameAndTextQualifier;
      import org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier;
      import org.xml.sax.SAXException;
      
      public class XMLComparator {
      
           public static void main(String[] args) {
                URL url1 = XMLComparator.class.getResource("reference.xml");
                URL url2 = XMLComparator.class.getResource("comparison.xml");
                FileReader fr1 = null;
                FileReader fr2 = null;
                try {
                     fr1 = new FileReader(url1.getPath());
                     fr2 = new FileReader(url2.getPath());
                } catch (FileNotFoundException e) {
                     e.printStackTrace();
                }
      
                XMLUnit.setIgnoreComments(Boolean.TRUE);
                XMLUnit.setIgnoreWhitespace(Boolean.TRUE);
                XMLUnit.setNormalizeWhitespace(Boolean.TRUE);
                XMLUnit.setIgnoreDiffBetweenTextAndCDATA(Boolean.TRUE);
                XMLUnit.setIgnoreAttributeOrder(Boolean.TRUE);
                
                XMLUnit.setCompareUnmatched(Boolean.FALSE); 
                
                
                try {
                     Diff diff = new Diff(fr1, fr2);
                                    
                     diff.overrideDifferenceListener(new DifferenceListener() {
                          
                          @Override
                          public void skippedComparison(Node arg0, Node arg1) {
                               // TODO Auto-generated method stub
                          }
                          
                          @Override
                           public int differenceFound(Difference diff) { 
                             if (diff.getId() == DifferenceConstants.CHILD_NODELIST_SEQUENCE_ID) 
                          {
                             return RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;  
                             }
                               
                             return RETURN_ACCEPT_DIFFERENCE;
                         }
                          
                          
                          
                     });
                                    
                     System.out.println(" Similar ? " + diff.similar());
                     System.out.println(" Identical ? " + diff.identical());
                     
                     
      
                     DetailedDiff detDiff = new DetailedDiff(diff);
      
                     detDiff.overrideMatchTracker(new MatchTrackerImpl());
                     detDiff.overrideElementQualifier(new ElementNameAndTextQualifier());
                     
                     
      
                     List differences = detDiff.getAllDifferences();
                     
      
                     for (Object object : differences) {
                          Difference difference = (Difference) object;
                          System.out.println("***********************");
                          System.out.println(difference);
      
                          System.out.println("***********************");
                     }
      
                } catch (SAXException e) {
                     e.printStackTrace();
                } catch (IOException e) {
                     e.printStackTrace();
                }
           }
      
      }
      
      class MatchTrackerImpl implements MatchTracker {
      
           public void matchFound(Difference difference) {
                if (difference != null) {
                     NodeDetail controlNode = difference.getControlNodeDetail();
                     NodeDetail testNode = difference.getTestNodeDetail();
      
                     String controlNodeValue = printNode(controlNode.getNode());
                     String testNodeValue = printNode(testNode.getNode());
      
                     if (controlNodeValue != null) {
                          // System.out.println("####################");
                          // System.out.println("Control Node: " + controlNodeValue);
                     }
                     if (testNodeValue != null) {
                          // System.out.println("Test Node: " + testNodeValue);
                          // System.out.println("####################");
                     }
                }
           }
      
           private static String printNode(Node node) {
                if (node != null && node.getNodeType() == Node.ELEMENT_NODE) {
                     StringWriter sw = new StringWriter();
                     try {
                          Transformer t = TransformerFactory.newInstance()
                                    .newTransformer();
                          t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
                          t.transform(new DOMSource(node), new StreamResult(sw));
                     } catch (TransformerException te) {
                          System.out.println("nodeToString Transformer Exception");
                     }
                     return sw.toString();
      
                }
                return null;
           }
      }
      reference.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <UsernameToken>
           <OtherSrvcName>EXCURSION_AND_TICKETS</OtherSrvcName>
           <OtherSrvcName>TRAVELGUIDE</OtherSrvcName>
      </UsernameToken>
      comparison.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <UsernameToken>
           <OtherSrvcName>TRAVELGUIDE</OtherSrvcName>
           <OtherSrvcName>EXCURSION_AND_TICKETS</OtherSrvcName>
      </UsernameToken>
      The output:

      Similar ? false
      Identical ? false


      This to some degree resolved my original problem, but my question is why Similar is false? Shouldn't it be 'true' ?

      Secondly, on my slightly changing the XMLs, the entire output then yielded the same original response, which i am not interested in.

      reference.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <UsernameToken>
           <OtherSrvcPref>
                <OtherSrvcName>EXCURSION_AND_TICKETS</OtherSrvcName>
           </OtherSrvcPref>
           <OtherSrvcPref>
                <OtherSrvcName>TRAVELGUIDE</OtherSrvcName>
           </OtherSrvcPref>
      </UsernameToken>
      comparision.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <UsernameToken>
           <OtherSrvcPref>
                <OtherSrvcName>TRAVELGUIDE</OtherSrvcName>
           </OtherSrvcPref>
           <OtherSrvcPref>
                <OtherSrvcName>EXCURSION_AND_TICKETS</OtherSrvcName>
           </OtherSrvcPref>
      </UsernameToken>
      Output:

      Similar ? false
      Identical ? false
      ***********************
      Expected presence of child node 'OtherSrvcName' but was 'null' - comparing <OtherSrvcName...> at /UsernameToken[1]/OtherSrvcPref[1]/OtherSrvcName[1] to at null
      ***********************
      ***********************
      Expected presence of child node 'null' but was 'OtherSrvcName' - comparing at null to <OtherSrvcName...> at /UsernameToken[1]/OtherSrvcPref[1]/OtherSrvcName[1]
      ***********************
      ***********************
      Expected presence of child node 'OtherSrvcName' but was 'null' - comparing <OtherSrvcName...> at /UsernameToken[1]/OtherSrvcPref[2]/OtherSrvcName[1] to at null
      ***********************
      ***********************
      Expected presence of child node 'null' but was 'OtherSrvcName' - comparing at null to <OtherSrvcName...> at /UsernameToken[1]/OtherSrvcPref[2]/OtherSrvcName[1]
      ***********************


      Now why am i getting the 'Expected presence...' messages in the output? Shouldn't it just produce the same output as in the previous case, i.e.

      Similar ? false
      Identical ? false



      I don't understand this difference in the behaviour of the output? Could someone please help me out here..

      Thanks.
        • 1. Re: XMLUnit: Element and Attribute ordering problem
          858567

          You need to tell XmlUnit how to identify pairs of nodes in the control and test XML. You do this by applying an ElementQualifier, e.g.

          diff.overrideElementQualifier(new ElementNameAndAttributeQualifier());

          This element qualifier will consider a control element to be comparable with a test element if the element name matches, and if the attributes match (same amount of attributes, same attribute names, same values of attributes). It will find differences in the text node or child nodes of this element.

          See also http://xmlunit.sourceforge.net/userguide/html/ar01s03.html#ElementQualifier

           

          In your case, you might want to use the RecursiveElementNameAndTextQualifier or write an own.

           

          Further, I recommend to unset this option to not receive strange matches.

          XmlUnit.setCompareUnmatched(false);

          cheers

          Leo