mirror of
https://github.com/nlohmann/json.git
synced 2025-07-31 10:24:23 +03:00
Add ignore_trailing_commas
option (#4609)
Added examples and modified the corresponding documents and unit tests. Signed-off-by: chirsz-ever <chirsz-ever@outlook.com> Co-authored-by: Niels Lohmann <niels.lohmann@gmail.com>
This commit is contained in:
12
README.md
12
README.md
@ -1801,7 +1801,17 @@ This library does not support comments by default. It does so for three reasons:
|
|||||||
|
|
||||||
3. It is dangerous for interoperability if some libraries would add comment support while others don't. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this.
|
3. It is dangerous for interoperability if some libraries would add comment support while others don't. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this.
|
||||||
|
|
||||||
However, you can pass set parameter `ignore_comments` to true in the `parse` function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace.
|
However, you can set set parameter `ignore_comments` to true in the `parse` function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace.
|
||||||
|
|
||||||
|
### Trailing commas
|
||||||
|
|
||||||
|
The JSON specification does not allow trailing commas in arrays and objects, and hence this library is treating them as parsing errors by default.
|
||||||
|
|
||||||
|
Like comments, you can set parameter `ignore_trailing_commas` to true in the `parse` function to ignore trailing commas in arrays and objects. Note that a single comma as the only content of the array or object (`[,]` or `{,}`) is not allowed, and multiple trailing commas (`[1,,]`) are not allowed either.
|
||||||
|
|
||||||
|
This library does not add trailing commas when serializing JSON data.
|
||||||
|
|
||||||
|
For more information, see [JSON With Commas and Comments (JWCC)](https://nigeltao.github.io/blog/2021/json-with-commas-comments.html).
|
||||||
|
|
||||||
### Order of object keys
|
### Order of object keys
|
||||||
|
|
||||||
|
@ -4,12 +4,14 @@
|
|||||||
// (1)
|
// (1)
|
||||||
template<typename InputType>
|
template<typename InputType>
|
||||||
static bool accept(InputType&& i,
|
static bool accept(InputType&& i,
|
||||||
const bool ignore_comments = false);
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false);
|
||||||
|
|
||||||
// (2)
|
// (2)
|
||||||
template<typename IteratorType>
|
template<typename IteratorType>
|
||||||
static bool accept(IteratorType first, IteratorType last,
|
static bool accept(IteratorType first, IteratorType last,
|
||||||
const bool ignore_comments = false);
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false);
|
||||||
```
|
```
|
||||||
|
|
||||||
Checks whether the input is valid JSON.
|
Checks whether the input is valid JSON.
|
||||||
@ -50,6 +52,10 @@ Unlike the [`parse()`](parse.md) function, this function neither throws an excep
|
|||||||
: whether comments should be ignored and treated like whitespace (`#!cpp true`) or yield a parse error
|
: whether comments should be ignored and treated like whitespace (`#!cpp true`) or yield a parse error
|
||||||
(`#!cpp false`); (optional, `#!cpp false` by default)
|
(`#!cpp false`); (optional, `#!cpp false` by default)
|
||||||
|
|
||||||
|
`ignore_trailing_commas` (in)
|
||||||
|
: whether trailing commas in arrays or objects should be ignored and treated like whitespace (`#!cpp true`) or yield a parse error
|
||||||
|
(`#!cpp false`); (optional, `#!cpp false` by default)
|
||||||
|
|
||||||
`first` (in)
|
`first` (in)
|
||||||
: iterator to the start of the character range
|
: iterator to the start of the character range
|
||||||
|
|
||||||
@ -102,6 +108,7 @@ A UTF-8 byte order mark is silently ignored.
|
|||||||
- Added in version 3.0.0.
|
- Added in version 3.0.0.
|
||||||
- Ignoring comments via `ignore_comments` added in version 3.9.0.
|
- Ignoring comments via `ignore_comments` added in version 3.9.0.
|
||||||
- Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0.
|
- Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0.
|
||||||
|
- Added `ignore_trailing_commas` in version 3.12.1.
|
||||||
|
|
||||||
!!! warning "Deprecation"
|
!!! warning "Deprecation"
|
||||||
|
|
||||||
|
@ -6,14 +6,16 @@ template<typename InputType>
|
|||||||
static basic_json parse(InputType&& i,
|
static basic_json parse(InputType&& i,
|
||||||
const parser_callback_t cb = nullptr,
|
const parser_callback_t cb = nullptr,
|
||||||
const bool allow_exceptions = true,
|
const bool allow_exceptions = true,
|
||||||
const bool ignore_comments = false);
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false);
|
||||||
|
|
||||||
// (2)
|
// (2)
|
||||||
template<typename IteratorType>
|
template<typename IteratorType>
|
||||||
static basic_json parse(IteratorType first, IteratorType last,
|
static basic_json parse(IteratorType first, IteratorType last,
|
||||||
const parser_callback_t cb = nullptr,
|
const parser_callback_t cb = nullptr,
|
||||||
const bool allow_exceptions = true,
|
const bool allow_exceptions = true,
|
||||||
const bool ignore_comments = false);
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false);
|
||||||
```
|
```
|
||||||
|
|
||||||
1. Deserialize from a compatible input.
|
1. Deserialize from a compatible input.
|
||||||
@ -56,6 +58,10 @@ static basic_json parse(IteratorType first, IteratorType last,
|
|||||||
: whether comments should be ignored and treated like whitespace (`#!cpp true`) or yield a parse error
|
: whether comments should be ignored and treated like whitespace (`#!cpp true`) or yield a parse error
|
||||||
(`#!cpp false`); (optional, `#!cpp false` by default)
|
(`#!cpp false`); (optional, `#!cpp false` by default)
|
||||||
|
|
||||||
|
`ignore_trailing_commas` (in)
|
||||||
|
: whether trailing commas in arrays or objects should be ignored and treated like whitespace (`#!cpp true`) or yield a parse error
|
||||||
|
(`#!cpp false`); (optional, `#!cpp false` by default)
|
||||||
|
|
||||||
`first` (in)
|
`first` (in)
|
||||||
: iterator to the start of a character range
|
: iterator to the start of a character range
|
||||||
|
|
||||||
@ -189,6 +195,34 @@ A UTF-8 byte order mark is silently ignored.
|
|||||||
--8<-- "examples/parse__allow_exceptions.output"
|
--8<-- "examples/parse__allow_exceptions.output"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
??? example "Effect of `ignore_comments` parameter"
|
||||||
|
|
||||||
|
The example below demonstrates the effect of the `ignore_comments` parameter in the `parse()` function.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/comments.cpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```
|
||||||
|
--8<-- "examples/comments.output"
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Effect of `ignore_trailing_commas` parameter"
|
||||||
|
|
||||||
|
The example below demonstrates the effect of the `ignore_trailing_commas` parameter in the `parse()` function.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/trailing_commas.cpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```
|
||||||
|
--8<-- "examples/trailing_commas.output"
|
||||||
|
```
|
||||||
|
|
||||||
## See also
|
## See also
|
||||||
|
|
||||||
- [accept](accept.md) - check if the input is valid JSON
|
- [accept](accept.md) - check if the input is valid JSON
|
||||||
@ -200,6 +234,7 @@ A UTF-8 byte order mark is silently ignored.
|
|||||||
- Overload for contiguous containers (1) added in version 2.0.3.
|
- Overload for contiguous containers (1) added in version 2.0.3.
|
||||||
- Ignoring comments via `ignore_comments` added in version 3.9.0.
|
- Ignoring comments via `ignore_comments` added in version 3.9.0.
|
||||||
- Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0.
|
- Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0.
|
||||||
|
- Added `ignore_trailing_commas` in version 3.12.1.
|
||||||
|
|
||||||
!!! warning "Deprecation"
|
!!! warning "Deprecation"
|
||||||
|
|
||||||
|
@ -7,7 +7,8 @@ static bool sax_parse(InputType&& i,
|
|||||||
SAX* sax,
|
SAX* sax,
|
||||||
input_format_t format = input_format_t::json,
|
input_format_t format = input_format_t::json,
|
||||||
const bool strict = true,
|
const bool strict = true,
|
||||||
const bool ignore_comments = false);
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false);
|
||||||
|
|
||||||
// (2)
|
// (2)
|
||||||
template<class IteratorType, class SAX>
|
template<class IteratorType, class SAX>
|
||||||
@ -15,7 +16,8 @@ static bool sax_parse(IteratorType first, IteratorType last,
|
|||||||
SAX* sax,
|
SAX* sax,
|
||||||
input_format_t format = input_format_t::json,
|
input_format_t format = input_format_t::json,
|
||||||
const bool strict = true,
|
const bool strict = true,
|
||||||
const bool ignore_comments = false);
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false);
|
||||||
```
|
```
|
||||||
|
|
||||||
Read from input and generate SAX events
|
Read from input and generate SAX events
|
||||||
@ -65,6 +67,10 @@ The SAX event lister must follow the interface of [`json_sax`](../json_sax/index
|
|||||||
: whether comments should be ignored and treated like whitespace (`#!cpp true`) or yield a parse error
|
: whether comments should be ignored and treated like whitespace (`#!cpp true`) or yield a parse error
|
||||||
(`#!cpp false`); (optional, `#!cpp false` by default)
|
(`#!cpp false`); (optional, `#!cpp false` by default)
|
||||||
|
|
||||||
|
`ignore_trailing_commas` (in)
|
||||||
|
: whether trailing commas in arrays or objects should be ignored and treated like whitespace (`#!cpp true`) or yield a parse error
|
||||||
|
(`#!cpp false`); (optional, `#!cpp false` by default)
|
||||||
|
|
||||||
`first` (in)
|
`first` (in)
|
||||||
: iterator to the start of a character range
|
: iterator to the start of a character range
|
||||||
|
|
||||||
@ -107,6 +113,7 @@ A UTF-8 byte order mark is silently ignored.
|
|||||||
|
|
||||||
- Added in version 3.2.0.
|
- Added in version 3.2.0.
|
||||||
- Ignoring comments via `ignore_comments` added in version 3.9.0.
|
- Ignoring comments via `ignore_comments` added in version 3.9.0.
|
||||||
|
- Added `ignore_trailing_commas` in version 3.12.1.
|
||||||
|
|
||||||
!!! warning "Deprecation"
|
!!! warning "Deprecation"
|
||||||
|
|
||||||
|
31
docs/mkdocs/docs/examples/comments.cpp
Normal file
31
docs/mkdocs/docs/examples/comments.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::string s = R"(
|
||||||
|
{
|
||||||
|
// update in 2006: removed Pluto
|
||||||
|
"planets": ["Mercury", "Venus", "Earth", "Mars",
|
||||||
|
"Jupiter", "Uranus", "Neptune" /*, "Pluto" */]
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
json j = json::parse(s);
|
||||||
|
}
|
||||||
|
catch (json::exception& e)
|
||||||
|
{
|
||||||
|
std::cout << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
json j = json::parse(s,
|
||||||
|
/* callback */ nullptr,
|
||||||
|
/* allow exceptions */ true,
|
||||||
|
/* ignore_comments */ true);
|
||||||
|
std::cout << j.dump(2) << '\n';
|
||||||
|
}
|
12
docs/mkdocs/docs/examples/comments.output
Normal file
12
docs/mkdocs/docs/examples/comments.output
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[json.exception.parse_error.101] parse error at line 3, column 9: syntax error while parsing object key - invalid literal; last read: '<U+000A> {<U+000A> /'; expected string literal
|
||||||
|
{
|
||||||
|
"planets": [
|
||||||
|
"Mercury",
|
||||||
|
"Venus",
|
||||||
|
"Earth",
|
||||||
|
"Mars",
|
||||||
|
"Jupiter",
|
||||||
|
"Uranus",
|
||||||
|
"Neptune"
|
||||||
|
]
|
||||||
|
}
|
37
docs/mkdocs/docs/examples/trailing_commas.cpp
Normal file
37
docs/mkdocs/docs/examples/trailing_commas.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::string s = R"(
|
||||||
|
{
|
||||||
|
"planets": [
|
||||||
|
"Mercury",
|
||||||
|
"Venus",
|
||||||
|
"Earth",
|
||||||
|
"Mars",
|
||||||
|
"Jupiter",
|
||||||
|
"Uranus",
|
||||||
|
"Neptune",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
json j = json::parse(s);
|
||||||
|
}
|
||||||
|
catch (json::exception& e)
|
||||||
|
{
|
||||||
|
std::cout << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
json j = json::parse(s,
|
||||||
|
/* callback */ nullptr,
|
||||||
|
/* allow exceptions */ true,
|
||||||
|
/* ignore_comments */ false,
|
||||||
|
/* ignore_trailing_commas */ true);
|
||||||
|
std::cout << j.dump(2) << '\n';
|
||||||
|
}
|
12
docs/mkdocs/docs/examples/trailing_commas.output
Normal file
12
docs/mkdocs/docs/examples/trailing_commas.output
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[json.exception.parse_error.101] parse error at line 11, column 9: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal
|
||||||
|
{
|
||||||
|
"planets": [
|
||||||
|
"Mercury",
|
||||||
|
"Venus",
|
||||||
|
"Earth",
|
||||||
|
"Mars",
|
||||||
|
"Jupiter",
|
||||||
|
"Uranus",
|
||||||
|
"Neptune"
|
||||||
|
]
|
||||||
|
}
|
@ -11,7 +11,9 @@ This library does not support comments *by default*. It does so for three reason
|
|||||||
|
|
||||||
3. It is dangerous for interoperability if some libraries add comment support while others do not. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this.
|
3. It is dangerous for interoperability if some libraries add comment support while others do not. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this.
|
||||||
|
|
||||||
However, you can pass set parameter `ignore_comments` to `#!c true` in the parse function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace.
|
However, you can set parameter `ignore_comments` to `#!cpp true` in the [`parse`](../api/basic_json/parse.md) function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace.
|
||||||
|
|
||||||
|
For more information, see [JSON With Commas and Comments (JWCC)](https://nigeltao.github.io/blog/2021/json-with-commas-comments.html).
|
||||||
|
|
||||||
!!! example
|
!!! example
|
||||||
|
|
||||||
@ -28,56 +30,11 @@ However, you can pass set parameter `ignore_comments` to `#!c true` in the parse
|
|||||||
When calling `parse` without additional argument, a parse error exception is thrown. If `ignore_comments` is set to `#! true`, the comments are ignored during parsing:
|
When calling `parse` without additional argument, a parse error exception is thrown. If `ignore_comments` is set to `#! true`, the comments are ignored during parsing:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
#include <iostream>
|
--8<-- "examples/comments.cpp"
|
||||||
#include "json.hpp"
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
std::string s = R"(
|
|
||||||
{
|
|
||||||
// update in 2006: removed Pluto
|
|
||||||
"planets": ["Mercury", "Venus", "Earth", "Mars",
|
|
||||||
"Jupiter", "Uranus", "Neptune" /*, "Pluto" */]
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
json j = json::parse(s);
|
|
||||||
}
|
|
||||||
catch (json::exception &e)
|
|
||||||
{
|
|
||||||
std::cout << e.what() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
json j = json::parse(s,
|
|
||||||
/* callback */ nullptr,
|
|
||||||
/* allow exceptions */ true,
|
|
||||||
/* ignore_comments */ true);
|
|
||||||
std::cout << j.dump(2) << '\n';
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Output:
|
Output:
|
||||||
|
|
||||||
```
|
```
|
||||||
[json.exception.parse_error.101] parse error at line 3, column 9:
|
--8<-- "examples/comments.output"
|
||||||
syntax error while parsing object key - invalid literal;
|
|
||||||
last read: '<U+000A> {<U+000A> /'; expected string literal
|
|
||||||
```
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"planets": [
|
|
||||||
"Mercury",
|
|
||||||
"Venus",
|
|
||||||
"Earth",
|
|
||||||
"Mars",
|
|
||||||
"Jupiter",
|
|
||||||
"Uranus",
|
|
||||||
"Neptune"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
39
docs/mkdocs/docs/features/trailing_commas.md
Normal file
39
docs/mkdocs/docs/features/trailing_commas.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Trailing Commas
|
||||||
|
|
||||||
|
Like [comments](comments.md), this library does not support trailing commas in arrays and objects *by default*.
|
||||||
|
|
||||||
|
You can set parameter `ignore_trailing_commas` to `#!cpp true` in the [`parse`](../api/basic_json/parse.md) function to allow trailing commas in arrays and objects. Note that a single comma as the only content of the array or object (`[,]` or `{,}`) is not allowed, and multiple trailing commas (`[1,,]`) are not allowed either.
|
||||||
|
|
||||||
|
This library does not add trailing commas when serializing JSON data.
|
||||||
|
|
||||||
|
For more information, see [JSON With Commas and Comments (JWCC)](https://nigeltao.github.io/blog/2021/json-with-commas-comments.html).
|
||||||
|
|
||||||
|
!!! example
|
||||||
|
|
||||||
|
Consider the following JSON with trailing commas.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"planets": [
|
||||||
|
"Mercury",
|
||||||
|
"Venus",
|
||||||
|
"Earth",
|
||||||
|
"Mars",
|
||||||
|
"Jupiter",
|
||||||
|
"Uranus",
|
||||||
|
"Neptune",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
When calling `parse` without additional argument, a parse error exception is thrown. If `ignore_trailing_commas` is set to `#! true`, the trailing commas are ignored during parsing:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/trailing_commas.cpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```
|
||||||
|
--8<-- "examples/trailing_commas.output"
|
||||||
|
```
|
@ -67,6 +67,7 @@ nav:
|
|||||||
- features/binary_formats/ubjson.md
|
- features/binary_formats/ubjson.md
|
||||||
- features/binary_values.md
|
- features/binary_values.md
|
||||||
- features/comments.md
|
- features/comments.md
|
||||||
|
- features/trailing_commas.md
|
||||||
- Element Access:
|
- Element Access:
|
||||||
- features/element_access/index.md
|
- features/element_access/index.md
|
||||||
- features/element_access/unchecked_access.md
|
- features/element_access/unchecked_access.md
|
||||||
|
@ -71,10 +71,12 @@ class parser
|
|||||||
explicit parser(InputAdapterType&& adapter,
|
explicit parser(InputAdapterType&& adapter,
|
||||||
parser_callback_t<BasicJsonType> cb = nullptr,
|
parser_callback_t<BasicJsonType> cb = nullptr,
|
||||||
const bool allow_exceptions_ = true,
|
const bool allow_exceptions_ = true,
|
||||||
const bool skip_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas_ = false)
|
||||||
: callback(std::move(cb))
|
: callback(std::move(cb))
|
||||||
, m_lexer(std::move(adapter), skip_comments)
|
, m_lexer(std::move(adapter), ignore_comments)
|
||||||
, allow_exceptions(allow_exceptions_)
|
, allow_exceptions(allow_exceptions_)
|
||||||
|
, ignore_trailing_commas(ignore_trailing_commas_)
|
||||||
{
|
{
|
||||||
// read first token
|
// read first token
|
||||||
get_token();
|
get_token();
|
||||||
@ -384,11 +386,17 @@ class parser
|
|||||||
if (states.back()) // array
|
if (states.back()) // array
|
||||||
{
|
{
|
||||||
// comma -> next value
|
// comma -> next value
|
||||||
|
// or end of array (ignore_trailing_commas = true)
|
||||||
if (get_token() == token_type::value_separator)
|
if (get_token() == token_type::value_separator)
|
||||||
{
|
{
|
||||||
// parse a new value
|
// parse a new value
|
||||||
get_token();
|
get_token();
|
||||||
continue;
|
|
||||||
|
// if ignore_trailing_commas and last_token is ], we can continue to "closing ]"
|
||||||
|
if (!(ignore_trailing_commas && last_token == token_type::end_array))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// closing ]
|
// closing ]
|
||||||
@ -417,32 +425,39 @@ class parser
|
|||||||
// states.back() is false -> object
|
// states.back() is false -> object
|
||||||
|
|
||||||
// comma -> next value
|
// comma -> next value
|
||||||
|
// or end of object (ignore_trailing_commas = true)
|
||||||
if (get_token() == token_type::value_separator)
|
if (get_token() == token_type::value_separator)
|
||||||
{
|
{
|
||||||
// parse key
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string))
|
|
||||||
{
|
|
||||||
return sax->parse_error(m_lexer.get_position(),
|
|
||||||
m_lexer.get_token_string(),
|
|
||||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse separator (:)
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
|
|
||||||
{
|
|
||||||
return sax->parse_error(m_lexer.get_position(),
|
|
||||||
m_lexer.get_token_string(),
|
|
||||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse values
|
|
||||||
get_token();
|
get_token();
|
||||||
continue;
|
|
||||||
|
// if ignore_trailing_commas and last_token is }, we can continue to "closing }"
|
||||||
|
if (!(ignore_trailing_commas && last_token == token_type::end_object))
|
||||||
|
{
|
||||||
|
// parse key
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse separator (:)
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse values
|
||||||
|
get_token();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// closing }
|
// closing }
|
||||||
@ -513,6 +528,8 @@ class parser
|
|||||||
lexer_t m_lexer;
|
lexer_t m_lexer;
|
||||||
/// whether to throw exceptions in case of errors
|
/// whether to throw exceptions in case of errors
|
||||||
const bool allow_exceptions = true;
|
const bool allow_exceptions = true;
|
||||||
|
/// whether trailing commas in objects and arrays should be ignored (true) or signaled as errors (false)
|
||||||
|
const bool ignore_trailing_commas = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
@ -134,11 +134,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
InputAdapterType adapter,
|
InputAdapterType adapter,
|
||||||
detail::parser_callback_t<basic_json>cb = nullptr,
|
detail::parser_callback_t<basic_json>cb = nullptr,
|
||||||
const bool allow_exceptions = true,
|
const bool allow_exceptions = true,
|
||||||
const bool ignore_comments = false
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
|
return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
|
||||||
std::move(cb), allow_exceptions, ignore_comments);
|
std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -4045,10 +4046,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static basic_json parse(InputType&& i,
|
static basic_json parse(InputType&& i,
|
||||||
parser_callback_t cb = nullptr,
|
parser_callback_t cb = nullptr,
|
||||||
const bool allow_exceptions = true,
|
const bool allow_exceptions = true,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
basic_json result;
|
basic_json result;
|
||||||
parser(detail::input_adapter(std::forward<InputType>(i)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved,accessForwarded]
|
parser(detail::input_adapter(std::forward<InputType>(i)), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas).parse(true, result); // cppcheck-suppress[accessMoved,accessForwarded]
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4060,10 +4062,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
IteratorType last,
|
IteratorType last,
|
||||||
parser_callback_t cb = nullptr,
|
parser_callback_t cb = nullptr,
|
||||||
const bool allow_exceptions = true,
|
const bool allow_exceptions = true,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
basic_json result;
|
basic_json result;
|
||||||
parser(detail::input_adapter(std::move(first), std::move(last)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved]
|
parser(detail::input_adapter(std::move(first), std::move(last)), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas).parse(true, result); // cppcheck-suppress[accessMoved]
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4072,10 +4075,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static basic_json parse(detail::span_input_adapter&& i,
|
static basic_json parse(detail::span_input_adapter&& i,
|
||||||
parser_callback_t cb = nullptr,
|
parser_callback_t cb = nullptr,
|
||||||
const bool allow_exceptions = true,
|
const bool allow_exceptions = true,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
basic_json result;
|
basic_json result;
|
||||||
parser(i.get(), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved]
|
parser(i.get(), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas).parse(true, result); // cppcheck-suppress[accessMoved]
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4083,26 +4087,29 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
||||||
template<typename InputType>
|
template<typename InputType>
|
||||||
static bool accept(InputType&& i,
|
static bool accept(InputType&& i,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments).accept(true);
|
return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief check if the input is valid JSON
|
/// @brief check if the input is valid JSON
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
||||||
template<typename IteratorType>
|
template<typename IteratorType>
|
||||||
static bool accept(IteratorType first, IteratorType last,
|
static bool accept(IteratorType first, IteratorType last,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true);
|
return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
|
||||||
static bool accept(detail::span_input_adapter&& i,
|
static bool accept(detail::span_input_adapter&& i,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
return parser(i.get(), nullptr, false, ignore_comments).accept(true);
|
return parser(i.get(), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief generate SAX events
|
/// @brief generate SAX events
|
||||||
@ -4112,11 +4119,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static bool sax_parse(InputType&& i, SAX* sax,
|
static bool sax_parse(InputType&& i, SAX* sax,
|
||||||
input_format_t format = input_format_t::json,
|
input_format_t format = input_format_t::json,
|
||||||
const bool strict = true,
|
const bool strict = true,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
||||||
return format == input_format_t::json
|
return format == input_format_t::json
|
||||||
? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
|
? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict)
|
||||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4127,11 +4135,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,
|
static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,
|
||||||
input_format_t format = input_format_t::json,
|
input_format_t format = input_format_t::json,
|
||||||
const bool strict = true,
|
const bool strict = true,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||||
return format == input_format_t::json
|
return format == input_format_t::json
|
||||||
? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
|
? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict)
|
||||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4146,12 +4155,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,
|
static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,
|
||||||
input_format_t format = input_format_t::json,
|
input_format_t format = input_format_t::json,
|
||||||
const bool strict = true,
|
const bool strict = true,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
auto ia = i.get();
|
auto ia = i.get();
|
||||||
return format == input_format_t::json
|
return format == input_format_t::json
|
||||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||||
? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
|
? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict)
|
||||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
||||||
}
|
}
|
||||||
|
@ -12987,10 +12987,12 @@ class parser
|
|||||||
explicit parser(InputAdapterType&& adapter,
|
explicit parser(InputAdapterType&& adapter,
|
||||||
parser_callback_t<BasicJsonType> cb = nullptr,
|
parser_callback_t<BasicJsonType> cb = nullptr,
|
||||||
const bool allow_exceptions_ = true,
|
const bool allow_exceptions_ = true,
|
||||||
const bool skip_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas_ = false)
|
||||||
: callback(std::move(cb))
|
: callback(std::move(cb))
|
||||||
, m_lexer(std::move(adapter), skip_comments)
|
, m_lexer(std::move(adapter), ignore_comments)
|
||||||
, allow_exceptions(allow_exceptions_)
|
, allow_exceptions(allow_exceptions_)
|
||||||
|
, ignore_trailing_commas(ignore_trailing_commas_)
|
||||||
{
|
{
|
||||||
// read first token
|
// read first token
|
||||||
get_token();
|
get_token();
|
||||||
@ -13300,11 +13302,17 @@ class parser
|
|||||||
if (states.back()) // array
|
if (states.back()) // array
|
||||||
{
|
{
|
||||||
// comma -> next value
|
// comma -> next value
|
||||||
|
// or end of array (ignore_trailing_commas = true)
|
||||||
if (get_token() == token_type::value_separator)
|
if (get_token() == token_type::value_separator)
|
||||||
{
|
{
|
||||||
// parse a new value
|
// parse a new value
|
||||||
get_token();
|
get_token();
|
||||||
continue;
|
|
||||||
|
// if ignore_trailing_commas and last_token is ], we can continue to "closing ]"
|
||||||
|
if (!(ignore_trailing_commas && last_token == token_type::end_array))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// closing ]
|
// closing ]
|
||||||
@ -13333,32 +13341,39 @@ class parser
|
|||||||
// states.back() is false -> object
|
// states.back() is false -> object
|
||||||
|
|
||||||
// comma -> next value
|
// comma -> next value
|
||||||
|
// or end of object (ignore_trailing_commas = true)
|
||||||
if (get_token() == token_type::value_separator)
|
if (get_token() == token_type::value_separator)
|
||||||
{
|
{
|
||||||
// parse key
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string))
|
|
||||||
{
|
|
||||||
return sax->parse_error(m_lexer.get_position(),
|
|
||||||
m_lexer.get_token_string(),
|
|
||||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse separator (:)
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
|
|
||||||
{
|
|
||||||
return sax->parse_error(m_lexer.get_position(),
|
|
||||||
m_lexer.get_token_string(),
|
|
||||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse values
|
|
||||||
get_token();
|
get_token();
|
||||||
continue;
|
|
||||||
|
// if ignore_trailing_commas and last_token is }, we can continue to "closing }"
|
||||||
|
if (!(ignore_trailing_commas && last_token == token_type::end_object))
|
||||||
|
{
|
||||||
|
// parse key
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse separator (:)
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse values
|
||||||
|
get_token();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// closing }
|
// closing }
|
||||||
@ -13429,6 +13444,8 @@ class parser
|
|||||||
lexer_t m_lexer;
|
lexer_t m_lexer;
|
||||||
/// whether to throw exceptions in case of errors
|
/// whether to throw exceptions in case of errors
|
||||||
const bool allow_exceptions = true;
|
const bool allow_exceptions = true;
|
||||||
|
/// whether trailing commas in objects and arrays should be ignored (true) or signaled as errors (false)
|
||||||
|
const bool ignore_trailing_commas = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
@ -20219,11 +20236,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
InputAdapterType adapter,
|
InputAdapterType adapter,
|
||||||
detail::parser_callback_t<basic_json>cb = nullptr,
|
detail::parser_callback_t<basic_json>cb = nullptr,
|
||||||
const bool allow_exceptions = true,
|
const bool allow_exceptions = true,
|
||||||
const bool ignore_comments = false
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
|
return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
|
||||||
std::move(cb), allow_exceptions, ignore_comments);
|
std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -24130,10 +24148,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static basic_json parse(InputType&& i,
|
static basic_json parse(InputType&& i,
|
||||||
parser_callback_t cb = nullptr,
|
parser_callback_t cb = nullptr,
|
||||||
const bool allow_exceptions = true,
|
const bool allow_exceptions = true,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
basic_json result;
|
basic_json result;
|
||||||
parser(detail::input_adapter(std::forward<InputType>(i)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved,accessForwarded]
|
parser(detail::input_adapter(std::forward<InputType>(i)), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas).parse(true, result); // cppcheck-suppress[accessMoved,accessForwarded]
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24145,10 +24164,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
IteratorType last,
|
IteratorType last,
|
||||||
parser_callback_t cb = nullptr,
|
parser_callback_t cb = nullptr,
|
||||||
const bool allow_exceptions = true,
|
const bool allow_exceptions = true,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
basic_json result;
|
basic_json result;
|
||||||
parser(detail::input_adapter(std::move(first), std::move(last)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved]
|
parser(detail::input_adapter(std::move(first), std::move(last)), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas).parse(true, result); // cppcheck-suppress[accessMoved]
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24157,10 +24177,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static basic_json parse(detail::span_input_adapter&& i,
|
static basic_json parse(detail::span_input_adapter&& i,
|
||||||
parser_callback_t cb = nullptr,
|
parser_callback_t cb = nullptr,
|
||||||
const bool allow_exceptions = true,
|
const bool allow_exceptions = true,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
basic_json result;
|
basic_json result;
|
||||||
parser(i.get(), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved]
|
parser(i.get(), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas).parse(true, result); // cppcheck-suppress[accessMoved]
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24168,26 +24189,29 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
||||||
template<typename InputType>
|
template<typename InputType>
|
||||||
static bool accept(InputType&& i,
|
static bool accept(InputType&& i,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments).accept(true);
|
return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief check if the input is valid JSON
|
/// @brief check if the input is valid JSON
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
||||||
template<typename IteratorType>
|
template<typename IteratorType>
|
||||||
static bool accept(IteratorType first, IteratorType last,
|
static bool accept(IteratorType first, IteratorType last,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true);
|
return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
|
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
|
||||||
static bool accept(detail::span_input_adapter&& i,
|
static bool accept(detail::span_input_adapter&& i,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
return parser(i.get(), nullptr, false, ignore_comments).accept(true);
|
return parser(i.get(), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief generate SAX events
|
/// @brief generate SAX events
|
||||||
@ -24197,11 +24221,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static bool sax_parse(InputType&& i, SAX* sax,
|
static bool sax_parse(InputType&& i, SAX* sax,
|
||||||
input_format_t format = input_format_t::json,
|
input_format_t format = input_format_t::json,
|
||||||
const bool strict = true,
|
const bool strict = true,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
||||||
return format == input_format_t::json
|
return format == input_format_t::json
|
||||||
? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
|
? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict)
|
||||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24212,11 +24237,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,
|
static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,
|
||||||
input_format_t format = input_format_t::json,
|
input_format_t format = input_format_t::json,
|
||||||
const bool strict = true,
|
const bool strict = true,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||||
return format == input_format_t::json
|
return format == input_format_t::json
|
||||||
? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
|
? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict)
|
||||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24231,12 +24257,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,
|
static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,
|
||||||
input_format_t format = input_format_t::json,
|
input_format_t format = input_format_t::json,
|
||||||
const bool strict = true,
|
const bool strict = true,
|
||||||
const bool ignore_comments = false)
|
const bool ignore_comments = false,
|
||||||
|
const bool ignore_trailing_commas = false)
|
||||||
{
|
{
|
||||||
auto ia = i.get();
|
auto ia = i.get();
|
||||||
return format == input_format_t::json
|
return format == input_format_t::json
|
||||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||||
? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
|
? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict)
|
||||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
||||||
}
|
}
|
||||||
|
@ -206,6 +206,7 @@ class SaxCountdown : public nlohmann::json::json_sax_t
|
|||||||
json parser_helper(const std::string& s);
|
json parser_helper(const std::string& s);
|
||||||
bool accept_helper(const std::string& s);
|
bool accept_helper(const std::string& s);
|
||||||
void comments_helper(const std::string& s);
|
void comments_helper(const std::string& s);
|
||||||
|
void trailing_comma_helper(const std::string& s);
|
||||||
|
|
||||||
json parser_helper(const std::string& s)
|
json parser_helper(const std::string& s)
|
||||||
{
|
{
|
||||||
@ -225,6 +226,8 @@ json parser_helper(const std::string& s)
|
|||||||
|
|
||||||
comments_helper(s);
|
comments_helper(s);
|
||||||
|
|
||||||
|
trailing_comma_helper(s);
|
||||||
|
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,10 +262,11 @@ bool accept_helper(const std::string& s)
|
|||||||
// 6. check if this approach came to the same result
|
// 6. check if this approach came to the same result
|
||||||
CHECK(ok_noexcept == ok_noexcept_cb);
|
CHECK(ok_noexcept == ok_noexcept_cb);
|
||||||
|
|
||||||
// 7. check if comments are properly ignored
|
// 7. check if comments or trailing commas are properly ignored
|
||||||
if (ok_accept)
|
if (ok_accept)
|
||||||
{
|
{
|
||||||
comments_helper(s);
|
comments_helper(s);
|
||||||
|
trailing_comma_helper(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8. return result
|
// 8. return result
|
||||||
@ -302,6 +306,38 @@ void comments_helper(const std::string& s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void trailing_comma_helper(const std::string& s)
|
||||||
|
{
|
||||||
|
json _;
|
||||||
|
|
||||||
|
// parse/accept with default parser
|
||||||
|
CHECK_NOTHROW(_ = json::parse(s));
|
||||||
|
CHECK(json::accept(s));
|
||||||
|
|
||||||
|
// parse/accept while allowing trailing commas
|
||||||
|
CHECK_NOTHROW(_ = json::parse(s, nullptr, false, false, true));
|
||||||
|
CHECK(json::accept(s, false, true));
|
||||||
|
|
||||||
|
// note: [,] and {,} are not allowed
|
||||||
|
if (s.size() > 1 && (s.back() == ']' || s.back() == '}') && !_.empty())
|
||||||
|
{
|
||||||
|
std::vector<std::string> json_with_trailing_commas;
|
||||||
|
json_with_trailing_commas.push_back(s.substr(0, s.size() - 1) + " ," + s.back());
|
||||||
|
json_with_trailing_commas.push_back(s.substr(0, s.size() - 1) + "," + s.back());
|
||||||
|
json_with_trailing_commas.push_back(s.substr(0, s.size() - 1) + ", " + s.back());
|
||||||
|
|
||||||
|
for (const auto& json_with_trailing_comma : json_with_trailing_commas)
|
||||||
|
{
|
||||||
|
CAPTURE(json_with_trailing_comma)
|
||||||
|
CHECK_THROWS_AS(_ = json::parse(json_with_trailing_comma), json::parse_error);
|
||||||
|
CHECK(!json::accept(json_with_trailing_comma));
|
||||||
|
|
||||||
|
CHECK_NOTHROW(_ = json::parse(json_with_trailing_comma, nullptr, true, false, true));
|
||||||
|
CHECK(json::accept(json_with_trailing_comma, false, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TEST_CASE("parser class")
|
TEST_CASE("parser class")
|
||||||
|
Reference in New Issue
Block a user