// unflatten static JsonDocumentBuilder SafeUnflatten(JsonDocumentBuilder value) { if (value.ValueKind != JsonValueKind.Object || value.GetObjectLength() == 0) { return value; } bool safe = true; int index = 0; foreach (var item in value.EnumerateObject()) { int n; if (!int.TryParse(item.Key, out n) || index++ != n) { safe = false; break; } } if (safe) { var j = new JsonDocumentBuilder(JsonValueKind.Array); foreach (var item in value.EnumerateObject()) { j.AddArrayItem(item.Value); } var a = new JsonDocumentBuilder(JsonValueKind.Array); foreach (var item in j.EnumerateArray()) { a.AddArrayItem(SafeUnflatten(item)); } return a; } else { var o = new JsonDocumentBuilder(JsonValueKind.Object); foreach (var item in value.EnumerateObject()) { //if (!o.ContainsPropertyName(item.Key)) //{ // o.AddProperty(item.Key, SafeUnflatten (item.Value)); //} o.TryAddProperty(item.Key, SafeUnflatten (item.Value)); } return o; } }
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); }
public static bool TryAdd(this JsonPointer location, ref JsonDocumentBuilder root, JsonDocumentBuilder value) { JsonDocumentBuilder current = root; string token = ""; var enumerator = location.GetEnumerator(); bool more = enumerator.MoveNext(); if (!more) { return(false); } while (more) { token = enumerator.Current; more = enumerator.MoveNext(); if (more) { if (!TryResolve(token, current, out current)) { return(false); } } } if (current.ValueKind == JsonValueKind.Array) { if (token.Length == 1 && token[0] == '-') { current.AddArrayItem(value); current = current[current.GetArrayLength() - 1]; } else { int index; if (!int.TryParse(token, out index)) { return(false); } if (index > current.GetArrayLength()) { return(false); } if (index == current.GetArrayLength()) { current.AddArrayItem(value); current = value; } else { current.InsertArrayItem(index, value); current = value; } } } else if (current.ValueKind == JsonValueKind.Object) { if (current.ContainsPropertyName(token)) { current.RemoveProperty(token); } current.AddProperty(token, value); current = value; } else { return(false); } return(true); }
static bool TryUnflattenArray(JsonElement value, out JsonDocumentBuilder result) { if (value.ValueKind != JsonValueKind.Object) { throw new ArgumentException("The value to unflatten is not a JSON object"); } result = new JsonDocumentBuilder(JsonValueKind.Object); foreach (var item in value.EnumerateObject()) { JsonDocumentBuilder? parent = null; JsonDocumentBuilder part = result; int parentIndex = 0; string parentName = ""; JsonPointer ptr; if (!JsonPointer.TryParse(item.Name, out ptr)) { throw new ArgumentException("Name contains invalid JSON Pointer"); } int index = 0; var it = ptr.GetEnumerator(); bool more = it.MoveNext(); while (more) { string token = it.Current; int n; if (int.TryParse(token, out n) && index++ == n) { if (part.ValueKind != JsonValueKind.Array) { if (parent != null && parent.ValueKind == JsonValueKind.Object) { parent.RemoveProperty(parentName); var val = new JsonDocumentBuilder(JsonValueKind.Array); parent.AddProperty(parentName, val); part = val; } else if (parent != null && parent.ValueKind == JsonValueKind.Array) { var val = new JsonDocumentBuilder(JsonValueKind.Array); parent[parentIndex] = val; part = val; } else { return false; } } parent = part; parentIndex = n; parentName = token; more = it.MoveNext(); if (more) { if (n >= part.GetArrayLength()) { part.AddArrayItem(new JsonDocumentBuilder(JsonValueKind.Object)); part = part[part.GetArrayLength() - 1]; } else { part = part[n]; } } else { part.AddArrayItem(new JsonDocumentBuilder(item.Value)); part = part[part.GetArrayLength() - 1]; } } else if (part.ValueKind == JsonValueKind.Object) { more = it.MoveNext(); if (more) { JsonDocumentBuilder val; if (part.TryGetProperty(token, out val)) { part = val; } else { val = new JsonDocumentBuilder(JsonValueKind.Object); part.AddProperty(token,val); part = val; } } else { JsonDocumentBuilder val; if (part.TryGetProperty(token, out val)) { part = val; } else { val = new JsonDocumentBuilder(item.Value); part.AddProperty(token,val); part = val; } } } else { return false; } } } return true; }