static void _Flatten(string parentKey, JsonElement parentValue, JsonDocumentBuilder result) { switch (parentValue.ValueKind) { case JsonValueKind.Array: { if (parentValue.GetArrayLength() == 0) { result.AddProperty(parentKey, new JsonDocumentBuilder(parentValue)); } else { for (int i = 0; i < parentValue.GetArrayLength(); ++i) { var buffer = new StringBuilder(parentKey); buffer.Append('/'); buffer.Append(i.ToString()); _Flatten(buffer.ToString(), parentValue[i], result); } } break; } case JsonValueKind.Object: { if (parentValue.EnumerateObject().Count() == 0) { result.AddProperty(parentKey, new JsonDocumentBuilder(parentValue)); } else { foreach (var item in parentValue.EnumerateObject()) { var buffer = new StringBuilder(parentKey); buffer.Append('/'); buffer.Append(JsonPointer.Escape(item.Name)); _Flatten(buffer.ToString(), item.Value, result); } } break; } default: { result.AddProperty(parentKey, new JsonDocumentBuilder(parentValue)); break; } } }
static JsonDocumentBuilder _FromDiff(JsonElement source, JsonElement target, string path) { var builder = new JsonDocumentBuilder(JsonValueKind.Array); JsonElementEqualityComparer comparer = JsonElementEqualityComparer.Instance; if (comparer.Equals(source, target)) { return(builder); } if (source.ValueKind == JsonValueKind.Array && target.ValueKind == JsonValueKind.Array) { int common = Math.Min(source.GetArrayLength(), target.GetArrayLength()); for (int i = 0; i < common; ++i) { var buffer = new StringBuilder(path); buffer.Append("/"); buffer.Append(i.ToString()); var temp_diff = _FromDiff(source[i], target[i], buffer.ToString()); foreach (var item in temp_diff.EnumerateArray()) { builder.AddArrayItem(item); } } // Element in source, not in target - remove for (int i = source.GetArrayLength(); i-- > target.GetArrayLength();) { var buffer = new StringBuilder(path); buffer.Append("/"); buffer.Append(i.ToString()); var valBuilder = new JsonDocumentBuilder(JsonValueKind.Object); valBuilder.AddProperty("op", new JsonDocumentBuilder("remove")); valBuilder.AddProperty("path", new JsonDocumentBuilder(buffer.ToString())); builder.AddArrayItem(valBuilder); } // Element in target, not in source - add, for (int i = source.GetArrayLength(); i < target.GetArrayLength(); ++i) { var a = target[i]; var buffer = new StringBuilder(path); buffer.Append("/"); buffer.Append(i.ToString()); var valBuilder = new JsonDocumentBuilder(JsonValueKind.Object); valBuilder.AddProperty("op", new JsonDocumentBuilder("add")); valBuilder.AddProperty("path", new JsonDocumentBuilder(buffer.ToString())); valBuilder.AddProperty("value", new JsonDocumentBuilder(a)); builder.AddArrayItem(valBuilder); } } else if (source.ValueKind == JsonValueKind.Object && target.ValueKind == JsonValueKind.Object) { foreach (var a in source.EnumerateObject()) { var buffer = new StringBuilder(path); buffer.Append("/"); buffer.Append(JsonPointer.Escape(a.Name)); JsonElement element; if (target.TryGetProperty(a.Name, out element)) { var temp_diff = _FromDiff(a.Value, element, buffer.ToString()); foreach (var item in temp_diff.EnumerateArray()) { builder.AddArrayItem(item); } } else { var valBuilder = new JsonDocumentBuilder(JsonValueKind.Object); valBuilder.AddProperty("op", new JsonDocumentBuilder("remove")); valBuilder.AddProperty("path", new JsonDocumentBuilder(buffer.ToString())); builder.AddArrayItem(valBuilder); } } foreach (var a in target.EnumerateObject()) { JsonElement element; if (!source.TryGetProperty(a.Name, out element)) { var buffer = new StringBuilder(path); buffer.Append("/"); buffer.Append(JsonPointer.Escape(a.Name)); var valBuilder = new JsonDocumentBuilder(JsonValueKind.Object); valBuilder.AddProperty("op", new JsonDocumentBuilder("add")); valBuilder.AddProperty("path", new JsonDocumentBuilder(buffer.ToString())); valBuilder.AddProperty("value", new JsonDocumentBuilder(a.Value)); builder.AddArrayItem(valBuilder); } } } else { var valBuilder = new JsonDocumentBuilder(JsonValueKind.Object); valBuilder.AddProperty("op", new JsonDocumentBuilder("replace")); valBuilder.AddProperty("path", new JsonDocumentBuilder(path)); valBuilder.AddProperty("value", new JsonDocumentBuilder(target)); builder.AddArrayItem(valBuilder); } return(builder); }