TemplateMerger.cs
using System.Collections.Generic;
using System.Linq; using Newtonsoft.Json.Linq; namespace APIManagementTemplate { public class TemplateMerger { /// <summary> /// Merges the changes in the newObject into the oldObject. /// Please not that the contents of oldObject is changed! /// </summary> /// <param name="oldObject">The old object. The contents of this parameter is changed by this function</param> /// <param name="newObject">The new object.</param> /// <returns></returns> public static JObject Merge(JObject oldObject, JObject newObject) { foreach (KeyValuePair<string, JToken> pair in newObject) { if (oldObject[pair.Key] != null) { if (pair.Value is JArray newArray && oldObject[pair.Key] is JArray oldArray) { foreach (var item in newArray) { if (item is JValue) { if (oldArray.All(x => !JToken.EqualityComparer.Equals(x, item))) oldArray.Add(item); } else if (item is JObject) { var oldItem = oldArray.OfType<JObject>().FirstOrDefault(x => SameIdentity(x, item, pair.Key)); if (oldItem == null) { if (oldArray.OfType<JObject>().Any(x => JToken.EqualityComparer.Equals(x, item))) continue; } if (oldItem == null) oldArray.Add(item); else { Merge(oldItem, (JObject)item); } } } } else if (pair.Value is JObject && oldObject[pair.Key] is JObject) { Merge((JObject)oldObject[pair.Key], (JObject)pair.Value); } else if(pair.Value is JValue && oldObject[pair.Key] is JValue) { oldObject[pair.Key] = pair.Value; } } else oldObject[pair.Key] = pair.Value; } return oldObject; } public static bool SameIdentity(JToken x, JToken y, string parent) { if (x == null || y == null) return false; switch (parent.ToLower()) { case "resources": return JTokenEqualsOnProperties(x, y, "name", "type"); case "responses": return JTokenEqualsOnProperties(x, y, "statusCode"); case "representations": return JTokenEqualsOnProperties(x, y, "contentType"); case "templateparameters": return JTokenEqualsOnProperties(x, y, "name"); default: return JToken.EqualityComparer.Equals(x, y); } } private static bool JTokenEqualsOnProperties(JToken x, JToken y, params string[] properties) { if (properties.Any(p => x.Value<string>(p) == null || y.Value<string>(p) == null)) return false; return properties.All(p => x.Value<string>(p) == y.Value<string>(p)); } } } |