我正在将视图模型转换为 JSON 对象并插入到数据库中。
现在我想从数据库中选择任意两个 JSON 对象并比较两个 JSON 对象,看看属性值是否有任何变化并返回它们之间的差异列表。所以我在 C# 中寻找一个比较两个 JSON 对象的函数,并返回一个包含差异列表的 JSON 对象,如果可能的话还有更多数据,例如覆盖率指标。有人可以帮我吗。
例子:
var json1 = @"{ ""name"": ""JohnRob", ""昵称"":""约翰", ""年龄"": 20, “”已婚“”:假 }”;
var json2 = @"{ ""name"": ""JohnRob", ""昵称"":""约翰", ""年龄"": 22, “”已婚“”:真实 }”;
结果:输出应该是这样的
{ “年龄”:[ 20, 22 ], “已婚”:[ 错误的, 真的 ] }
答案将取决于您要使用哪个 JSON 库以及您是否要处理复杂 json 对象的嵌套属性,或者遍历主要对象的属性列表是否足够。
Newtonsoft.Json
库,只比较一级属性,这段代码就足够了:
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;
}
常见的策略是遍历第一个JSON的每个属性,通过key找到第二个JSON对应的属性,比较它们,如果不同,则写入结果。如果第二个对象没有相应的属性,则执行相同的操作。同样,第二个对象的属性,可能不存在于第一个对象中,必须类似地处理。
System.Text.Json
并且需要递归检查和比较复杂对象的属性,代码会有所不同。我们将使用类似的策略,但递归地。
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();
}
这里的上一个线程讨论了一个 diff 程序为此称为 jsondiffpatch。看起来它可以满足您的需求。它是主要对象,让您将左右 json 传递给 diff。
通话格式只是
jdp.Patch(左,补丁);