| 202 | |
| 203 | template <typename Json> |
| 204 | Json from_diff(const Json& source, const Json& target, const typename Json::string_view_type& path) |
| 205 | { |
| 206 | using char_type = typename Json::char_type; |
| 207 | |
| 208 | Json result = typename Json::array(); |
| 209 | |
| 210 | if (source == target) |
| 211 | { |
| 212 | return result; |
| 213 | } |
| 214 | |
| 215 | if (source.is_array() && target.is_array()) |
| 216 | { |
| 217 | std::size_t common = (std::min)(source.size(),target.size()); |
| 218 | for (std::size_t i = 0; i < common; ++i) |
| 219 | { |
| 220 | std::basic_string<char_type> ss(path); |
| 221 | ss.push_back('/'); |
| 222 | jsoncons::from_integer(i,ss); |
| 223 | auto temp_diff = from_diff(source[i],target[i],ss); |
| 224 | result.insert(result.array_range().end(),temp_diff.array_range().begin(),temp_diff.array_range().end()); |
| 225 | } |
| 226 | // Element in source, not in target - remove |
| 227 | for (std::size_t i = source.size(); i-- > target.size();) |
| 228 | { |
| 229 | std::basic_string<char_type> ss(path); |
| 230 | ss.push_back('/'); |
| 231 | jsoncons::from_integer(i,ss); |
| 232 | Json val(json_object_arg); |
| 233 | val.insert_or_assign(jsonpatch_names<char_type>::op_name(), jsonpatch_names<char_type>::remove_name()); |
| 234 | val.insert_or_assign(jsonpatch_names<char_type>::path_name(), ss); |
| 235 | result.push_back(std::move(val)); |
| 236 | } |
| 237 | // Element in target, not in source - add, |
| 238 | // Fix contributed by Alexander rog13 |
| 239 | for (std::size_t i = source.size(); i < target.size(); ++i) |
| 240 | { |
| 241 | const auto& a = target[i]; |
| 242 | std::basic_string<char_type> ss(path); |
| 243 | ss.push_back('/'); |
| 244 | jsoncons::from_integer(i,ss); |
| 245 | Json val(json_object_arg); |
| 246 | val.insert_or_assign(jsonpatch_names<char_type>::op_name(), jsonpatch_names<char_type>::add_name()); |
| 247 | val.insert_or_assign(jsonpatch_names<char_type>::path_name(), ss); |
| 248 | val.insert_or_assign(jsonpatch_names<char_type>::value_name(), a); |
| 249 | result.push_back(std::move(val)); |
| 250 | } |
| 251 | } |
| 252 | else if (source.is_object() && target.is_object()) |
| 253 | { |
| 254 | for (const auto& a : source.object_range()) |
| 255 | { |
| 256 | std::basic_string<char_type> ss(path); |
| 257 | ss.push_back('/'); |
| 258 | jsonpointer::escape(a.key(),ss); |
| 259 | auto it = target.find(a.key()); |
| 260 | if (it != target.object_range().end()) |
| 261 | { |