I have two XML files that I want to compare. I am using XMLUnit 2. But elements can be out of order (including sub element ordering) All three examples below need to be considered equivalent:
<Product>
<Property>
<Container value="1">Test 01</Container>
<Container value="3">Test 02</Container>
<Container value="5">Test 03</Container>
</Property>
<Property>
<Container value="2">Test A</Container>
<Container value="4">Test B</Container>
<Container value="6">Test C</Container>
</Property>
</Product>
<Product>
<Property>
<Container value="5">Test 03</Container>
<Container value="1">Test 01</Container>
<Container value="3">Test 02</Container>
</Property>
<Property>
<Container value="2">Test A</Container>
<Container value="4">Test B</Container>
<Container value="6">Test C</Container>
</Property>
<Product>
<Property>
<Container value="2">Test A</Container>
<Container value="4">Test B</Container>
<Container value="6">Test C</Container>
</Property>
<Property>
<Container value="5">Test 03</Container>
<Container value="1">Test 01</Container>
<Container value="3">Test 02</Container>
</Property>
</Product>
It seems like XMLUnit should be able to do this fairly easily but I don't know what I need to do to configure the test. I should add that nesting can get deeper where container has more elements under it that demonstrate the same issue.
---
POSSIBLE SOLUTION:
public class SubNodeEqualityElementSelector implements ElementSelector {
public SubNodeEqualityElementSelector() {
}
@Override
public boolean canBeCompared(Element controlElement, Element testElement) {
// test input nodes for equality first.
if (!ElementSelectors.byNameAndAllAttributes.canBeCompared(controlElement, testElement)) {
return false;
}
if (!ElementSelectors.byNameAndText.canBeCompared(controlElement, testElement)) {
return false;
}
// test children for equality. For each ctrl child, make sure that a matching element is found in the test set.
ArrayList<Element> ctrlChildren = getChildElements(controlElement);
ArrayList<Element> testChildren = getChildElements(testElement);
ArrayList<Element> ctrlChildrenResults = new ArrayList<Element>(ctrlChildren);
ArrayList<Element> testChildrenResults = new ArrayList<Element>(testChildren);
for (Element ctrlChild : ctrlChildren) {
for (Element testChild : testChildren) {
if (ElementSelectors.byNameAndAllAttributes.canBeCompared(ctrlChild, testChild) &&
ElementSelectors.byNameAndText.canBeCompared(ctrlChild, testChild)) {
ctrlChildrenResults.remove(ctrlChild);
testChildrenResults.remove(testChild);
}
}
}
return ctrlChildrenResults.size() == 0 && testChildrenResults.size() == 0;
}
private ArrayList<Element> getChildElements(Element elem) {
ArrayList<Element> retVal = new ArrayList<Element>();
NodeList childNodes = elem.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (node instanceof Element){
Element element = (Element) node;
retVal.add(element);
}
}
return retVal;
}
}
I tested the above class (SubNodeEqualityElementSelector) and it seems to work well!