! @brief applies a JSON patch [JSON Patch](http://jsonpatch.com) 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. @param[in] json_patch JSON patch document @return patched document @note The application of a patch is at
| 10679 | @since version 2.0.0 |
| 10680 | */ |
| 10681 | basic_json patch(const basic_json& json_patch) const { |
| 10682 | // make a working copy to apply the patch to |
| 10683 | basic_json result = *this; |
| 10684 | |
| 10685 | // the valid JSON Patch operations |
| 10686 | enum class patch_operations { add, remove, replace, move, copy, test, invalid }; |
| 10687 | |
| 10688 | const auto get_op = [](const std::string op) { |
| 10689 | if (op == "add") { return patch_operations::add; } |
| 10690 | if (op == "remove") { return patch_operations::remove; } |
| 10691 | if (op == "replace") { return patch_operations::replace; } |
| 10692 | if (op == "move") { return patch_operations::move; } |
| 10693 | if (op == "copy") { return patch_operations::copy; } |
| 10694 | if (op == "test") { return patch_operations::test; } |
| 10695 | |
| 10696 | return patch_operations::invalid; |
| 10697 | }; |
| 10698 | |
| 10699 | // wrapper for "add" operation; add value at ptr |
| 10700 | const auto operation_add = [&result](json_pointer& ptr, basic_json val) { |
| 10701 | // adding to the root of the target document means replacing it |
| 10702 | if (ptr.is_root()) { |
| 10703 | result = val; |
| 10704 | } else { |
| 10705 | // make sure the top element of the pointer exists |
| 10706 | json_pointer top_pointer = ptr.top(); |
| 10707 | if (top_pointer != ptr) { result.at(top_pointer); } |
| 10708 | |
| 10709 | // get reference to parent of JSON pointer ptr |
| 10710 | const auto last_path = ptr.pop_back(); |
| 10711 | basic_json& parent = result[ptr]; |
| 10712 | |
| 10713 | switch (parent.m_type) { |
| 10714 | case value_t::null: |
| 10715 | case value_t::object: { |
| 10716 | // use operator[] to add value |
| 10717 | parent[last_path] = val; |
| 10718 | break; |
| 10719 | } |
| 10720 | |
| 10721 | case value_t::array: { |
| 10722 | if (last_path == "-") { |
| 10723 | // special case: append to back |
| 10724 | parent.push_back(val); |
| 10725 | } else { |
| 10726 | const auto idx = std::stoi(last_path); |
| 10727 | if (static_cast<size_type>(idx) > parent.size()) { |
| 10728 | // avoid undefined behavior |
| 10729 | JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + |
| 10730 | " is out of range")); |
| 10731 | } else { |
| 10732 | // default case: insert add offset |
| 10733 | parent.insert(parent.begin() + static_cast<difference_type>(idx), val); |
| 10734 | } |
| 10735 | } |
| 10736 | break; |
| 10737 | } |
| 10738 |