summaryrefslogtreecommitdiff
path: root/docs/handbook/json4cpp/json-pointer.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/handbook/json4cpp/json-pointer.md')
-rw-r--r--docs/handbook/json4cpp/json-pointer.md361
1 files changed, 361 insertions, 0 deletions
diff --git a/docs/handbook/json4cpp/json-pointer.md b/docs/handbook/json4cpp/json-pointer.md
new file mode 100644
index 0000000000..0fb0283fe9
--- /dev/null
+++ b/docs/handbook/json4cpp/json-pointer.md
@@ -0,0 +1,361 @@
+# json4cpp — JSON Pointer (RFC 6901)
+
+## Overview
+
+JSON Pointer (RFC 6901) provides a string syntax for identifying a specific
+value within a JSON document. The library implements this as the
+`json_pointer` class template, defined in
+`include/nlohmann/detail/json_pointer.hpp`.
+
+```cpp
+template<typename RefStringType>
+class json_pointer
+{
+ friend class basic_json;
+
+ std::vector<string_t> reference_tokens; // parsed path segments
+};
+```
+
+The default alias is:
+
+```cpp
+using json_pointer = json_pointer<std::string>;
+```
+
+## Syntax
+
+A JSON Pointer is a string of zero or more tokens separated by `/`:
+
+```
+"" → whole document
+"/foo" → key "foo" in root object
+"/foo/0" → first element of array at key "foo"
+"/a~1b" → key "a/b" (escaped /)
+"/m~0n" → key "m~n" (escaped ~)
+```
+
+### Escape Sequences
+
+| Sequence | Represents |
+|---|---|
+| `~0` | `~` |
+| `~1` | `/` |
+
+Escaping is applied **before** splitting (per RFC 6901 §3).
+
+## Construction
+
+### From String
+
+```cpp
+json_pointer(const string_t& s = "");
+```
+
+Parses the pointer string and populates `reference_tokens`. Throws
+`parse_error::107` if the string is not a valid JSON Pointer (e.g.,
+a non-empty string that doesn't start with `/`):
+
+```cpp
+json_pointer ptr("/foo/bar/0");
+
+// Invalid:
+// json_pointer ptr("foo"); // parse_error::107 — must start with /
+```
+
+### User-Defined Literal
+
+```cpp
+using namespace nlohmann::literals;
+
+auto ptr = "/server/host"_json_pointer;
+```
+
+## Accessing Values
+
+### `operator[]` with Pointer
+
+```cpp
+json j = {{"server", {{"host", "localhost"}, {"port", 8080}}}};
+
+j["/server/host"_json_pointer]; // "localhost"
+j["/server/port"_json_pointer]; // 8080
+j["/server"_json_pointer]; // {"host":"localhost","port":8080}
+```
+
+### `at()` with Pointer
+
+```cpp
+json j = {{"a", {{"b", 42}}}};
+
+j.at("/a/b"_json_pointer); // 42
+j.at("/a/missing"_json_pointer); // throws out_of_range::403
+```
+
+### `value()` with Pointer
+
+```cpp
+json j = {{"timeout", 30}};
+
+j.value("/timeout"_json_pointer, 60); // 30
+j.value("/retries"_json_pointer, 3); // 3 (key not found, returns default)
+```
+
+### `contains()` with Pointer
+
+```cpp
+json j = {{"a", {{"b", 42}}}};
+
+j.contains("/a/b"_json_pointer); // true
+j.contains("/a/c"_json_pointer); // false
+j.contains("/x"_json_pointer); // false
+```
+
+## Pointer Manipulation
+
+### `to_string()`
+
+```cpp
+string_t to_string() const;
+```
+
+Reconstructs the pointer string with proper escaping:
+
+```cpp
+json_pointer ptr("/a~1b/0");
+ptr.to_string(); // "/a~1b/0"
+```
+
+### `operator string_t()`
+
+Implicit conversion to string (same as `to_string()`).
+
+### `operator/=` — Append Token
+
+```cpp
+json_pointer& operator/=(const string_t& token);
+json_pointer& operator/=(std::size_t array_index);
+```
+
+Appends a reference token:
+
+```cpp
+json_pointer ptr("/a");
+ptr /= "b"; // "/a/b"
+ptr /= 0; // "/a/b/0"
+```
+
+### `operator/` — Concatenate
+
+```cpp
+friend json_pointer operator/(const json_pointer& lhs, const string_t& token);
+friend json_pointer operator/(const json_pointer& lhs, std::size_t array_index);
+friend json_pointer operator/(const json_pointer& lhs, const json_pointer& rhs);
+```
+
+```cpp
+auto ptr = "/a"_json_pointer / "b" / 0; // "/a/b/0"
+auto combined = "/a"_json_pointer / "/b/c"_json_pointer; // "/a/b/c"
+```
+
+### `parent_pointer()`
+
+```cpp
+json_pointer parent_pointer() const;
+```
+
+Returns the parent pointer (all tokens except the last):
+
+```cpp
+auto ptr = "/a/b/c"_json_pointer;
+ptr.parent_pointer().to_string(); // "/a/b"
+
+auto root = ""_json_pointer;
+root.parent_pointer().to_string(); // "" (root's parent is root)
+```
+
+### `back()`
+
+```cpp
+const string_t& back() const;
+```
+
+Returns the last reference token:
+
+```cpp
+auto ptr = "/a/b/c"_json_pointer;
+ptr.back(); // "c"
+```
+
+Throws `out_of_range::405` if the pointer is empty (root).
+
+### `push_back()`
+
+```cpp
+void push_back(const string_t& token);
+void push_back(string_t&& token);
+```
+
+Appends a token:
+
+```cpp
+json_pointer ptr;
+ptr.push_back("a");
+ptr.push_back("b");
+ptr.to_string(); // "/a/b"
+```
+
+### `pop_back()`
+
+```cpp
+void pop_back();
+```
+
+Removes the last token:
+
+```cpp
+auto ptr = "/a/b/c"_json_pointer;
+ptr.pop_back();
+ptr.to_string(); // "/a/b"
+```
+
+Throws `out_of_range::405` if the pointer is empty.
+
+### `empty()`
+
+```cpp
+bool empty() const noexcept;
+```
+
+Returns `true` if the pointer has no reference tokens (i.e., it refers to
+the whole document):
+
+```cpp
+json_pointer("").empty(); // true (root pointer)
+json_pointer("/a").empty(); // false
+```
+
+## Array Indexing
+
+JSON Pointer uses string tokens for array indices. The token `"0"` refers
+to the first element, `"1"` to the second, etc.:
+
+```cpp
+json j = {"a", "b", "c"};
+
+j["/0"_json_pointer]; // "a"
+j["/1"_json_pointer]; // "b"
+j["/2"_json_pointer]; // "c"
+```
+
+### The `-` Token
+
+The special token `-` refers to the "past-the-end" position in an array.
+It can be used with `operator[]` to **append** to an array:
+
+```cpp
+json j = {1, 2, 3};
+j["/-"_json_pointer] = 4;
+// j is now [1, 2, 3, 4]
+```
+
+Using `-` with `at()` throws `out_of_range::402` since there's no element
+at that position.
+
+## `flatten()` and `unflatten()`
+
+### `flatten()`
+
+```cpp
+basic_json flatten() const;
+```
+
+Converts a nested JSON value into a flat object where each key is a JSON
+Pointer and each value is a primitive:
+
+```cpp
+json j = {
+ {"name", "alice"},
+ {"address", {
+ {"city", "wonderland"},
+ {"zip", "12345"}
+ }},
+ {"scores", {90, 85, 92}}
+};
+
+json flat = j.flatten();
+// {
+// "/name": "alice",
+// "/address/city": "wonderland",
+// "/address/zip": "12345",
+// "/scores/0": 90,
+// "/scores/1": 85,
+// "/scores/2": 92
+// }
+```
+
+### `unflatten()`
+
+```cpp
+basic_json unflatten() const;
+```
+
+The inverse of `flatten()`. Reconstructs a nested structure from a flat
+pointer-keyed object:
+
+```cpp
+json flat = {
+ {"/a/b", 1},
+ {"/a/c", 2},
+ {"/d", 3}
+};
+
+json nested = flat.unflatten();
+// {"a": {"b": 1, "c": 2}, "d": 3}
+```
+
+Throws `type_error::314` if a value is not primitive, or
+`type_error::315` if values at a path conflict (e.g., both
+`/a` and `/a/b` have values).
+
+### Roundtrip
+
+```cpp
+json j = /* any JSON value */;
+assert(j == j.flatten().unflatten());
+```
+
+Note: `unflatten()` cannot reconstruct arrays from flattened form since
+numeric keys (`/0`, `/1`) become object keys. The result will have
+object-typed containers where the original had arrays.
+
+## Internal Implementation
+
+### Token Resolution
+
+The `get_checked()` and `get_unchecked()` methods resolve a pointer
+against a JSON value by walking through the reference tokens:
+
+```cpp
+// Simplified logic
+BasicJsonType* ptr = &value;
+for (const auto& token : reference_tokens) {
+ if (ptr->is_object()) {
+ ptr = &ptr->at(token);
+ } else if (ptr->is_array()) {
+ ptr = &ptr->at(std::stoi(token));
+ }
+}
+return *ptr;
+```
+
+### Error IDs
+
+| ID | Condition |
+|---|---|
+| `parse_error::107` | Invalid pointer syntax |
+| `out_of_range::401` | Array index out of range |
+| `out_of_range::402` | Array index `-` used with `at()` |
+| `out_of_range::403` | Key not found in object |
+| `out_of_range::404` | Unresolved reference token |
+| `out_of_range::405` | `back()` / `pop_back()` on empty pointer |