I'm trying to unit test some methods that produce xml. I have an expected xml string and the result string and after googling and searching stack overflow, I found XMLUnit. However it doesn't seem to handle one particular case where repeating elements in different orders contain elements that are in different orders. For example:
Expected XML:
<graph>
<parent>
<foo>David</foo>
<bar>Rosalyn</bar>
</parent>
<parent>
<bar>Alexander</bar>
<foo>Linda</foo>
</parent>
</graph>
Actual XML:
<graph>
<parent>
<foo>Linda</foo>
<bar>Alexander</bar>
</parent>
<parent>
<bar>Rosalyn</bar>
<foo>David</foo>
</parent>
</graph>
You can see the parent node repeats and it's contents can be in any order. These two xml pieces should be equivalent but nothing from the stackoverflow examples I've seen does the trick with this. (Best way to compare 2 XML documents in Java) (How can I compare two similar XML files in XMLUnit)
I've resorted to creating Documents from the xml strings, stepping through each expected parent node and then comparing it to each actual parent node to see if one of them is equivalent.
It seems to me like a lot of reinventing of the wheel for something that should be a relatively common comparison. XMLUnit seems to do a lot, perhaps I've missed something but from what I can tell, it falls short in this particular case.
Is there an easier/better way to do this?
My Solution:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setCoalescing(true);
dbf.setIgnoringElementContentWhitespace(true);
dbf.setIgnoringComments(true);
DocumentBuilder db = dbf.newDocumentBuilder();
// parse and normalize expected xml
Document expectedXMLDoc = db.parse(new ByteArrayInputStream(resultXML.getBytes()));
expectedXMLDoc.normalizeDocument();
// parse and normalize actual xml
Document actualXMLDoc = db.parse(new ByteArrayInputStream(actual.getXml().getBytes()));
actualXMLDoc.normalizeDocument();
// expected and actual parent nodes
NodeList expectedParentNodes = expectedXMLDoc.getLastChild().getChildNodes();
NodeList actualParentNodes = actualXMLDoc.getLastChild().getChildNodes();
// assert same amount of nodes in actual and expected
assertEquals("actual XML does not have expected amount of Parent nodes", expectedParentNodes.getLength(), actualParentNodes.getLength());
// loop through expected parent nodes
for(int i=0; i < expectedParentNodes.getLength(); i++) {
// create doc from node
Node expectedParentNode = expectedParentNodes.item(i);
Document expectedParentDoc = db.newDocument();
Node importedExpectedNode = expectedParentDoc.importNode(expectedParentNode, true);
expectedParentDoc.appendChild(importedExpectedNode);
boolean hasSimilar = false;
StringBuilder messages = new StringBuilder();
// for each expected parent, find a similar parent
for(int j=0; j < actualParentNodes.getLength(); j++) {
// create doc from node
Node actualParentNode = actualParentNodes.item(j);
Document actualParentDoc = db.newDocument();
Node importedActualNode = actualParentDoc.importNode(actualParentNode, true);
actualParentDoc.appendChild(importedActualNode);
// XMLUnit Diff
Diff diff = new Diff(expectedParentDoc, actualParentDoc);
messages.append(diff.toString());
boolean similar = diff.similar();
if(similar) {
hasSimilar = true;
}
}
// assert it found a similar parent node
assertTrue("expected and actual XML nodes are not equivalent " + messages, hasSimilar);
}