! @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
| 8744 | @since version 2.0.0 |
| 8745 | */ |
| 8746 | JSON_HEDLEY_WARN_UNUSED_RESULT |
| 8747 | static basic_json diff(const basic_json& source, const basic_json& target, |
| 8748 | const std::string& path = "") |
| 8749 | { |
| 8750 | // the patch |
| 8751 | basic_json result(value_t::array); |
| 8752 | |
| 8753 | // if the values are the same, return empty patch |
| 8754 | if (source == target) |
| 8755 | { |
| 8756 | return result; |
| 8757 | } |
| 8758 | |
| 8759 | if (source.type() != target.type()) |
| 8760 | { |
| 8761 | // different types: replace value |
| 8762 | result.push_back( |
| 8763 | { |
| 8764 | {"op", "replace"}, {"path", path}, {"value", target} |
| 8765 | }); |
| 8766 | return result; |
| 8767 | } |
| 8768 | |
| 8769 | switch (source.type()) |
| 8770 | { |
| 8771 | case value_t::array: |
| 8772 | { |
| 8773 | // first pass: traverse common elements |
| 8774 | std::size_t i = 0; |
| 8775 | while (i < source.size() && i < target.size()) |
| 8776 | { |
| 8777 | // recursive call to compare array values at index i |
| 8778 | auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); |
| 8779 | result.insert(result.end(), temp_diff.begin(), temp_diff.end()); |
| 8780 | ++i; |
| 8781 | } |
| 8782 | |
| 8783 | // i now reached the end of at least one array |
| 8784 | // in a second pass, traverse the remaining elements |
| 8785 | |
| 8786 | // remove my remaining elements |
| 8787 | const auto end_index = static_cast<difference_type>(result.size()); |
| 8788 | while (i < source.size()) |
| 8789 | { |
| 8790 | // add operations in reverse order to avoid invalid |
| 8791 | // indices |
| 8792 | result.insert(result.begin() + end_index, object( |
| 8793 | { |
| 8794 | {"op", "remove"}, |
| 8795 | {"path", path + "/" + std::to_string(i)} |
| 8796 | })); |
| 8797 | ++i; |
| 8798 | } |
| 8799 | |
| 8800 | // add other remaining elements |
| 8801 | while (i < target.size()) |
| 8802 | { |
| 8803 | result.push_back( |