6.0 KiB
nlohmann::basic_json::diff
static basic_json diff(const basic_json& source,
const basic_json& target,
const string_t& path = "");
Creates a JSON Patch so that value source can be changed into the value target by calling patch function.
For two JSON values source and target, the following code yields true:
source.patch(diff(source, target)) == target;
The equality holds up to operator==, so it has the following exceptions:
- A value that is not equal to itself cannot round-trip. This applies to
NaN(also nested in an array or object) and to discarded values:diffemits areplaceoperation for them. ANaNin the patch is serialized asnull, so a patch that was dumped and parsed again would setnull. - Numbers that compare equal produce no operation, even if their types or signs differ:
diff(1, 1.0),diff(1u, 1)(unsigned and signed integer) anddiff(0.0, -0.0)all return[]. The patched value is then thesourceand keeps its number type.
Parameters
source (in) : JSON value to compare from
target (in) : JSON value to compare against
path (in) : a prefix that is put verbatim in front of the path member of every operation (default: "", which addresses the root of the value). The prefix is neither escaped nor validated: diff(1, 2, "abc") yields an operation with the path abc, which is not a valid JSON Pointer. Use it with a valid JSON Pointer such as /root and escape ~ and / in its reference tokens (see JSON Pointer).
Return value
a JSON patch to convert the source to target
Exception safety
Strong guarantee: source and target are never modified.
Complexity
Linear in the total number of values (including nested ones) in source and target, times the cost of a key-based object operation (looking up a key in an object): logarithmic for json, and linear for ordered_json (see ordered_map complexity). For ordered_json, diffing two objects with n and m members therefore takes O((n+m)²) when their keys do not line up (e.g., a key was added or the keys are in a different order). The size of the patch is proportional to the number of operations times the length of their paths, so a small change deep inside a value yields a long path.
Notes
- Currently, only
remove,add, andreplaceoperations are generated. - The patch is correct, but not guaranteed to be minimal. For instance,
diff([1,2,3], [0,1,2,3])yields threereplaceoperations and oneaddoperation instead of a single insertion. - Differences between two arrays are reported index by index. Elements that were added at the end of the array are added with
addoperations on the path/-(appended in order), and elements that were removed are removed withremoveoperations from the highest index down to the lowest, so that the remaining indices stay valid. - For objects, the operations for the members of
sourcecome first (replace,remove, or the operations for nested values, in the iteration order ofsource), followed byaddoperations for the members that onlytargethas. - For
ordered_json, objects with the same keys in a different order are different. As a patch cannot reorder members,diffremoves all keys of thesourceobject and adds them again in the order of thetarget. - If
sourceandtargetdiffer as a whole (e.g., different types), the patch consists of a singlereplaceoperation for the root of the value, i.e., with thepath""(or the givenpathprefix). - The
valuemembers of the patch hold copies of values oftarget. A binary value has no JSON representation: when a patch that contains one is serialized, it becomes an object such as{"bytes":[1,3],"subtype":null}, so a parsed patch no longer holds a binary value (and would set that object instead).
Examples
Example
The following code shows how a JSON patch is created as a diff for two JSON values.
#include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp>
using nlohmann::json;
using namespace nlohmann::literals;
int main()
{
// the source document
json source = R"(
{
"baz": "qux",
"foo": "bar"
}
)"_json;
// the target document
json target = R"(
{
"baz": "boo",
"hello": [
"world"
]
}
)"_json;
// create the patch
json patch = json::diff(source, target);
// roundtrip
json patched_source = source.patch(patch);
// output patch and roundtrip result
std::cout << std::setw(4) << patch << "\n\n"
<< std::setw(4) << patched_source << '\n';
}
Output:
[
{
"op": "replace",
"path": "/baz",
"value": "boo"
},
{
"op": "remove",
"path": "/foo"
},
{
"op": "add",
"path": "/hello",
"value": [
"world"
]
}
]
{
"baz": "boo",
"hello": [
"world"
]
}
See also
- RFC 6902 (JSON Patch)
- patch applies a JSON Patch
- patch_inplace applies a JSON Patch in place
- merge_patch applies a JSON Merge Patch
- merge_diff creates a diff as a JSON Merge Patch
Version history
- Added in version 2.0.0.