diff --git a/doc/examples/basic_json__istream.cpp b/doc/examples/basic_json__istream.cpp new file mode 100644 index 000000000..71f16ed34 --- /dev/null +++ b/doc/examples/basic_json__istream.cpp @@ -0,0 +1,55 @@ +#include + +using json = nlohmann::json; + +int main() +{ + // a JSON text + auto text = R"( + { + "Image": { + "Width": 800, + "Height": 600, + "Title": "View from 15th Floor", + "Thumbnail": { + "Url": "http://www.example.com/image/481989943", + "Height": 125, + "Width": 100 + }, + "Animated" : false, + "IDs": [116, 943, 234, 38793] + } + } + )"; + + // fill a stream with JSON text + std::stringstream ss; + ss << text; + + // create JSON from stream + json j_complete(ss); + std::cout << std::setw(4) << j_complete << "\n\n"; + + + // define parser callback + json::parser_callback_t cb = [](int depth, json::parse_event_t event, json & parsed) + { + // skip object elements with key "Thumbnail" + if (event == json::parse_event_t::key and parsed == json("Thumbnail")) + { + return false; + } + else + { + return true; + } + }; + + // fill a stream with JSON text + ss.clear(); + ss << text; + + // create JSON from stream (with callback) + json j_filtered(ss, cb); + std::cout << std::setw(4) << j_filtered << '\n'; +} \ No newline at end of file diff --git a/doc/examples/basic_json__istream.link b/doc/examples/basic_json__istream.link new file mode 100644 index 000000000..e5475436d --- /dev/null +++ b/doc/examples/basic_json__istream.link @@ -0,0 +1 @@ +online \ No newline at end of file diff --git a/doc/examples/basic_json__istream.output b/doc/examples/basic_json__istream.output new file mode 100644 index 000000000..279a7ff74 --- /dev/null +++ b/doc/examples/basic_json__istream.output @@ -0,0 +1,34 @@ +{ + "Image": { + "Animated": false, + "Height": 600, + "IDs": [ + 116, + 943, + 234, + 38793 + ], + "Thumbnail": { + "Height": 125, + "Url": "http://www.example.com/image/481989943", + "Width": 100 + }, + "Title": "View from 15th Floor", + "Width": 800 + } +} + +{ + "Image": { + "Animated": false, + "Height": 600, + "IDs": [ + 116, + 943, + 234, + 38793 + ], + "Title": "View from 15th Floor", + "Width": 800 + } +} diff --git a/src/json.hpp b/src/json.hpp index 39ef1fe88..effdeb135 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -1806,6 +1806,31 @@ class basic_json } } + /*! + @brief construct a JSON value given an input stream + + @param[in,out] i stream to read a serialized JSON value from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates constructing a JSON value from + a `std::stringstream` with and without callback + function.,basic_json__istream} + + @since version 2.0.0 + */ + basic_json(std::istream& i, parser_callback_t cb = nullptr) + { + *this = parser(i, cb).parse(); + } + /////////////////////////////////////// // other constructors and destructor // /////////////////////////////////////// diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index f49096290..e0636ab34 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -1806,6 +1806,31 @@ class basic_json } } + /*! + @brief construct a JSON value given an input stream + + @param[in,out] i stream to read a serialized JSON value from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates constructing a JSON value from + a `std::stringstream` with and without callback + function.,basic_json__istream} + + @since version 2.0.0 + */ + basic_json(std::istream& i, parser_callback_t cb = nullptr) + { + *this = parser(i, cb).parse(); + } + /////////////////////////////////////// // other constructors and destructor // /////////////////////////////////////// diff --git a/test/unit.cpp b/test/unit.cpp index 1c3957a46..fc77fe287 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -1264,6 +1264,42 @@ TEST_CASE("constructors") } } } + + SECTION("create a JSON value from an input stream") + { + SECTION("sts::stringstream") + { + std::stringstream ss; + ss << "[\"foo\",1,2,3,false,{\"one\":1}]"; + json j(ss); + CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); + } + + SECTION("with callback function") + { + std::stringstream ss; + ss << "[\"foo\",1,2,3,false,{\"one\":1}]"; + json j(ss, [](int, json::parse_event_t, const json & val) + { + // filter all number(2) elements + if (val == json(2)) + { + return false; + } + else + { + return true; + } + }); + CHECK(j == json({"foo", 1, 3, false, {{"one", 1}}})); + } + + SECTION("std::ifstream") + { + std::ifstream f("test/json_tests/pass1.json"); + json j(f); + } + } } TEST_CASE("other constructors and destructor")