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:
@ -71,10 +71,12 @@ class parser
|
||||
explicit parser(InputAdapterType&& adapter,
|
||||
parser_callback_t<BasicJsonType> cb = nullptr,
|
||||
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))
|
||||
, m_lexer(std::move(adapter), skip_comments)
|
||||
, m_lexer(std::move(adapter), ignore_comments)
|
||||
, allow_exceptions(allow_exceptions_)
|
||||
, ignore_trailing_commas(ignore_trailing_commas_)
|
||||
{
|
||||
// read first token
|
||||
get_token();
|
||||
@ -384,11 +386,17 @@ class parser
|
||||
if (states.back()) // array
|
||||
{
|
||||
// comma -> next value
|
||||
// or end of array (ignore_trailing_commas = true)
|
||||
if (get_token() == token_type::value_separator)
|
||||
{
|
||||
// parse a new value
|
||||
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 ]
|
||||
@ -417,32 +425,39 @@ class parser
|
||||
// states.back() is false -> object
|
||||
|
||||
// comma -> next value
|
||||
// or end of object (ignore_trailing_commas = true)
|
||||
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();
|
||||
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 }
|
||||
@ -513,6 +528,8 @@ class parser
|
||||
lexer_t m_lexer;
|
||||
/// whether to throw exceptions in case of errors
|
||||
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
|
||||
|
@ -134,11 +134,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
InputAdapterType adapter,
|
||||
detail::parser_callback_t<basic_json>cb = nullptr,
|
||||
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),
|
||||
std::move(cb), allow_exceptions, ignore_comments);
|
||||
std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -4045,10 +4046,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
static basic_json parse(InputType&& i,
|
||||
parser_callback_t cb = nullptr,
|
||||
const bool allow_exceptions = true,
|
||||
const bool ignore_comments = false)
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@ -4060,10 +4062,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
IteratorType last,
|
||||
parser_callback_t cb = nullptr,
|
||||
const bool allow_exceptions = true,
|
||||
const bool ignore_comments = false)
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@ -4072,10 +4075,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
static basic_json parse(detail::span_input_adapter&& i,
|
||||
parser_callback_t cb = nullptr,
|
||||
const bool allow_exceptions = true,
|
||||
const bool ignore_comments = false)
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@ -4083,26 +4087,29 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
||||
template<typename InputType>
|
||||
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
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
||||
template<typename IteratorType>
|
||||
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_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
|
||||
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
|
||||
@ -4112,11 +4119,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
static bool sax_parse(InputType&& i, SAX* sax,
|
||||
input_format_t format = input_format_t::json,
|
||||
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));
|
||||
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);
|
||||
}
|
||||
|
||||
@ -4127,11 +4135,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,
|
||||
input_format_t format = input_format_t::json,
|
||||
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));
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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,
|
||||
input_format_t format = input_format_t::json,
|
||||
const bool strict = true,
|
||||
const bool ignore_comments = false)
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false)
|
||||
{
|
||||
auto ia = i.get();
|
||||
return format == input_format_t::json
|
||||
// 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)
|
||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
||||
}
|
||||
|
Reference in New Issue
Block a user