Skip to content

Commit

Permalink
Merge pull request #876 from nlohmann/feature/rfc7396
Browse files Browse the repository at this point in the history
JSON Merge Patch (RFC 7396)
  • Loading branch information
nlohmann authored Jan 18, 2018
2 parents 3ac6745 + 541b461 commit 6402077
Show file tree
Hide file tree
Showing 7 changed files with 470 additions and 0 deletions.
78 changes: 78 additions & 0 deletions develop/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7397,6 +7397,7 @@ class basic_json
diff for two JSON values.,diff}
@sa @ref patch -- apply a JSON patch
@sa @ref merge_patch -- apply a JSON Merge Patch
@sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
Expand Down Expand Up @@ -7528,6 +7529,83 @@ class basic_json
}

/// @}

////////////////////////////////
// JSON Merge Patch functions //
////////////////////////////////

/// @name JSON Merge Patch functions
/// @{

/*!
@brief applies a JSON Merge Patch
The merge patch format is primarily intended for use with the HTTP PATCH
method as a means of describing a set of modifications to a target
resource's content. This function applies a merge patch to the current
JSON value.
The function implements the following algorithm from Section 2 of
[RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396):
```
define MergePatch(Target, Patch):
if Patch is an Object:
if Target is not an Object:
Target = {} // Ignore the contents and set it to an empty Object
for each Name/Value pair in Patch:
if Value is null:
if Name exists in Target:
remove the Name/Value pair from Target
else:
Target[Name] = MergePatch(Target[Name], Value)
return Target
else:
return Patch
```
Thereby, `Target` is the current object; that is, the patch is applied to
the current value.
@param[in] patch the patch to apply
@complexity Linear in the lengths of @a patch.
@liveexample{The following code shows how a JSON Merge Patch is applied to
a JSON document.,merge_patch}
@sa @ref patch -- apply a JSON patch
@sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396)
@since version 3.0.0
*/
void merge_patch(const basic_json& patch)
{
if (patch.is_object())
{
if (not is_object())
{
*this = object();
}
for (auto it = patch.begin(); it != patch.end(); ++it)
{
if (it.value().is_null())
{
erase(it.key());
}
else
{
operator[](it.key()).merge_patch(it.value());
}
}
}
else
{
*this = patch;
}
}

/// @}
};

//////////////////
Expand Down
40 changes: 40 additions & 0 deletions doc/examples/merge_patch.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include <iostream>
#include "json.hpp"
#include <iomanip> // for std::setw

using json = nlohmann::json;

int main()
{
// the original document
json document = R"({
"title": "Goodbye!",
"author": {
"givenName": "John",
"familyName": "Doe"
},
"tags": [
"example",
"sample"
],
"content": "This will be unchanged"
})"_json;

// the patch
json patch = R"({
"title": "Hello!",
"phoneNumber": "+01-123-456-7890",
"author": {
"familyName": null
},
"tags": [
"example"
]
})"_json;

// apply the patch
document.merge_patch(patch);

// output original and patched document
std::cout << std::setw(4) << document << std::endl;
}
1 change: 1 addition & 0 deletions doc/examples/merge_patch.link
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<a target="_blank" href="https://wandbox.org/permlink/h13IsbffwmMfqsej"><b>online</b></a>
11 changes: 11 additions & 0 deletions doc/examples/merge_patch.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"author": {
"givenName": "John"
},
"content": "This will be unchanged",
"phoneNumber": "+01-123-456-7890",
"tags": [
"example"
],
"title": "Hello!"
}
78 changes: 78 additions & 0 deletions src/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14685,6 +14685,7 @@ class basic_json
diff for two JSON values.,diff}

@sa @ref patch -- apply a JSON patch
@sa @ref merge_patch -- apply a JSON Merge Patch

@sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)

Expand Down Expand Up @@ -14816,6 +14817,83 @@ class basic_json
}

/// @}

////////////////////////////////
// JSON Merge Patch functions //
////////////////////////////////

/// @name JSON Merge Patch functions
/// @{

/*!
@brief applies a JSON Merge Patch

The merge patch format is primarily intended for use with the HTTP PATCH
method as a means of describing a set of modifications to a target
resource's content. This function applies a merge patch to the current
JSON value.

The function implements the following algorithm from Section 2 of
[RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396):

```
define MergePatch(Target, Patch):
if Patch is an Object:
if Target is not an Object:
Target = {} // Ignore the contents and set it to an empty Object
for each Name/Value pair in Patch:
if Value is null:
if Name exists in Target:
remove the Name/Value pair from Target
else:
Target[Name] = MergePatch(Target[Name], Value)
return Target
else:
return Patch
```

Thereby, `Target` is the current object; that is, the patch is applied to
the current value.

@param[in] patch the patch to apply

@complexity Linear in the lengths of @a patch.

@liveexample{The following code shows how a JSON Merge Patch is applied to
a JSON document.,merge_patch}

@sa @ref patch -- apply a JSON patch
@sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396)

@since version 3.0.0
*/
void merge_patch(const basic_json& patch)
{
if (patch.is_object())
{
if (not is_object())
{
*this = object();
}
for (auto it = patch.begin(); it != patch.end(); ++it)
{
if (it.value().is_null())
{
erase(it.key());
}
else
{
operator[](it.key()).merge_patch(it.value());
}
}
}
else
{
*this = patch;
}
}

/// @}
};

//////////////////
Expand Down
1 change: 1 addition & 0 deletions test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ SOURCES = src/unit.cpp \
src/unit-iterator_wrapper.cpp \
src/unit-iterators1.cpp \
src/unit-iterators2.cpp \
src/unit-merge_patch.cpp \
src/unit-json_patch.cpp \
src/unit-json_pointer.cpp \
src/unit-meta.cpp \
Expand Down
Loading

0 comments on commit 6402077

Please sign in to comment.