! @brief creates a diff as a JSON patch Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can be changed into the value @a target by calling @ref patch function. @invariant For two JSON values @a source and @a target, the following code yields always `true`: @code {.cpp} source.patch(diff(source, target)) == target; @endcode @note Currently
| 22403 | @since version 2.0.0 |
| 22404 | */ |
| 22405 | JSON_HEDLEY_WARN_UNUSED_RESULT |
| 22406 | static basic_json diff(const basic_json& source, const basic_json& target, |
| 22407 | const std::string& path = "") |
| 22408 | { |
| 22409 | // the patch |
| 22410 | basic_json result(value_t::array); |
| 22411 | |
| 22412 | // if the values are the same, return empty patch |
| 22413 | if (source == target) |
| 22414 | { |
| 22415 | return result; |
| 22416 | } |
| 22417 | |
| 22418 | if (source.type() != target.type()) |
| 22419 | { |
| 22420 | // different types: replace value |
| 22421 | result.push_back( |
| 22422 | { |
| 22423 | {"op", "replace"}, {"path", path}, {"value", target} |
| 22424 | }); |
| 22425 | return result; |
| 22426 | } |
| 22427 | |
| 22428 | switch (source.type()) |
| 22429 | { |
| 22430 | case value_t::array: |
| 22431 | { |
| 22432 | // first pass: traverse common elements |
| 22433 | std::size_t i = 0; |
| 22434 | while (i < source.size() and i < target.size()) |
| 22435 | { |
| 22436 | // recursive call to compare array values at index i |
| 22437 | auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); |
| 22438 | result.insert(result.end(), temp_diff.begin(), temp_diff.end()); |
| 22439 | ++i; |
| 22440 | } |
| 22441 | |
| 22442 | // i now reached the end of at least one array |
| 22443 | // in a second pass, traverse the remaining elements |
| 22444 | |
| 22445 | // remove my remaining elements |
| 22446 | const auto end_index = static_cast<difference_type>(result.size()); |
| 22447 | while (i < source.size()) |
| 22448 | { |
| 22449 | // add operations in reverse order to avoid invalid |
| 22450 | // indices |
| 22451 | result.insert(result.begin() + end_index, object( |
| 22452 | { |
| 22453 | {"op", "remove"}, |
| 22454 | {"path", path + "/" + std::to_string(i)} |
| 22455 | })); |
| 22456 | ++i; |
| 22457 | } |
| 22458 | |
| 22459 | // add other remaining elements |
| 22460 | while (i < target.size()) |
| 22461 | { |
| 22462 | result.push_back( |