Files
json/docs/mkdocs/docs/api/json_sax/key.md
T
Niels Lohmann 2aecd86b37 Document the contract of object keys passed to json_sax::key and key callbacks (#5956)
* 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>
2026-10-29 07:37:33 +01:00

2.6 KiB

nlohmann::json_sax::key

virtual bool key(string_t& val) = 0;

An object key was read.

Parameters

val (in)
object key

Return value

Whether parsing should proceed.

Notes

It is safe to move the passed object key value.

When parsing JSON text, val is the decoded object name, not its spelling in the input:

  • All escape sequences (\", \\, \/, \b, \f, \n, \r, \t, \uXXXX, and surrogate pairs) are decoded, and \uXXXX escapes are stored as UTF-8. Different spellings of the same name, such as #!json "/" and #!json "\/", or #!json "\u00e9" and #!json "\u00E9", yield identical strings. An escaped \u0000 yields an embedded NUL byte.
  • The name is scanned and validated completely before key is called. If it contains an invalid escape sequence, an unpaired surrogate, a control character, or ill-formed UTF-8, the parse fails with a parse_error, and key is not called for it.
  • No Unicode normalization or case conversion is applied: names that differ in any byte are different strings.
  • key is called before the following : is read, so a parse error may still follow for the same member.
  • A name that occurs several times in the same object is passed once per occurrence.

For the binary formats, object keys contain no escape sequences. For CBOR, MessagePack, UBJSON, and BSON, val holds the bytes stored in the input, and sax_parse passes them unchanged, without checking them for valid UTF-8. BON8 encodes characters itself, so an ill-formed name is a parse error and key is not called for it.

Examples

??? example

The example below shows how the SAX interface is used.

```cpp
--8<-- "examples/sax_parse.cpp"
```

Output:

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

See also

Version history

  • Added in version 3.2.0.
  • The behavior described in the notes above (decoded names, validation before key is called, no normalization, key before the : check, one call per duplicate, bytes of binary formats passed unchanged) is the same in all versions from 3.2.0 on, and for the key event of a parser callback from 3.0.0 on. BSON is only supported from version 3.4.0, and BON8 only from version 3.13.0.