XMLUnit compare XML not working where parent node contains multiple child nodes of same name and attributes list but different attribute values

Rishi Singhal :

I am using XMLUnit to compare two XMLs to detect the updates. My pom is as :

<dependency>
    <groupId>xmlunit</groupId>
    <artifactId>xmlunit</artifactId>
    <version>1.6</version>
</dependency>

For most of the scenarios, XMLUnit is working fine except few where the given differences are wrong or unexpected. Lets take first the positive scenario where the XMLUnit is working correct :

Case-1:

XML-Original:

<ClassHours>                          
    <Hours close="11:10" day="27" classname="sec-1" open="17:20" noOfStudent="23"/>
    <Hours close="11:10" day="28" classname="sec-2" open="17:20" noOfStudent="43"/>
    <Hours close="11:10" day="21" classname="sec-3" open="17:20" noOfStudent="12"/>
    <Hours close="11:10" day="1" classname="sec-4" open="17:20" noOfStudent="54"/>
    <Hours close="11:10" day="25" classname="sec-5" open="17:20" noOfStudent="22"/>
    <Hours close="11:10" day="1" classname="sec-6" open="17:20" noOfStudent="10"/>      s
</ClassHours>

XML-Updated:

<ClassHours>                          
    <Hours close="18:00" day="27" classname="sec-1" open="10:00" noOfStudent="23"/>
    <Hours close="18:00" day="28" classname="sec-2" open="10:00" noOfStudent="43"/>
    <Hours close="18:00" day="21" classname="sec-3" open="10:00" noOfStudent="12"/>
    <Hours close="18:00" day="1" classname="sec-4" open="10:00" noOfStudent="54"/>
    <Hours close="18:00" day="25" classname="sec-5" open="10:00" noOfStudent="22"/>
    <Hours close="18:00" day="1" classname="sec-6" open="10:00" noOfStudent="10"/>      s
</ClassHours>

as you can notice, the parent node contains multiple child nodes . For all the child nodes, the name and attribute is same and the only difference is in Open and Close attributes value. In this case the output is :

2019-12-24 19:53:28,093  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:53:28,093  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:53:28,093  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:53:28,093  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:53:28,093  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:53:28,095  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:53:28,096  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:53:28,096  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:53:28,096  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:53:28,096  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:53:28,097  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:53:28,097  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]

Case-2:

XML-Original:

<ClassHours>                          
    <Hours close="11:10" day="27" classname="sec-1" open="17:20" noOfStudent="23"/>
    <Hours close="11:10" day="28" classname="sec-2" open="17:20" noOfStudent="43"/>
    <Hours close="11:10" day="21" classname="sec-3" open="17:20" noOfStudent="12"/>
    <Hours close="11:10" day="1" classname="sec-4" open="17:20" noOfStudent="54"/>
    <Hours close="11:10" day="25" classname="sec-5" open="17:20" noOfStudent="22"/>
    <Hours close="11:10" day="1" classname="sec-6" open="17:20" noOfStudent="10"/>      s
</ClassHours>

XML-Updated:

<ClassHours>    
    <Hours close="18:00" day="28" classname="sec-2" open="10:00" noOfStudent="43"/>
    <Hours close="18:00" day="21" classname="sec-3" open="10:00" noOfStudent="12"/>
    <Hours close="18:00" day="27" classname="sec-1" open="10:00" noOfStudent="23"/>
    <Hours close="18:00" day="1" classname="sec-4" open="10:00" noOfStudent="54"/>
    <Hours close="18:00" day="25" classname="sec-5" open="10:00" noOfStudent="22"/>
    <Hours close="18:00" day="1" classname="sec-6" open="10:00" noOfStudent="10"/>      s
</ClassHours>

Here, again for all the child nodes, the name and attribute is same and the difference is in Open and Close attributes value. This time the sequence of the nodes is also updated as classname sec-3 row is shifted after sec-2. In this case the output is :

2019-12-24 19:54:31,737  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [classname], Before value : [sec-1], After value : [sec-2]]
2019-12-24 19:54:31,738  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:54:31,738  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [day], Before value : [27], After value : [28]]
2019-12-24 19:54:31,738  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [noOfStudent], Before value : [23], After value : [43]]
2019-12-24 19:54:31,738  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:54:31,740  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [classname], Before value : [sec-2], After value : [sec-3]]
2019-12-24 19:54:31,740  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:54:31,740  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [day], Before value : [28], After value : [21]]
2019-12-24 19:54:31,741  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [noOfStudent], Before value : [43], After value : [12]]
2019-12-24 19:54:31,741  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:54:31,741  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [classname], Before value : [sec-3], After value : [sec-1]]
2019-12-24 19:54:31,741  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:54:31,741  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [day], Before value : [21], After value : [27]]
2019-12-24 19:54:31,741  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [noOfStudent], Before value : [12], After value : [23]]
2019-12-24 19:54:31,742  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:54:31,742  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:54:31,742  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:54:31,742  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:54:31,742  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]
2019-12-24 19:54:31,742  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [close], Before value : [11:10], After value : [18:00]]
2019-12-24 19:54:31,742  INFO [main] (XMLDiffMain.java:107) -  Node [/ClassHours/Hours, node attribute : [open], Before value : [17:20], After value : [10:00]]

here the output is wrong as the difference is in only in values, but XMLUnit is considering the sequence of the nodes as well and giving such output.

My code is :

    LOGGER.debug("Comparing Actual and Expected XMLs");
    XMLUnit.setIgnoreWhitespace(true);
    XMLUnit.setIgnoreAttributeOrder(true);
    XMLUnit.setIgnoreComments(true);
    DetailedDiff diff = new DetailedDiff(XMLUnit.compareXML(expectedXML, actualXML));
    diff.overrideElementQualifier(new ElementNameAndAttributeQualifier());

    return diff.getAllDifferences();

Can somebody tell me how I can fix this? I have also tried adding

diff.overrideDifferenceListener(new IgnoreTextAndAttributeValuesDifferenceListener());
diff.overrideElementQualifier(new RecursiveElementNameAndTextQualifier());

and still getting same results. Also I cannot control the sequence of the XML nodes as it is coming from some other external system. I need to get the fix to ignore sequence while comparing the nodes attributes.

Also, I already mentioned that this is the only case where XMLUnit is not working. For all other cases it is working as expected.

Stefan Bodewig :

You are using the no-arg constructor of ElementNameAndAttributeQualifier which means two elements are eligible to being compared if their names are the same and all their attributes have the same values. This is not true for any pair of elements in your example as the close attributes are all different. So there are no matches at all.

In XMLUnit 1.x the default behavior is to match elements that haven't got a matching partner to match them in document order with those without partners from the test document. So in effect you are comparing elements in order.

One thing you can do is make the ElementNameAndAttributeQualifier more specific by listing the attributes that you expect to keep the same values in the constructor. You probably also want to set XMLUnit.setCompareUnmatched to false so you won't trip over the bad default - or better, yet, switch to XMLUnit 2.x which unlike 1.x is actively maintained and will never compare unmatched nodes to each other.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How to convert attribute-centric XML to element-centric XML, persist parent node into each child node, and preserve nodes of the same name?

How to Unmarshaller XML by JAXB where parent and child node as same name

xml nodes() in tsql - matching parent nodes with child node attributes

XML - where node has same name but different values

Comparing similar xml files with XmlUnit with unordered tags (same tag name with different attributes)

XML data extraction where not all parent nodes contain the child node

Web API XML Deserialization : Node with multiple child nodes with same tag name

Replace attribute of XML parent node with values from child node

Insert multiple child nodes with same structure into the given parent node

Different child nodes in the same XML

Need the values of multiple sibling nodes of the same name: XML::LibXML

How can i compare the values of the attributes on XML and only echo the attribute that contains the string i want with PHP?

How to deserialize child object into list of parent (ex, List<Parent>) based on values of xml nodes?

Populate Attribute and values to all parent nodes of the XML file from 4th parent node

Web.config -- Setting multiple attributes in different nodes based on a value in another node attribute value

Sort XML nodes by child node, then sort different child nodes

XSL - Create Multiple Tables According to The Different Values Of An XML Child Node

R XML - combining parent and child nodes(w same name) into data frame

Collecting XML child nodes from multiple parent nodes

Transform multiple elements with same attribute name to a new element with those attribute values as child-elements

Delete multiple xml nodes with same name (but not all)

Merge XML nodes sharing the same name with "_LIST" in the node name and also at root level

How to add multiple child nodes with the same tag to an existing node in an XML document

Remove parent node in xml if child node contains a particular string

Extract attributes with same name for all nodes in an xml file using R

How to call parent class attributes in child class if they are of same name?

How to loop through all same name parent and child nodes

Compare subnodes in XMLUnit 2 - Expected child 'node2' but was 'null'

XSLT generate table out of child nodes in same parent node