Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Comparing nodes with checkForSimilar and checkForIdentical #160

Closed
michailangelo opened this issue Jul 4, 2019 · 20 comments
Closed

Comparing nodes with checkForSimilar and checkForIdentical #160

michailangelo opened this issue Jul 4, 2019 · 20 comments
Labels

Comments

@michailangelo
Copy link

Hello again,

Let's say I have these strings:
String xml1 ="<persons><person><Id>1</Id><name><firstName>George</firstName><lastName>White</lastName></name></person><person><Id>2</Id><name><firstName>John</firstName><lastName>Black</lastName></name></person></persons>";

String xml2 ="<persons><person><Id>2</Id><name><firstName>John</firstName><lastName>Black</lastName></name></person><person><name><firstName>George</firstName><lastName>White</lastName></name><Id>1</Id></person></persons>";

I don't mind about the order of 'person' elements but I do mind about the order of the child nodes of 'person' element like the 'name' element that comes before the 'Id' element in the xml2 string.

I figured I would use this:

.withNodeMatcher(new DefaultNodeMatcher(conditionalBuilder()
                    .whenElementIsNamed("person").thenUse(byXPath("./Id", byNameAndText))
                    .elseUse(byNameAndText).build()))
                    .withDifferenceEvaluator(DifferenceEvaluators.chain(
                       DifferenceEvaluators.Default,            
DifferenceEvaluators.upgradeDifferencesToDifferent(ComparisonType.CHILD_NODELIST_SEQUENCE) ))
.checkForSimilar()
.build();

but it just overrides the difference outcome of comparison of 'person' nodes not its children.

What am I missing here?

@bodewig
Copy link
Member

bodewig commented Jul 4, 2019

I'm not sure I understand what you see and what you'd like to see. Without running code the behavior I would expect from your configuration is you get a "different" result because the order of person elements is not the expected order.

If you still want to ignore the difference of order of the persons you need to provide DifferenceEvaluator that is a bit more advanced than upgradeDifferencesToDifferent - and you will have to write that yourself.

From your description it seems you are not getting CHILD_NODELIST_SEQUENCE differences for the children of persons, right? Not any at all or just not DIFFERENT ones?

@michailangelo
Copy link
Author

I would like to ignore the order of 'Person' elements but I dont want to ignore the order of its child nodes.

@bodewig
Copy link
Member

bodewig commented Jul 4, 2019

and with the change above you get differences for both or just the persons?

@michailangelo
Copy link
Author

michailangelo commented Jul 4, 2019

This is what I get:
[Expected child nodelist sequence '0' but was '1' - comparing <person...> at /persons[1]/person[1] to <person...> at /persons[1]/person[2] (DIFFERENT), Expected child nodelist sequence '0' but was '1' - comparing <Id...> at /persons[1]/person[1]/Id[1] to <Id...> at /persons[1]/person[2]/Id[1] (DIFFERENT), Expected child nodelist sequence '1' but was '0' - comparing <name...> at /persons[1]/person[1]/name[1] to <name...> at /persons[1]/person[2]/name[1] (DIFFERENT), Expected child nodelist sequence '1' but was '0' - comparing <person...> at /persons[1]/person[2] to <person...> at /persons[1]/person[1] (DIFFERENT)]

I think that means I get differences for persons (which I dont want) and none for its children (which I would like to catch).

@bodewig
Copy link
Member

bodewig commented Jul 4, 2019

To me it looks as if you now get all the differences for the children of person that you expected.

Expected child nodelist sequence '0' but was '1' - comparing <Id...> at /persons[1]/person[1]/Id[1] to <Id...> at /persons[1]/person[2]/Id[1] (DIFFERENT)

@bodewig
Copy link
Member

bodewig commented Jul 4, 2019

If you want to keep the differences for person elements as similar you'll have to provide a more sophisticated DifferenceEvaluator.

Very raw something like

public ComparisonResult evaluate(Comparison comparison, ComparisonResult outcome) {
    if (comparison.getType() == ComparisonType.CHILD_NODELIST_SEQUENCE
       && ("person".equals(comparison.getControlDetals().getTarget().getParentNode().getLocalName())
          || "person".equals(comparison.getControlDetals().getTarget().getParentNode().getNodeName()))) {
        return ComparisonResult.DIFFERENT;
    }
    return outcome;
}

The || is there to get the raw name depending on whether the node is namespaced or not.

The idea is to only upgrade the differences if the parent of the compared nodes is a person element.

Oh, and you'd still need to chain it behind DifferenceEvaluators.Default.

@michailangelo
Copy link
Author

How can this be?

I changed my String xmls to these:

   ` String xml1 ="<persons><person><Id>1</Id><name><firstName>George</firstName><lastName>White</lastName></name></person><person><Id>2</Id><name><firstName>John</firstName><lastName>Black</lastName></name></person></persons>";`

  `  String xml2 ="<persons><person><Id>2</Id><name><firstName>John</firstName><lastName>Black</lastName></name></person><person><Id>1</Id><name><firstName>George</firstName><lastName>White</lastName></name></person></persons>";`

I use this again:

.withNodeMatcher(new DefaultNodeMatcher(conditionalBuilder()
                    .whenElementIsNamed("person").thenUse(byXPath("./Id", byNameAndText))
                    .elseUse(byNameAndText).build()))
                    .withDifferenceEvaluator(DifferenceEvaluators.chain(
                       DifferenceEvaluators.Default,            
DifferenceEvaluators.upgradeDifferencesToDifferent(ComparisonType.CHILD_NODELIST_SEQUENCE) ))
.checkForSimilar()
.build();

This is what I get:

[Expected child nodelist sequence '0' but was '1' - comparing <person...> at /persons[1]/person[1] to <person...> at /persons[1]/person[2] (DIFFERENT), Expected child nodelist sequence '1' but was '0' - comparing <person...> at /persons[1]/person[2] to <person...> at /persons[1]/person[1] (DIFFERENT)]

The order in person's children is the same in both xmls so I would expect to find no differences at all.

@bodewig
Copy link
Member

bodewig commented Jul 4, 2019

your person elements are still swapped, this is what the differences say.

@michailangelo
Copy link
Author

So I guess this snippet catches both person's and its children differences.

How can I make it to catch only its children ?

@bodewig
Copy link
Member

bodewig commented Jul 4, 2019

see my example code above. DifferenceEvaluators.upgradeDifferencesToDifferent works globally, if you need something more targeted you have to write it yourself. Right now I don't see how create a more general API that would allow special cases like yours to be expressed.

@michailangelo
Copy link
Author

michailangelo commented Jul 4, 2019

So If I get this correctly, the idea is to implement a custom differenceEvaluator and then use it like this:

.withDifferenceEvaluator(DifferenceEvaluators.chain( CustomDifferenceEvaluator,
                       DifferenceEvaluators.Default,            
DifferenceEvaluators.upgradeDifferencesToDifferent(ComparisonType.CHILD_NODELIST_SEQUENCE) ))
.checkForSimilar()

EDIT:
Am I correct to assume this will ignore person's order but not its children?

@bodewig
Copy link
Member

bodewig commented Jul 4, 2019

You should place your CustomDifferenceEvaluator at the end or the upgradeDifferencesToDifferent will overrule it again.

Whether or not the setup ignores person's order but not its children depends on your CustomDifferenceEvaluator ;-)

@bodewig
Copy link
Member

bodewig commented Jul 4, 2019

sorry for editing the last post three times. This is what I meant "You should place your CustomDifferenceEvaluator at the end or the upgradeDifferencesToDifferent will overrule it again."

@bodewig
Copy link
Member

bodewig commented Jul 4, 2019

my example from above would replace upgradeDifferencesToDifferent.

By default you'd get SIMILAR differences for swapped nodes and only upgrade those that affect children of person.

In you setup you'd upgrade all differences for swapped nodes and then use CustomDifferenceEvaluator to downgrade all except those that apply to children of parent. This looks a bit more complex to me.

@michailangelo
Copy link
Author

I get it now. I can't thank you enough. :)

On to implement the customDifferenceEvaluator and I will report back :)

@bodewig
Copy link
Member

bodewig commented Jul 4, 2019

🤞

@michailangelo
Copy link
Author

So I implemented the customDifferenceEvaluator as in your example above but It doesnt spot the diffs about person's children order.

`    String xml1 ="<persons><person><Id>1</Id><name><firstName>George</firstName><lastName>White</lastName></name></person><person><Id>2</Id><name><firstName>John</firstName><lastName>Black</lastName></name></person></persons>";`

    `String xml2 ="<persons><person><Id>2</Id><name><firstName>John</firstName><lastName>Black</lastName></name></person><person><name><firstName>George</firstName><lastName>White</lastName></name><Id>1</Id></person></persons>";`
.withDifferenceEvaluator(DifferenceEvaluators.chain(
                        new IgnoreOrderEvaluator(),
                        DifferenceEvaluators.Default

                ))
                .checkForSimilar()

public ComparisonResult evaluate(Comparison comparison, ComparisonResult outcome) {
        if (outcome == ComparisonResult.EQUAL) return outcome;
        if (comparison.getType() == ComparisonType.CHILD_NODELIST_SEQUENCE
                && ("person".equals(comparison.getControlDetails().getTarget().getParentNode().getLocalName())
                || "person".equals(comparison.getControlDetails().getTarget().getParentNode().getNodeName()))) {
            return ComparisonResult.DIFFERENT;
        }
        return outcome;
    }

It doesnt find any diff at all.

@bodewig
Copy link
Member

bodewig commented Jul 4, 2019

First of all, put your evaluator after Default or Default downgrades the differences again.

When you say "doesnt find any diff at all" does that mean "no differences at all" or "no differences that are DIFFERENT but some that are SIMILAR"?

@michailangelo
Copy link
Author

Oh silly me, now it does find the person's children diffs and ignores the persons order.

Once again you have been of great help good sir.

@bodewig
Copy link
Member

bodewig commented Jul 4, 2019

you're welcome.

@bodewig bodewig closed this as completed Jul 4, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants