first of all thank you for this wonderful library, it's really great.
I'm having a problem comparing elements in different order within my xml document. I've developed a custom ElementSelector to use with the NodeMatcher (later the code) but still it seems to check based on element order more than element content. Let me write an example
Control
<Parent>
<Person>
<FirstName>John</FirstName>
<LastName>Doe</LastName>
<Email>[email protected]</Email>
</Person>
<Person>
<FirstName>Mickey</FirstName>
<LastName>Mouse</LastName>
<Email>[email protected]</Email>
</Person>
<Person>
<FirstName>John</FirstName>
<LastName>Doe</LastName>
<Email />
</Person>
</Parent>
Test
<Parent>
<Person>
<FirstName>Mickey</FirstName>
<LastName>Mouse</LastName>
<Email>[email protected]</Email>
</Person>
<Person>
<FirstName>John</FirstName>
<LastName>Doe</LastName>
<Email>[email protected]</Email>
</Person>
<Person>
<FirstName>John</FirstName>
<LastName>Doe</LastName>
<Email />
</Person>
</Parent>
How I made the Diff
Diff diff = DiffBuilder.compare(refSource)
.withTest(testSource)
.checkForSimilar()
.ignoreWhitespace()
.normalizeWhitespace()
.withNodeMatcher(new DefaultNodeMatcher(selector))
.build();
How I created the ElementSelector selector
ElementSelector selector = ElementSelectors.conditionalBuilder()
.whenElementIsNamed("Person").thenUse(new PersonNodeMatcher())
.defaultTo(ElementSelectors.byNameAndText).build();
How is actually implemented the PersonNodeMatcher
public class PersonNodeMatcher extends BaseElementSelector {
@Override
protected boolean canBeCompared(Element control, Element test) {
String controlFirstName = control.getElementsByTagName("FirstName").item(0).getTextContent();
String controlLastName = control.getElementsByTagName("LastName").item(0).getTextContent();
Node controlEmailNode = control.getElementsByTagName("Email").item(0);
String controlEmail = null;
if ( controlEmailNode != null) {
controlEmail = controlEmailNode.getTextContent();
}
String testFirstName = test.getElementsByTagName("FirstName").item(0).getTextContent();
String testLastName = test.getElementsByTagName("LastName").item(0).getTextContent();
Node testEmailNode = test.getElementsByTagName("Email").item(0);
String testEmail = null;
if (testEmailNode != null) {
testEmail = testEmailNode.getTextContent();
}
return bothNullOrEqual(controlFirstName,testFirstName) &&
bothNullOrEqual(controlLastName,testLastName) &&
bothNullOrEqual(controlEmail,testEmail);
}
The routine is still checking the nodes in order, so they will never match. I thought that providing a node custom node matcher I would be able to check all the Element with the tagName provided.
Am I doing something wrong or simply is not possible?
[UPDATE] Using the alpha3 I had to do some modification to the code, specifically:
ElementSelector selector = ElementSelectors.conditionalBuilder()
.whenElementIsNamed("Person").thenUse(new PersonNodeMatcher()).build();
Diff diff = DiffBuilder.compare(refSource)
.withTest(testSource)
.checkForSimilar()
.ignoreWhitespace()
.normalizeWhitespace()
.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.or(selector,ElementSelectors.Default)))
.build();
Instead of using the
ElementSelectors.orinside of theDefaultNodeMatcher, I used thevarargsconstructorThe difference between the two approaches is explained here.
This solved my primary issue, still there was a problem since the
DifferenceEvaluatorwas outputting that document were different, due to this (look at the end of paragraph). Indeed, the document areSIMILARand notIDENTICAL, since the order of the inner elements is not equal. In order to prevent such an output from theDifferenceEvaluator, at the moment I've updated theDiffBuilderwith a specificDifferenceEvaluatoreven if probably the best solution, as suggested by Stefan Bodewig, would be to
chainmy implementation withDifferenceListeners.Defaultand drop the check of outcome.