Any chance to get better nested diff information?
With the following code (excluded the usings for simplicity)
var node1 = JsonNode.Parse("{\"foo\":[ {\"bar1\": \"res1\"} ]}");
var node2 = JsonNode.Parse("{\"foo\":[ {\"bar1\": \"res2\"} ]}");
var x = JsonDiffPatcher.Diff(node1, node2, new JsonPatchDeltaFormatter());
Console.WriteLine(x);
I'm getting follwing:
[
{
"op": "remove",
"path": "/foo/0"
},
{
"op": "add",
"path": "/foo/0",
"value": {
"bar1": "res2"
}
}
]
I would like to get something like:
[
{
"op": "replace",
"path": "/foo/0/bar1"
"value": "res2"
}
]
I've looked into DefaultFormatter and it seems that JsonDiffDelta has already 2 change entries: one for remove and one for add.
What's the best method to check arrays recursively (the way I want)? Is there some kind of flag or would I need to override FormatArray somehow?
Thanks!
Seems like I can use following JsonDiffOptions to control array-comparison:
- ArrayObjectItemKeyFinder
- ArrayObjectItemMatchByPosition and maybe
- PropertyFilter
Looks promising, the following works as expected (I've changed bar1 to ID since this would be my real-world example, if for any reason the ID is missing I'm falling back with ArrayObjectItemMatchByPosition=true):
var node1 = JsonNode.Parse("{\"foo\":[ {\"ID\": \"res1\", \"bar2\": \"res3\"} ]}");
var node2 = JsonNode.Parse("{\"foo\":[ {\"ID\": \"res1\", \"bar2\": \"res4\"} ]}");
var opt = new JsonDiffOptions
{
ArrayObjectItemKeyFinder = ArrayObjectItemKeyFinder,
ArrayObjectItemMatchByPosition = true
};
object? ArrayObjectItemKeyFinder(JsonNode? node, int index)
{
if (node is JsonObject obj && obj.TryGetPropertyValue("ID", out var value))
{
return value?.GetValue<string>() ?? "";
}
return null;
}
var x = JsonDiffPatcher.Diff(node1, node2, new JsonPatchDeltaFormatter(), opt);
Console.WriteLine(x);
Did I miss out any documentation about this?
Yes works this way:
- One suggestion: JsonPatchDeltaFormatter should have overridable strings like PropertyNameOperation and JsonPatchDeltaFormatter.PropertyPathScope should be protected instead of private. I had a small (project-specific) change and needed to copy more than I should.
What's the best method to check arrays recursively (the way I want)?
I think you've pretty much found the way.
If you have a look at the JsonDiffOptions, there are 3 ways you can use:
ArrayItemMatcherwhich deals with the diff contextArrayObjectItemKeyFinderwhich finds the key/id of an object or arrayArrayObjectItemMatchByPositionwhich indicates whether to compare two objects or arrays by their position
By default if the two objects are not deeply equal to each other, then they are considered totally not equal and therefore the remove/add (arguably update) result. To forcibly get a diff of array items, you need to implement an "object comparer" to compare them if they are not deeply equal, similar to an object hash function.
There probably should be some Wiki documentation about array diffs.
JsonPatchDeltaFormatter.PropertyPathScope should be protected instead of private
I agree. The reason for it being a private is because the implementation of the class is actually a combination of partial JSON Pointer and a pointer scope at the moment. The JSON Pointer implementation should ideally be a public type. I did not want to expose this type until it is properly refactored otherwise it might be hard to change the implementation.