Reputation: 311
I have 2 XML. I have been using XMLUnit for comparing the 2 xml strings. The problem is I am not able to ignore the order in which elements occur. I tried overriding ElementQualifier as well as DifferenceListener but that didn't help for this scenario.
Control XML
<xs:complexType>
<xs:anotation>
<xs:description>
<Description>Country</Description>
</xs:description>
</xs:anotation>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:complexType>
Test XML
<xs:complexType>
<xs:anotation>
<xs:description>
<Description>Country</Description>
</xs:description>
</xs:anotation>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
</xs:sequence>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="street" type="xs:string"/>
</xs:sequence>
</xs:complexType>
Note that in Test XML another sequence is added and last element(country) of 1st sequence is removed.
XMLUnit complains about not having the element named city
which is there in second sequence. Its taking the elements in Order. I tried Overriding ELementNameAndAttributeQualifier but didnt produced the desired result.Moreover, overriding RecursiveElemenNameAndTextQualifier didnt help either. The reason RecursiveElemenNameAndTextQualifier doesn't work because theres is no match for the 1st sequence. How would I approach and make sure
public boolean qualifyForComparison(Element element, Element element1)
{
// should return true only when **element 1** has all elements of **element**
}
Upvotes: 2
Views: 817
Reputation:
This is really a bit more complex than "ignore element order", isn't it? :-)
ElementNameAndAttributeQualifier
would be fine for the xs:element
elements, but your real problem is making XMLUnit pick the correct xs:sequence
elements. I really recommend you use XMLUnit 2.x as it's conditional element selector builder is something you'll need and replicating that in XMLUnit 1.x is a bit of a pain.
If your custom element selector did what your comments say, then you wouldn't select the xs:sequence
elements you want to compare at all. The "test" sequence didn't contain the "street" xs:element
and this the ElementNameQualifier
would return false
.
I'm not really sure what the exact logic you want would have to look like. What you describe in you comment would be something like (using XMLUnit 2.x, untested)
public boolean canBeCompared(Element e1, Element e2) {
NodeList e1Children = e1.getChildNodes();
NodeList e2Children = e2.getChildNodes();
Iterable<Map.Entry<Node, Node>> matches =
new DefaultNodeMatcher(ElementSelectors.byNameAndAllAttributes)
.match(new IterableNodeList(e1Children), new IterableNodeList(e2Children));
for (Map.Entry<Node, Node> m : matches) {
if (m.getKey() == null // test child with no matching control child
|| m.getValue() == null // control child with no matching test child
) {
return false;
}
}
return true;
}
There is no builtin way to do it, you really need to work against the DOM on your own.
Finally you'd use something like
ElementSelectors.conditionalBuilder()
.whenElementIsNamed(new QName("sequence", XMLConstants.W3C_XML_SCHEMA_NS_URI))
.thenUse(the element selector built above)
.elseUse(ElementSelectors.byNameAndAllAttributes)
.build();
when feeding the difference engine.
Upvotes: 1