mirror of
https://github.com/nlohmann/json.git
synced 2025-07-29 23:01:16 +03:00
📝 add page on parsing and exceptions
This commit is contained in:
13
doc/mkdocs/docs/features/parsing/index.md
Normal file
13
doc/mkdocs/docs/features/parsing/index.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Overview
|
||||
|
||||
!!! note
|
||||
|
||||
This page is under construction.
|
||||
|
||||
## Input
|
||||
|
||||
## SAX vs. DOM parsing
|
||||
|
||||
## Exceptions
|
||||
|
||||
See [parsing and exceptions](parse_exceptions.md).
|
114
doc/mkdocs/docs/features/parsing/parse_exceptions.md
Normal file
114
doc/mkdocs/docs/features/parsing/parse_exceptions.md
Normal file
@ -0,0 +1,114 @@
|
||||
# Parsing and exceptions
|
||||
|
||||
When the input is not valid JSON, an exception of type [`parse_error`](../../home/exceptions.md#parse-errors) 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](../../home/exceptions.md#parse-errors). In case you process untrusted input, always enclose your code with a `#!cpp try`/`#!cpp catch` block, like
|
||||
|
||||
```cpp
|
||||
json j;
|
||||
try
|
||||
{
|
||||
j = json::parse(my_input);
|
||||
}
|
||||
catch (json::exception::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:
|
||||
|
||||
|
||||
## Switch off exceptions
|
||||
|
||||
The `parse()` function accepts as last parameter a `#!cpp bool` variable `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`).
|
||||
|
||||
```cpp
|
||||
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.
|
||||
|
||||
```cpp
|
||||
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](sax_interface.md) and decide what should happen in case of a parse error.
|
||||
|
||||
This function has the following interface:
|
||||
|
||||
```cpp
|
||||
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
|
||||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include "json.hpp"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
class sax_no_exception : public nlohmann::detail::json_sax_dom_parser<json>
|
||||
{
|
||||
public:
|
||||
sax_no_exception(json& j)
|
||||
: nlohmann::detail::json_sax_dom_parser<json>(j, false)
|
||||
{}
|
||||
|
||||
bool parse_error(std::size_t position,
|
||||
const std::string& last_token,
|
||||
const json::exception& ex)
|
||||
{
|
||||
std::cerr << "parse error at input byte " << position << "\n"
|
||||
<< ex.what() << "\n"
|
||||
<< "last read: \"" << last_token << "\""
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
std::string myinput = "[1,2,3,]";
|
||||
|
||||
json result;
|
||||
sax_no_exception sax(result);
|
||||
|
||||
bool parse_result = json::sax_parse(myinput, &sax);
|
||||
if (!parse_result)
|
||||
{
|
||||
std::cerr << "parsing unsuccessful!" << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "parsed value: " << result << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
parse error at input byte 8
|
||||
[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal
|
||||
last read: "3,]"
|
||||
parsing unsuccessful!
|
||||
parsed value: [1,2,3]
|
||||
```
|
79
doc/mkdocs/docs/features/parsing/parser_callbacks.md
Normal file
79
doc/mkdocs/docs/features/parsing/parser_callbacks.md
Normal file
@ -0,0 +1,79 @@
|
||||
# Parser Callbacks
|
||||
|
||||
## Overview
|
||||
|
||||
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.
|
||||
|
||||
The type of the callback function is:
|
||||
|
||||
```cpp
|
||||
template<typename BasicJsonType>
|
||||
using parser_callback_t =
|
||||
std::function<bool(int depth, parse_event_t event, BasicJsonType& parsed)>;
|
||||
```
|
||||
|
||||
|
||||
## Callback event types
|
||||
|
||||
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
|
||||
|
||||
??? example
|
||||
|
||||
When parsing the following JSON text,
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Berlin",
|
||||
"location": [
|
||||
52.519444,
|
||||
13.406667
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
these calls are made to the callback function:
|
||||
|
||||
| event | depth | parsed |
|
||||
| -------------- | ----- | ------ |
|
||||
| `object_start` | 0 | *discarded* |
|
||||
| `key` | 1 | `#!json "name"` |
|
||||
| `value` | 1 | `#!json "Berlin"` |
|
||||
| `key` | 1 | `#!json "location"` |
|
||||
| `array_start` | 1 | *discarded* |
|
||||
| `value` | 2 | `#!json 52.519444` |
|
||||
| `value` | 2 | `#!json 13.406667` |
|
||||
| `array_end` | 1 | `#!json [52.519444,13.406667]` |
|
||||
| `object_end` | 0 | `#!json {"location":[52.519444,13.406667],"name":"Berlin"}` |
|
||||
|
||||
## Return value
|
||||
|
||||
Discarding a value (i.e., returning `#!c 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.
|
||||
- In case a value outside a structured type is skipped, it is replaced with `#!json null`. This case happens if the top-level element is skipped.
|
||||
|
||||
??? example
|
||||
|
||||
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"
|
||||
```
|
65
doc/mkdocs/docs/features/parsing/sax_interface.md
Normal file
65
doc/mkdocs/docs/features/parsing/sax_interface.md
Normal file
@ -0,0 +1,65 @@
|
||||
# SAX Interface
|
||||
|
||||
The library uses a SAX-like interface with the following functions:
|
||||
|
||||
```plantuml
|
||||
interface json::sax_t {
|
||||
+ {abstract} bool null()
|
||||
|
||||
+ {abstract} bool boolean(bool val)
|
||||
|
||||
+ {abstract} bool number_integer(number_integer_t val)
|
||||
+ {abstract} bool number_unsigned(number_unsigned_t val)
|
||||
|
||||
+ {abstract} bool number_float(number_float_t val, const string_t& s)
|
||||
|
||||
+ {abstract} bool string(string_t& val)
|
||||
|
||||
+ {abstract} bool start_object(std::size_t elements)
|
||||
+ {abstract} bool end_object()
|
||||
+ {abstract} bool start_array(std::size_t elements)
|
||||
+ {abstract} bool end_array()
|
||||
+ {abstract} bool key(string_t& val)
|
||||
|
||||
+ {abstract} bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex)
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
// called when null is parsed
|
||||
bool null();
|
||||
|
||||
// called when a boolean is parsed; value is passed
|
||||
bool boolean(bool val);
|
||||
|
||||
// called when a signed or unsigned integer number is parsed; value is passed
|
||||
bool number_integer(number_integer_t val);
|
||||
bool number_unsigned(number_unsigned_t val);
|
||||
|
||||
// called when a floating-point number is parsed; value and original string is passed
|
||||
bool number_float(number_float_t val, const string_t& s);
|
||||
|
||||
// called when a string is parsed; value is passed and can be safely moved away
|
||||
bool string(string_t& val);
|
||||
|
||||
// called when an object or array begins or ends, resp. The number of elements is passed (or -1 if not known)
|
||||
bool start_object(std::size_t elements);
|
||||
bool end_object();
|
||||
bool start_array(std::size_t elements);
|
||||
bool end_array();
|
||||
// called when an object key is parsed; value is passed and can be safely moved away
|
||||
bool key(string_t& val);
|
||||
|
||||
// called when a parse error occurs; byte position, the last token, and an exception is passed
|
||||
bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex);
|
||||
```
|
||||
|
||||
The return value of each function determines whether parsing should proceed.
|
||||
|
||||
To implement your own SAX handler, proceed as follows:
|
||||
|
||||
1. Implement the SAX interface in a class. You can use class `nlohmann::json_sax<json>` as base class, but you can also use any class where the functions described above are implemented and public.
|
||||
2. Create an object of your SAX interface class, e.g. `my_sax`.
|
||||
3. Call `#!cpp bool json::sax_parse(input, &my_sax);` where the first parameter can be any input like a string or an input stream and the second parameter is a pointer to your SAX interface.
|
||||
|
||||
Note the `sax_parse` function only returns a `#!cpp bool` indicating the result of the last executed SAX event. It does not return `json` value - it is up to you to decide what to do with the SAX events. Furthermore, no exceptions are thrown in case of a parse error - it is up to you what to do with the exception object passed to your `parse_error` implementation. Internally, the SAX interface is used for the DOM parser (class `json_sax_dom_parser`) as well as the acceptor (`json_sax_acceptor`), see file `json_sax.hpp`.
|
Reference in New Issue
Block a user