nlohmann::basic_json::patch¶
basic_json patch(const basic_json& json_patch) const;
JSON Patch defines a JSON document structure for expressing a sequence of operations to apply to a JSON document. With this function, a JSON Patch is applied to the current JSON value by executing all operations from the patch.
Parameters¶
json_patch(in)- JSON patch document
Return value¶
patched document
Exception safety¶
Strong guarantee: if an exception is thrown, there are no changes in the JSON value.
Exceptions¶
- Throws
parse_error.104if the JSON patch does not consist of an array of objects. - Throws
parse_error.105if the JSON patch is malformed (e.g., mandatory attributes are missing); example:"operation 'add' must have member 'path'". - Throws
out_of_range.401if an array index is out of range. - Throws
parse_error.106if an array index in a "path" or "from" member begins with '0'; example:"array index '01' must not begin with '0'". - Throws
parse_error.107if a "path" or "from" member is not empty and does not begin with a slash (/); example:"JSON pointer must be empty or begin with '/' - was: 'a'". - Throws
parse_error.108if a tilde (~) in a "path" or "from" member is not followed by0or1; example:"escape character '~' must be followed with '0' or '1'". - Throws
parse_error.109if an array index in a "path" or "from" member is not a number; example:"array index 'foo' is not a number". - Throws
out_of_range.402if the array index-is used where an existing element is required (the "path" of "replace", the "from" of "move" and "copy"); example:"array index '-' (3) is out of range". - Throws
out_of_range.403if a JSON pointer inside the patch could not be resolved successfully in the current JSON value; example:"key 'baz' not found". - Throws
out_of_range.404if a reference token of a JSON pointer inside the patch cannot be resolved, e.g.,-in a "remove" operation or1afor an array; example:"unresolved reference token '-'". - Throws
out_of_range.405if JSON pointer has no parent ("remove", "move") - Throws
out_of_range.411if an "add" operation's target location has a parent that is neither an object nor an array. - Throws
out_of_range.413if a "remove" operation's target location has a parent that is neither an object nor an array. - Throws
out_of_range.414if a "move" operation's "from" location is a proper prefix of its "path" location. - Throws
other_error.501if "test" operation was unsuccessful. A "test" operation whose "path" does not exist is unsuccessful, too: the failed lookup is reported as a failed test, even if the operation has no "value" member (which would otherwise beparse_error.105). Which of the two errors is reported for this combination depends on the order in which the operands of a comparison are evaluated, so do not rely on it.
Complexity¶
Linear in the size of the JSON value and the length of the JSON patch. As usually the patch affects only a fraction of the JSON value, the complexity can usually be neglected.
Notes¶
The application of a patch is atomic: Either all operations succeed and the patched document is returned or an exception is thrown. In any case, the original value is not changed: the patch is applied to a copy of the value.
Duplicate member names inside an operation object are resolved by the parser before the patch is applied (the last one is kept, see object_t), so {"op": "add", "op": "remove", "path": "/a"} is a remove operation.
Examples¶
Example: apply a JSON patch
The following code shows how a JSON patch is applied to a value.
#include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp>
using nlohmann::json;
using namespace nlohmann::literals;
int main()
{
// the original document
json doc = R"(
{
"baz": "qux",
"foo": "bar"
}
)"_json;
// the patch
json patch = R"(
[
{ "op": "replace", "path": "/baz", "value": "boo" },
{ "op": "add", "path": "/hello", "value": ["world"] },
{ "op": "remove", "path": "/foo"}
]
)"_json;
// apply the patch
json patched_doc = doc.patch(patch);
// output original and patched document
std::cout << std::setw(4) << doc << "\n\n"
<< std::setw(4) << patched_doc << '\n';
}
Output:
{
"baz": "qux",
"foo": "bar"
}
{
"baz": "boo",
"hello": [
"world"
]
}
Example: out_of_range.414 exception
The following code shows how a "move" operation whose "from" location is a proper prefix of its "path" location is rejected, and how the original document is left unchanged because the patch is applied to a copy.
#include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp>
using nlohmann::json;
using namespace nlohmann::literals;
int main()
{
// the original document
json doc = R"(
{
"a": { "b": 1 }
}
)"_json;
// a patch that tries to move "/a" into one of its own children
json patch = R"(
[
{ "op": "move", "from": "/a", "path": "/a/b" }
]
)"_json;
// exception out_of_range.414
try
{
json patched_doc = doc.patch(patch);
}
catch (const json::out_of_range& e)
{
std::cout << e.what() << '\n';
}
// the original document is unchanged
std::cout << std::setw(4) << doc << '\n';
}
Output:
[json.exception.out_of_range.414] cannot move value: 'from' path '/a' is a proper prefix of 'path' '/a/b'
{
"a": {
"b": 1
}
}
See also¶
- RFC 6902 (JSON Patch)
- RFC 6901 (JSON Pointer)
- patch_inplace applies a JSON Patch without creating a copy of the document
- merge_patch applies a JSON Merge Patch
Version history¶
- Added in version 2.0.0.
- Added
out_of_range.411and stopped relying on an internal assertion when an "add" operation's target location has a non-object/non-array parent in version 3.13.0 unreleased. This includes anullparent, which was previously silently converted to an object, in version 3.13.0 unreleased. - Added
out_of_range.413and stopped silently ignoring a "remove" operation whose target location has a non-object/non-array parent in version 3.13.0 unreleased. - Added
out_of_range.414and rejected a "move" operation whose "from" location is a proper prefix of its "path" location instead of silently producing a corrupted result in version 3.13.0 unreleased. - Throws
parse_error.109instead ofout_of_range.404for a one-character array index that is not a digit (e.g.,/x) in version 3.13.0 unreleased, as it already did for longer ones.