* docs: new design for the documentation site Apply the brand to the Material for MkDocs site: Inter and JetBrains Mono served by the site (upright and real italic), brand colours, blue header band with the syntax pattern, wordmark in the header, new home page (hero, cards, animated feature tour), 404 page, polish for tabs, search, footer, focus rings, tables and code blocks, and theme features (code copy, previous/next footer, TOC follow, search suggestions). Draw the number railroad diagram, the parser callback events and the iterator illustrations as inline SVGs that follow the light and dark scheme. The generator scripts are in docs/mkdocs/scripts/figures; the feature slideshow (json-light.svg, json-dark.svg, replacing json.gif on the home page) is built by docs/mkdocs/scripts/slideshow. Decision nodes in five flowcharts become hexagons, which need far less room. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: add figures, table captions and a macro chooser - Figures with numbered captions: SAX stepper, json_view layout and edit stepper, exception map, JSON pointer and patch walkers, QA pipeline, scaling and binary size charts, roadmap lanes, release timeline, integration decision tree and namespace builder - Table captions (nj-table-caption) on 9 pages - Compile times: modules and PCH charts, filesystem section, re-measured Figure 1, links between features/modules.md and compile_times.md - Interactive macro chooser for features/arbitrary_types.md - Link check: exclude URLs that answer the plugin with 400/401/419 or are dead (customers.md) Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: macro chooser generates adl_serializer for non-default-constructible types Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: cross-link concept pages and API pages in See also sections Add See also links in both directions between the concept pages (features, home, integration) and the API pages, write API links in code font, give every entry a comment after a dash, and show the callback event figure on the parser callbacks page. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: address review comments on the new design - Home: add a "Latest release" button - Sponsors: update the list and group it by tier - Features: list all feature pages on the index page - Releases: add highlights per release, link the 4.0 roadmap, add the first commit to the timeline - Exceptions: prefix all example messages with the exception name - API: no code font for format names in the See also links of the to_/from_ pages - Merge Patch: show the document before, the patch, and the result - Replace "--" with typographic dashes, mark external links with an icon, center Mermaid diagrams Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me>
6.0 KiB
Parsing and Exceptions
When the input is not valid JSON, an exception of type parse_error is thrown.
This exception contains the position in the input where the error occurred, together with a diagnostic message and the
last read input token. The exceptions page contains a
list of examples for parse error exceptions. In case you process untrusted
input, always enclose your code with a #!cpp try/#!cpp catch block, like
json j;
try
{
j = json::parse(my_input);
}
catch (json::parse_error& ex)
{
std::cerr << "parse error at byte " << ex.byte << std::endl;
}
In case exceptions are undesired or not supported by the environment, there are different ways to proceed:
!!! tip
[Working without exceptions](../no_exceptions.md) also covers accessing values and converting to your own types.
Switch off exceptions
The parse() function accepts a #!cpp bool parameter allow_exceptions which
controls whether an exception is thrown when a parse error occurs (#!cpp true, default) or whether a discarded value
should be returned (#!cpp false).
json j = json::parse(my_input, nullptr, false);
if (j.is_discarded())
{
std::cerr << "parse error" << std::endl;
}
Note there is no diagnostic information available in this scenario.
Use accept() function
Alternatively, function accept() can be used which does not return a json value,
but a #!cpp bool indicating whether the input is valid JSON.
if (!json::accept(my_input))
{
std::cerr << "parse error" << std::endl;
}
Again, there is no diagnostic information available.
User-defined SAX interface
Finally, you can implement the SAX interface and decide what should happen in case of a parse error.
This function has the following interface:
bool parse_error(std::size_t position,
const std::string& last_token,
const json::exception& ex);
The return value indicates whether the parsing should continue, so the function should usually return #!cpp false.
??? example "Example: report parse errors without exceptions"
The example derives from the library's DOM parser and overrides `parse_error` to print the error instead of
throwing. Note the DOM parser is an implementation detail (`nlohmann::detail`) and may change between releases;
see [Do not use the `detail` namespace](../../integration/migration_guide.md#do-not-use-the-detail-namespace).
```cpp
--8<-- "examples/sax_no_exception.cpp"
```
Output:
```
--8<-- "examples/sax_no_exception.output"
```
Where did the error occur?
The message of a parse_error for JSON text contains the line
and column of the error:
[json.exception.parse_error.101] parse error at line 3, column 8: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal
The exception object itself only stores the byte index of the last read character in the member byte (the first
byte of the input has index 1). The same index is passed to parse_error in the SAX interface. If
you need the line and column as numbers, for example to show them in an editor, compute them from the input:
??? example "Example: compute line and column of a parse error"
```cpp
--8<-- "examples/parse_error_position.cpp"
```
Output:
```
--8<-- "examples/parse_error_position.output"
```
Columns count bytes, so a line with multi-byte UTF-8 characters before the error may differ from the column your editor shows.
Where is the value that caused a later error?
A parse_error is raised while the text is read. Many mistakes show up later: the text is valid JSON, but a value has
the wrong type when you convert it (type_error.302), or a key is missing (out_of_range.403). The exception then says
what is wrong, but not where in the input the value was. Define
JSON_DIAGNOSTIC_POSITIONS before including the library to add the
byte range of the offending value to such messages (since version 3.12.0), and to query the range of any value with
start_pos() and end_pos():
??? example "Example: locate a value with diagnostic positions"
```cpp
--8<-- "examples/parse_error_position_diagnostic.cpp"
```
Output:
```
--8<-- "examples/parse_error_position_diagnostic.output"
```
Positions are only available for values created by parse, they are not updated when a
value is changed, and the macro makes every value 16 bytes larger on 64-bit platforms, so use it where the cost is
acceptable, for example for configuration files. Note that start_pos() is a 0-based index into the input, whereas
byte of a parse_error starts at 1.
For binary formats such as CBOR, there are no lines; byte is the position in the byte sequence. To find out how many
bytes a successfully parsed value used, see
Several values in one stream.
See also
parse- deserialize from a compatible inputaccept- check if the input is valid JSONsax_parse- generate SAX eventsparse_error- exception thrown on a parse errorJSON_DIAGNOSTIC_POSITIONS- record start and end positions of parsed values- Working Without Exceptions - error handling when exceptions are disabled
- Exceptions - list of exceptions and error codes
- Parsing Untrusted Input - limits and checks for input you do not control