! @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
| 10391 | @since version 2.0.0 |
| 10392 | */ |
| 10393 | static basic_json diff(const basic_json& source, |
| 10394 | const basic_json& target, |
| 10395 | const std::string& path = "") |
| 10396 | { |
| 10397 | // the patch |
| 10398 | basic_json result(value_t::array); |
| 10399 | |
| 10400 | // if the values are the same, return empty patch |
| 10401 | if (source == target) |
| 10402 | { |
| 10403 | return result; |
| 10404 | } |
| 10405 | |
| 10406 | if (source.type() != target.type()) |
| 10407 | { |
| 10408 | // different types: replace value |
| 10409 | result.push_back( |
| 10410 | { |
| 10411 | {"op", "replace"}, |
| 10412 | {"path", path}, |
| 10413 | {"value", target} |
| 10414 | }); |
| 10415 | } |
| 10416 | else |
| 10417 | { |
| 10418 | switch (source.type()) |
| 10419 | { |
| 10420 | case value_t::array: |
| 10421 | { |
| 10422 | // first pass: traverse common elements |
| 10423 | size_t i = 0; |
| 10424 | while (i < source.size() and i < target.size()) |
| 10425 | { |
| 10426 | // recursive call to compare array values at index i |
| 10427 | auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); |
| 10428 | result.insert(result.end(), temp_diff.begin(), temp_diff.end()); |
| 10429 | ++i; |
| 10430 | } |
| 10431 | |
| 10432 | // i now reached the end of at least one array |
| 10433 | // in a second pass, traverse the remaining elements |
| 10434 | |
| 10435 | // remove my remaining elements |
| 10436 | const auto end_index = static_cast<difference_type>(result.size()); |
| 10437 | while (i < source.size()) |
| 10438 | { |
| 10439 | // add operations in reverse order to avoid invalid |
| 10440 | // indices |
| 10441 | result.insert(result.begin() + end_index, object( |
| 10442 | { |
| 10443 | {"op", "remove"}, |
| 10444 | {"path", path + "/" + std::to_string(i)} |
| 10445 | })); |
| 10446 | ++i; |
| 10447 | } |
| 10448 | |
| 10449 | // add other remaining elements |
| 10450 | while (i < target.size()) |