Files
json/docs/mkdocs/docs/api/basic_json/diff.md
T
Niels Lohmann eb8f675bc9 docs: explain signed zero in the diff() round-trip exceptions (#5944)
Spell out that numbers comparing equal produce no operation even if one is
zero and the other negative zero, in diff.md and features/json_patch.md.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-27 17:16:08 +01:00

5.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 #!cpp 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: diff emits a replace operation for them. A NaN in the patch is serialized as #!json null, so a patch that was dumped and parsed again would set #!json null.
  • Numbers that compare equal produce no operation, even if their types differ or if one is zero and the other is negative zero: diff(1, 1.0) (integer and floating-point), diff(1u, 1) (unsigned and signed integer) and diff(0.0, -0.0) (positive and negative zero) all return #!json []. The patched value is then the source and keeps its number type and sign.

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: #!cpp 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, and replace operations are generated.
  • The patch is correct, but not guaranteed to be minimal. For instance, diff([1,2,3], [0,1,2,3]) yields three replace operations and one add operation 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 add operations on the path /- (appended in order), and elements that were removed are removed with remove operations from the highest index down to the lowest, so that the remaining indices stay valid.
  • For objects, the operations for the members of source come first (replace, remove, or the operations for nested values, in the iteration order of source), followed by add operations for the members that only target has.
  • For ordered_json, objects with the same keys in a different order are different. As a patch cannot reorder members, diff removes all keys of the source object and adds them again in the order of the target.
  • If source and target differ as a whole (e.g., different types), the patch consists of a single replace operation for the root of the value, i.e., with the path "" (or the given path prefix).
  • The value members of the patch hold copies of values of target. A binary value has no JSON representation: when a patch that contains one is serialized, it becomes an object such as #!json {"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.
 
```cpp
--8<-- "examples/diff.cpp"
```

Output:

```json
--8<-- "examples/diff.output"
```

See also

Version history

  • Added in version 2.0.0.