The answer will depend on which JSON library you want to use and whether you want to handle the nested properties of complex json objects, or whether it is sufficient to go through the list of properties of the main object.
For example, if you use the Newtonsoft.Json
library and only compare first-level properties, this code would be enough:
public static JObject CompareJsonObjects(string json1, string json2)
{
var obj1 = JObject.Parse(json1);
var obj2 = JObject.Parse(json2);
var diff = new JObject();
foreach (var property in obj1)
{
var value1 = property.Value;
if (obj2.TryGetValue(property.Key, out var value2))
if (!JToken.DeepEquals(value1, value2))
diff[property.Key] = new JArray(value1, value2);
else
diff[property.Key] = new JArray(value1, null);
}
foreach (var property in obj2)
if (!obj1.ContainsKey(property.Key))
diff[property.Key] = new JArray(null, property.Value);
return diff;
}
The common strategy is to go through each property of the first JSON, find the corresponding property of the second JSON by its key, compare them and, if they are different, write them into the result. Do the same if there is no corresponding property of the second object. Similarly, the properties of the second object, which may not exist in the first object, must be handled similarly.
If you use a more modern System.Text.Json
and need to recursively check and compare properties of complex objects, the code will be different. We will use similar strategy but recursively.
public static JsonElement CompareJsonObjects(string json1, string json2)
{
using var doc1 = JsonDocument.Parse(json1);
using var doc2 = JsonDocument.Parse(json2);
var obj1 = doc1.RootElement;
var obj2 = doc2.RootElement;
return CompareJsonElements(obj1, obj2);
}
private static JsonElement CompareJsonElements(JsonElement elem1, JsonElement elem2)
{
if (elem1.ValueKind != elem2.ValueKind)
return CreateDifferenceArray(elem1, elem2);
switch (elem1.ValueKind)
{
case JsonValueKind.Object:
var result = new Dictionary<string, JsonElement>();
foreach (var prop in elem1.EnumerateObject())
if (elem2.TryGetProperty(prop.Name, out var value2))
{
var diff = CompareJsonElements(prop.Value, value2);
if (diff.ValueKind != JsonValueKind.Undefined)
result.Add(prop.Name, diff);
}
else
result.Add(prop.Name, CreateDifferenceArray(prop.Value, default));
foreach (var prop in elem2.EnumerateObject().Where(prop => !elem1.TryGetProperty(prop.Name, out _)))
result.Add(prop.Name, CreateDifferenceArray(default, prop.Value));
return JsonElementFromObject(result);
case JsonValueKind.Array:
var areArraysEqual = elem1.GetArrayLength() == elem2.GetArrayLength();
if (areArraysEqual)
for (var i = 0; i < elem1.GetArrayLength(); i++)
if (!elem1[i].Equals(elem2[i]))
{
areArraysEqual = false;
break;
}
return areArraysEqual ? default : CreateDifferenceArray(elem1, elem2);
default:
return elem1.Equals(elem2) ? default : CreateDifferenceArray(elem1, elem2);
}
}
private static JsonElement CreateDifferenceArray(JsonElement elem1, JsonElement elem2)
{
var array = new JsonElement[] { elem1, elem2 };
return JsonElementFromObject(array);
}
private static JsonElement JsonElementFromObject(object obj)
{
var jsonString = JsonSerializer.Serialize(obj);
using var doc = JsonDocument.Parse(jsonString);
return doc.RootElement.Clone();
}