A code search of client code found many hand-written versions of functionality the library already has: recursive object merges (update(j, true) since 3.10.5), dotted-path getters (value() and contains() with a JSON Pointer), get_or helpers (value() throws for a member that is present but null), and adl_serializer specializations for std::optional (supported since 3.12.0). - modifying_values.md: describe both modes of update(), add a defaults + user settings recipe, and stop recommending Merge Patch for recursive merges. - merge_patch.md: note that null deletes keys, so a merge patch is not a general deep merge; link update(). - default_value.md: add "Nested values" (value/contains with a JSON Pointer, building a pointer from a dotted path with operator/=) and a warning that null and mistyped members are not missing. - value.md: note that a null member is converted, not replaced by the default. - json_pointer.md: link value/contains/at with JSON Pointers. - arbitrary_types.md: note that std::optional needs no serializer. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
5.0 KiB
JSON Pointer
Introduction
The library supports JSON Pointer (RFC 6901) as an alternative means to address structured values. A JSON Pointer is a string that identifies a specific value within a JSON document.
Consider the following JSON document
{
"array": ["A", "B", "C"],
"nested": {
"one": 1,
"two": 2,
"three": [true, false]
}
}
Then every value inside the JSON document can be identified as follows:
| JSON Pointer | JSON value |
|---|---|
| `` | #!json {"array":["A","B","C"],"nested":{"one":1,"two":2,"three":[true,false]}} |
/array |
#!json ["A","B","C"] |
/array/0 |
#!json A |
/array/1 |
#!json B |
/array/2 |
#!json C |
/nested |
#!json {"one":1,"two":2,"three":[true,false]} |
/nested/one |
#!json 1 |
/nested/two |
#!json 2 |
/nested/three |
#!json [true,false] |
/nested/three/0 |
#!json true |
/nested/three/1 |
#!json false |
Note / does not identify the root (i.e., the whole document), but an object entry with empty key "". See
RFC 6901 for more information.
JSON Pointer creation
JSON Pointers can be created from a string:
json::json_pointer p("/nested/one");
Furthermore, a user-defined string literal can be used to achieve the same result:
auto p = "/nested/one"_json_pointer;
The escaping rules of RFC 6901 are implemented. See the constructor documentation for more information.
Value access
JSON Pointers can be used in the at, operator[],
and value functions just like object keys or array indices.
// the JSON value from above
auto j = json::parse(R"({
"array": ["A", "B", "C"],
"nested": {
"one": 1,
"two": 2,
"three": [true, false]
}
})");
// access values
auto val = j[""_json_pointer]; // {"array":["A","B","C"],...}
auto val1 = j["/nested/one"_json_pointer]; // 1
auto val2 = j.at(json::json_pointer("/nested/three/1")); // false
auto val3 = j.value(json::json_pointer("/nested/four"), 0); // 0
To read a value with a fallback, use value with a JSON Pointer; to test for existence,
use contains. Neither needs intermediate checks, see
Nested values.
!!! note "Creating intermediate levels that don't exist"
See the [`operator[]` notes](../api/basic_json/operator%5B%5D.md#return-value) for how array vs. object is
decided when a pointer creates intermediate levels that don't exist yet.
Flatten / unflatten
The library implements a function flatten to convert any JSON document into a JSON
object where each key is a JSON Pointer and each value is a primitive JSON value (i.e., a string, boolean, number, or
null).
// the JSON value from above
auto j = json::parse(R"({
"array": ["A", "B", "C"],
"nested": {
"one": 1,
"two": 2,
"three": [true, false]
}
})");
// create flattened value
auto j_flat = j.flatten();
The resulting value j_flat is:
{
"/array/0": "A",
"/array/1": "B",
"/array/2": "C",
"/nested/one": 1,
"/nested/two": 2,
"/nested/three/0": true,
"/nested/three/1": false
}
The reverse function, unflatten recreates the original value.
auto j_original = j_flat.unflatten();
See also
- Class
json_pointer - Functions
value,contains, andataccept JSON Pointers; see Nested values - Function
flatten - Function
unflatten - JSON Patch - paths inside a patch are JSON Pointers
- JSON Merge Patch - an alternative patch format that does not use JSON Pointer