/// <summary> /// copy operation /// </summary> /// <param name="target">target JToken object</param> /// <param name="patch">json patch object</param> /// <returns>JToken result after the copy operation</returns> public static JToken Copy(JToken target, JObject patch) { if (patch["op"].Value <string>() != "copy") { return(target); } string from = patch["from"].Value <string>(); string path = patch["path"].Value <string>(); var jTokenPath = JsonPointer.ToJTokenPath(from); var jToken = target.SelectToken(jTokenPath); Patch addPatch = new Patch("add", null, path, jToken); Add(target, addPatch.Value); return(target); }
/// <summary> /// test operation /// </summary> /// <param name="target">target JToken object</param> /// <param name="patch">json patch object</param> /// <returns>throwing an InvalidOperationException indicate test fail, else success</returns> public static void Test(JToken target, JArray patches) { foreach (JObject patch in patches) { if (patch["op"].Value <string>() != "test") { throw new InvalidOperationException("Not a test operation: " + patch["op"].Value <string>()); } string path = patch["path"].Value <string>(); JToken value = patch["value"].Value <JToken>(); var jTokenPath = JsonPointer.ToJTokenPath(path); var jToken = target.SelectToken(jTokenPath); if (!jToken.Equals(value)) { throw new InvalidOperationException("Value at " + path + " does not match."); } } }
/// <summary> /// compare two JObjects,get all diff patches /// </summary> /// <param name="mirror">mirror/left Json Object</param> /// <param name="obj">object/right Json Object</param> /// <param name="patches">the array collection to store all diff patches</param> private void diffJObject(JObject mirror, JObject obj, JArray patches) { if (JToken.DeepEquals(mirror, obj)) { return; } IEnumerable <JProperty> newJProperties = obj.Properties(); IEnumerable <JProperty> oldJProperties = mirror.Properties(); foreach (JProperty jp in oldJProperties) { JToken oldValue = jp.Value; JToken newValue; if (OrdinalIgnoreCase) { newValue = obj.GetValue(jp.Name, StringComparison.OrdinalIgnoreCase); } else { newValue = obj.GetValue(jp.Name); } if (newValue == null) { string path = JsonPointer.ToJsonPointer(jp.Path); Patch patch = new Patch("remove", null, path, null); patches.Add(patch.Value); } else { string t = newValue.Type.ToString(); if ((newValue.Type == JTokenType.Object && oldValue.Type == JTokenType.Object)) { diffJObject((JObject)oldValue, (JObject)newValue, patches); } else if ((newValue.Type == JTokenType.Array && oldValue.Type == JTokenType.Array)) { JArray newArr = newValue as JArray; JArray oldArr = oldValue as JArray; if (NoOrderInBasicTypeValueJArray && IsNoDuplicateBasicTypeJArray(newArr) && IsNoDuplicateBasicTypeJArray(oldArr)) { diffJArrayNoOrder(oldArr, newArr, patches); } else { diffJArray(oldArr, newArr, patches); } } else { if (!JToken.DeepEquals(newValue, oldValue)) { string path = JsonPointer.ToJsonPointer(jp.Path); Patch patch = new Patch("replace", null, path, newValue); patches.Add(patch.Value); } } } } foreach (JProperty jp in newJProperties) { JToken newValue = jp.Value; JToken oldValue; if (OrdinalIgnoreCase) { oldValue = mirror.GetValue(jp.Name, StringComparison.OrdinalIgnoreCase); } else { oldValue = mirror.GetValue(jp.Name); } if (oldValue == null) { string path = JsonPointer.ToJsonPointer(jp.Path); Patch patch = new Patch("add", null, path, newValue); patches.Add(patch.Value); } } }
/// <summary> /// compare two JArrays, get get all diff patches /// </summary> /// <param name="mirror">mirror/left Json Array</param> /// <param name="obj">object/right Json Array</param> /// <param name="patches">the array collection to store all diff patches</param> private void diffJArray(JArray mirror, JArray obj, JArray patches) { if (NoOrderInBasicTypeValueJArray && IsNoDuplicateBasicTypeJArray(mirror) && IsNoDuplicateBasicTypeJArray(obj)) { diffJArrayNoOrder(mirror, obj, patches); return; } int oldObjArrSize = mirror.Count; int newObjArrSize = obj.Count; for (int i = 0; i < oldObjArrSize; i++) { JToken oldValue = mirror[i]; if (i < newObjArrSize) { JToken newValue = obj[i]; if ((newValue.Type == JTokenType.Object && oldValue.Type == JTokenType.Object)) { diffJObject((JObject)oldValue, (JObject)newValue, patches); } else if ((newValue.Type == JTokenType.Array && oldValue.Type == JTokenType.Array)) { JArray newArr = newValue as JArray; JArray oldArr = oldValue as JArray; if (NoOrderInBasicTypeValueJArray && IsNoDuplicateBasicTypeJArray(newArr) && IsNoDuplicateBasicTypeJArray(oldArr)) { diffJArrayNoOrder(oldArr, newArr, patches); } else { diffJArray(oldArr, newArr, patches); } } else { if (!JToken.DeepEquals(newValue, oldValue)) { string path = JsonPointer.ToJsonPointer(oldValue.Path); Patch patch = new Patch("replace", null, path, newValue); patches.Add(patch.Value); } } } else { string path = JsonPointer.ToJsonPointer(oldValue.Path); Patch patch = new Patch("remove", null, path, null); patches.Add(patch.Value); } } for (int i = 0; i < newObjArrSize; i++) { JToken newValue = obj[i]; if (i > oldObjArrSize - 1) { string path = JsonPointer.ToJsonPointer(newValue.Path); Patch patch = new Patch("add", null, path, newValue); patches.Add(patch.Value); } } }