* Document the contract of object keys passed to json_sax::key and key callbacks Describe what the name passed to json_sax::key and to a parser callback for parse_event_t::key holds when parsing JSON text: escapes are decoded to UTF-8, different spellings of a name yield identical strings, the name is validated before the call (invalid escapes or UTF-8 give a parse error and no key event), no normalization or case conversion is applied, the event precedes the ':' check, and duplicate names are reported once per occurrence. Also note that sax_parse passes binary-format keys unchanged. See discussion #5955. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Add a test for the object key contract and correct the BON8 note Pin the guarantees documented for json_sax::key and the key event of parser callbacks: decoded names, validation before delivery, delivery before the colon, one event per repeated name, and the binary formats. BON8 rejects ill-formed UTF-8 in a name even with sax_parse, so the note no longer lists it with the formats that pass bytes through. See discussion #5955. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Fix the GCC build of the object key contract test GCC 11 in C++11 mode rejects a default argument on a lambda parameter (-Wc++14-extensions) and ignores a static_cast<void> on the warn_unused_result of parse(). Pass the input format explicitly and bind the parse result to a variable. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Add version history for the object key contract Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me>
6.3 KiB
nlohmann::basic_json::parser_callback_t
template<typename BasicJsonType>
using parser_callback_t =
std::function<bool(int depth, parse_event_t event, BasicJsonType& parsed)>;
With a parser callback function, the result of parsing a JSON text can be influenced. When passed to
parse, it is called on certain events (passed as parse_event_t via parameter
event) with a set recursion depth depth and context JSON value parsed. The return value of the callback function
is a boolean indicating whether the element that emitted the callback shall be kept or not.
We distinguish six scenarios (determined by the event type) in which the callback function can be called. The following
table describes the values of the parameters depth, event, and parsed.
parameter event |
description | parameter depth |
parameter parsed |
|---|---|---|---|
parse_event_t::object_start |
the parser read { and started to process a JSON object |
depth of the parent of the JSON object | a JSON value with type discarded |
parse_event_t::key |
the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key |
parse_event_t::object_end |
the parser read } and finished processing a JSON object |
depth of the parent of the JSON object | the parsed JSON object |
parse_event_t::array_start |
the parser read [ and started to process a JSON array |
depth of the parent of the JSON array | a JSON value with type discarded |
parse_event_t::array_end |
the parser read ] and finished processing a JSON array |
depth of the parent of the JSON array | the parsed JSON array |
parse_event_t::value |
the parser finished reading a JSON value | depth of the value | the parsed JSON value |
Parse events for a small JSON text: each coloured dot marks the position at which the parser calls the callback, and the legend on the right names the event per colour.
Discarding a value (i.e., returning #!cpp false) has different effects depending on the context in which function was
called:
- Discarded values in structured types are skipped. That is, the parser will behave as if the discarded value was never read. This holds for every value type and for both kinds of parent: a discarded element is removed from the surrounding array, and a discarded member is removed from the surrounding object together with its key.
- Arrays and objects can be discarded either at their
parse_event_t::array_start/parse_event_t::object_startevent or at theirparse_event_t::array_end/parse_event_t::object_endevent, and both remove the whole value. Discarding it at the start event also means the callback is called neither for the content of the value nor for its matching end event. - Discarding a
parse_event_t::keyevent discards the whole object member. The callback is still called for the associated value, but its return value has no further effect. - In case a value outside a structured type is skipped, it is replaced with
null. This case happens if the top-level element is skipped.
Parameters
depth(in)- the depth of the recursion during parsing
event(in)- an event of type
parse_event_tindicating the context in the callback function has been called parsed(in, out)- the current intermediate parse result; note that
writing to this value has no effect for
parse_event_t::keyevents
Return value
Whether the JSON value which called the function during parsing should be kept (#!cpp true) or not (#!cpp false). In
the latter case, it is skipped completely, or replaced by null if it is the top-level value.
Notes
For a parse_event_t::key event, parsed holds the decoded object name, with the same guarantees as the val
parameter of json_sax::key: all escape sequences are decoded and \uXXXX escapes are
stored as UTF-8, so different spellings of the same name yield identical strings; the name is validated completely
before the callback is called, so a name with an invalid escape sequence or ill-formed UTF-8 causes a parse error and
no key event; no Unicode normalization or case conversion is applied; and a name that occurs several times in the
same object yields one key event per occurrence.
Examples
??? example "Example: skip an object key while parsing"
The example below demonstrates the `parse()` function with
and without callback function.
```cpp
--8<-- "examples/parse__string__parser_callback_t.cpp"
```
Output:
```json
--8<-- "examples/parse__string__parser_callback_t.output"
```
??? example "Example: how discarded values are removed"
The example below shows where discarded values are removed. The array and the number are discarded in different
ways, but in each case the parse result contains neither the value nor its key.
```cpp
--8<-- "examples/parser_callback_t.cpp"
```
Output:
```json
--8<-- "examples/parser_callback_t.output"
```
See also
parse- deserialize from a compatible inputparse_event_t- enumeration of parser events- Parser Callbacks - filter or inspect values while parsing
Version history
- Added in version 1.0.0.
- Fixed in version 3.13.0 to also remove discarded values from a parent object; before, discarding an array or a value stored under an object key left a discarded member behind, which made the parse result serialize to invalid JSON.
- Fixed in version 3.13.0 so that discarding an array or object at its start event also hides its content from the callback, as documented above; before, the callback was still called for the content, and the key of every member of a discarded object was kept in memory until the parse ended.