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.or
inside of theDefaultNodeMatcher
, I used thevarargs
constructorThe difference between the two approaches is explained here.
This solved my primary issue, still there was a problem since the
DifferenceEvaluator
was outputting that document were different, due to this (look at the end of paragraph). Indeed, the document areSIMILAR
and 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 theDiffBuilder
with a specificDifferenceEvaluator
even if probably the best solution, as suggested by Stefan Bodewig, would be to
chain
my implementation withDifferenceListeners.Default
and drop the check of outcome.