Files
json/docs/mkdocs/docs/api/basic_json/diff.md
T
Niels LohmannandClaude Sonnet 5.5 c712df0637 docs: make the diff() and patch() documentation accurate; add tests (#5939)
* Throw out_of_range.411 for JSON Patch add into a null parent (#5917)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MKJf48vnGtTE25KscmjfaW
Signed-off-by: Niels Lohmann <niels.lohmann@gmail.com>

* docs: make the diff() and patch() documentation accurate; add tests

Document the exceptions to the diff round-trip invariant (NaN, discarded
values, number types), the path parameter, non-minimal patches, array and
object operation order, the ordered_json fallback, binary values in
serialized patches, the real complexity, duplicate member names in
operations, test on missing paths, and the exact out_of_range.403 message.
Add tests for these behaviors.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <niels.lohmann@gmail.com>
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-26 17:12:05 +01:00

4.7 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 or signs differ: diff(1, 1.0), diff(1u, 1) (unsigned and signed integer) and diff(0.0, -0.0) all return #!json []. The patched value is then the source and 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: #!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.