diff --git a/src/json.hpp b/src/json.hpp index 6aca24ad..96bc1f32 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -8855,7 +8855,6 @@ basic_json_parser_63: } private: - /// return referenced value reference get(reference j) const { pointer result = &j; @@ -8880,6 +8879,49 @@ basic_json_parser_63: return *result; } + reference get2(reference j) const + { + pointer result = &j; + + for (const auto& reference_token : reference_tokens) + { + switch (result->m_type) + { + case value_t::null: + { + if (reference_token == "0") + { + result = &result->operator[](0); + } + else + { + result = &result->operator[](reference_token); + } + continue; + } + + case value_t::object: + { + result = &result->operator[](reference_token); + continue; + } + + case value_t::array: + { + result = &result->operator[](static_cast(std::stoi(reference_token))); + continue; + } + + default: + { + throw std::domain_error("unresolved reference token '" + reference_token + "'"); + } + } + } + + return *result; + } + const_reference get(const_reference j) const { const_pointer result = &j; @@ -9042,6 +9084,35 @@ basic_json_parser_63: } } } + + /*! + @param[in] value flattened JSON + + @return deflattened JSON + */ + static basic_json deflatten(const basic_json& value) + { + if (not value.is_object()) + { + throw std::domain_error("only objects can be deflattened"); + } + + basic_json result; + + // iterate the JSON object values + for (const auto& element : *value.m_value.object) + { + if (not element.second.is_primitive()) + { + throw std::domain_error("values in object must be primitive"); + } + + // assign value to reference pointed to by JSON pointer + json_pointer(element.first).get2(result) = element.second; + } + + return result; + } }; /*! @@ -9053,6 +9124,14 @@ basic_json_parser_63: json_pointer::flatten("", *this, result); return result; } + + /*! + @return the original JSON from a flattened version + */ + basic_json deflatten() const + { + return json_pointer::deflatten(*this); + } }; diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 74827e2c..1a049cd5 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -8165,7 +8165,6 @@ class basic_json } private: - /// return referenced value reference get(reference j) const { pointer result = &j; @@ -8190,6 +8189,49 @@ class basic_json return *result; } + reference get2(reference j) const + { + pointer result = &j; + + for (const auto& reference_token : reference_tokens) + { + switch (result->m_type) + { + case value_t::null: + { + if (reference_token == "0") + { + result = &result->operator[](0); + } + else + { + result = &result->operator[](reference_token); + } + continue; + } + + case value_t::object: + { + result = &result->operator[](reference_token); + continue; + } + + case value_t::array: + { + result = &result->operator[](static_cast(std::stoi(reference_token))); + continue; + } + + default: + { + throw std::domain_error("unresolved reference token '" + reference_token + "'"); + } + } + } + + return *result; + } + const_reference get(const_reference j) const { const_pointer result = &j; @@ -8352,6 +8394,35 @@ class basic_json } } } + + /*! + @param[in] value flattened JSON + + @return deflattened JSON + */ + static basic_json deflatten(const basic_json& value) + { + if (not value.is_object()) + { + throw std::domain_error("only objects can be deflattened"); + } + + basic_json result; + + // iterate the JSON object values + for (const auto& element : *value.m_value.object) + { + if (not element.second.is_primitive()) + { + throw std::domain_error("values in object must be primitive"); + } + + // assign value to reference pointed to by JSON pointer + json_pointer(element.first).get2(result) = element.second; + } + + return result; + } }; /*! @@ -8363,6 +8434,14 @@ class basic_json json_pointer::flatten("", *this, result); return result; } + + /*! + @return the original JSON from a flattened version + */ + basic_json deflatten() const + { + return json_pointer::deflatten(*this); + } }; diff --git a/test/unit.cpp b/test/unit.cpp index 0d9aa0a7..1ace40d0 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -12213,7 +12213,24 @@ TEST_CASE("JSON pointers") {"/object/~01", "tilde1"} }; + // check if flattened result is as expected CHECK(j.flatten() == j_flatten); + + // check if deflattened result is as expected + CHECK(j_flatten.deflatten() == j); + + // explicit roundtrip check + CHECK(j.flatten().deflatten() == j); + + // roundtrip for primitive values + json j_null; + CHECK(j_null.flatten().deflatten() == j_null); + json j_number = 42; + CHECK(j_number.flatten().deflatten() == j_number); + json j_boolean = false; + CHECK(j_boolean.flatten().deflatten() == j_boolean); + json j_string = "foo"; + CHECK(j_string.flatten().deflatten() == j_string); } }