diff --git a/doc/examples/update__range.cpp b/doc/examples/update__range.cpp index 9f3e521a3..98a390429 100644 --- a/doc/examples/update__range.cpp +++ b/doc/examples/update__range.cpp @@ -7,12 +7,17 @@ using json = nlohmann::json; int main() { // create two JSON objects - json o1 = R"( {"color": "red", "price": 17.99} )"_json; - json o2 = R"( {"color": "blue", "speed": 100} )"_json; + json o1 = R"( {"color": "red", "price": 17.99, "names": {"de": "Flugzeug"}} )"_json; + json o2 = R"( {"color": "blue", "speed": 100, "names": {"en": "plane"}} )"_json; + json o3 = o1; - // add all keys from o2 to o1 (updating "color") + // add all keys from o2 to o1 (updating "color", replacing "names") o1.update(o2.begin(), o2.end()); - // output updated object o1 + // add all keys from o2 to o1 (updating "color", merging "names") + o3.update(o2.begin(), o2.end(), true); + + // output updated object o1 and o3 std::cout << std::setw(2) << o1 << '\n'; + std::cout << std::setw(2) << o3 << '\n'; } diff --git a/doc/examples/update__range.output b/doc/examples/update__range.output index 69f0965af..c35a74513 100644 --- a/doc/examples/update__range.output +++ b/doc/examples/update__range.output @@ -1,5 +1,17 @@ { "color": "blue", + "names": { + "en": "plane" + }, + "price": 17.99, + "speed": 100 +} +{ + "color": "blue", + "names": { + "de": "Flugzeug", + "en": "plane" + }, "price": 17.99, "speed": 100 } diff --git a/doc/mkdocs/docs/api/basic_json/update.md b/doc/mkdocs/docs/api/basic_json/update.md index 2807bf897..851417e87 100644 --- a/doc/mkdocs/docs/api/basic_json/update.md +++ b/doc/mkdocs/docs/api/basic_json/update.md @@ -5,12 +5,14 @@ void update(const_reference j, bool merge_objects = false); // (2) -void update(const_iterator first, const_iterator last); +void update(const_iterator first, const_iterator last, bool merge_objects = false); ``` -1. Inserts all values from JSON object `j`. and overwrites existing keys. When `merge_objects` is `#!c false` (default), - existing keys are overwritten. When `merge_objects` is `#!c true`, recursively merges objects with common keys. -2. Inserts all values from from range `[first, last)` and overwrites existing keys. +1. Inserts all values from JSON object `j`. +2. Inserts all values from from range `[first, last)` + +When `merge_objects` is `#!c false` (default), existing keys are overwritten. When `merge_objects` is `#!c true`, +recursively merges objects with common keys. The function is motivated by Python's [dict.update](https://docs.python.org/3.6/library/stdtypes.html#dict.update) function. diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 58a00a470..9852b18c8 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -6002,39 +6002,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec */ void update(const_reference j, bool merge_objects = false) { - // implicitly convert null value to an empty object - if (is_null()) - { - m_type = value_t::object; - m_value.object = create(); - assert_invariant(); - } - - if (JSON_HEDLEY_UNLIKELY(!is_object())) - { - JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()), *this)); - } - if (JSON_HEDLEY_UNLIKELY(!j.is_object())) - { - JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()), *this)); - } - - for (auto it = j.cbegin(); it != j.cend(); ++it) - { - if (merge_objects && it.value().is_object()) - { - auto it2 = m_value.object->find(it.key()); - if (it2 != m_value.object->end()) - { - it2->second.update(it.value(), true); - continue; - } - } - m_value.object->operator[](it.key()) = it.value(); -#if JSON_DIAGNOSTICS - m_value.object->operator[](it.key()).m_parent = this; -#endif - } + update(j.begin(), j.end(), merge_objects); } /*! @@ -6045,6 +6013,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @param[in] first begin of the range of elements to insert @param[in] last end of the range of elements to insert + @param[in] merge_objects when true, existing keys are not overwritten, but + contents of objects are merged recursively + (default: false) @throw type_error.312 if called on JSON values other than objects; example: `"cannot use update() with string"` @@ -6061,9 +6032,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update - @since version 3.0.0 + @since version 3.0.0, `merge_objects` parameter added in 3.10.4. */ - void update(const_iterator first, const_iterator last) + void update(const_iterator first, const_iterator last, bool merge_objects = false) { // implicitly convert null value to an empty object if (is_null()) @@ -6093,6 +6064,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec for (auto it = first; it != last; ++it) { + if (merge_objects && it.value().is_object()) + { + auto it2 = m_value.object->find(it.key()); + if (it2 != m_value.object->end()) + { + it2->second.update(it.value(), true); + continue; + } + } m_value.object->operator[](it.key()) = it.value(); #if JSON_DIAGNOSTICS m_value.object->operator[](it.key()).m_parent = this; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 9e230b75f..bf7212b4d 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -23471,6 +23471,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec Inserts all values from JSON object @a j and overwrites existing keys. @param[in] j JSON object to read values from + @param[in] merge_objects when true, existing keys are not overwritten, but + contents of objects are merged recursively + (default: false) @throw type_error.312 if called on JSON values other than objects; example: `"cannot use update() with string"` @@ -23482,43 +23485,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update - @since version 3.0.0 + @since version 3.0.0, `merge_objects` parameter added in 3.10.4. */ - void update(const_reference j, bool recursive = false) + void update(const_reference j, bool merge_objects = false) { - // implicitly convert null value to an empty object - if (is_null()) - { - m_type = value_t::object; - m_value.object = create(); - assert_invariant(); - } - - if (JSON_HEDLEY_UNLIKELY(!is_object())) - { - JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()), *this)); - } - if (JSON_HEDLEY_UNLIKELY(!j.is_object())) - { - JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()), *this)); - } - - for (auto it = j.cbegin(); it != j.cend(); ++it) - { - if (recursive && it.value().is_object()) - { - auto it2 = m_value.object->find(it.key()); - if (it2 != m_value.object->end()) - { - it2->second.update(it.value(), recursive); - continue; - } - } - m_value.object->operator[](it.key()) = it.value(); -#if JSON_DIAGNOSTICS - m_value.object->operator[](it.key()).m_parent = this; -#endif - } + update(j.begin(), j.end(), merge_objects); } /*! @@ -23529,6 +23500,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @param[in] first begin of the range of elements to insert @param[in] last end of the range of elements to insert + @param[in] merge_objects when true, existing keys are not overwritten, but + contents of objects are merged recursively + (default: false) @throw type_error.312 if called on JSON values other than objects; example: `"cannot use update() with string"` @@ -23545,9 +23519,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update - @since version 3.0.0 + @since version 3.0.0, `merge_objects` parameter added in 3.10.4. */ - void update(const_iterator first, const_iterator last) + void update(const_iterator first, const_iterator last, bool merge_objects = false) { // implicitly convert null value to an empty object if (is_null()) @@ -23577,6 +23551,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec for (auto it = first; it != last; ++it) { + if (merge_objects && it.value().is_object()) + { + auto it2 = m_value.object->find(it.key()); + if (it2 != m_value.object->end()) + { + it2->second.update(it.value(), true); + continue; + } + } m_value.object->operator[](it.key()) = it.value(); #if JSON_DIAGNOSTICS m_value.object->operator[](it.key()).m_parent = this;