比较两个 JSON 对象并返回一个包含差异列表的 JSON 对象 c# [重复]

问题描述 投票:0回答:2

我正在将视图模型转换为 JSON 对象并插入到数据库中。

现在我想从数据库中选择任意两个 JSON 对象并比较两个 JSON 对象,看看属性值是否有任何变化并返回它们之间的差异列表。所以我在 C# 中寻找一个比较两个 JSON 对象的函数,并返回一个包含差异列表的 JSON 对象,如果可能的话还有更多数据,例如覆盖率指标。有人可以帮我吗。

例子:

var json1 = @"{ ""name"": ""JohnRob", ""昵称"":""约翰", ""年龄"": 20, “”已婚“”:假 }”;

var json2 = @"{ ""name"": ""JohnRob", ""昵称"":""约翰", ""年龄"": 22, “”已婚“”:真实 }”;

结果:输出应该是这样的

{ “年龄”:[ 20, 22 ], “已婚”:[ 错误的, 真的 ] }

c# json asp.net-mvc json-deserialization jsonserializer
2个回答
0
投票

答案将取决于您要使用哪个 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();
}

0
投票

这里的上一个线程讨论了一个 diff 程序为此称为 jsondiffpatch。看起来它可以满足您的需求。它是主要对象,让您将左右 json 传递给 diff。

通话格式只是

jdp.Patch(左,补丁);

© www.soinside.com 2019 - 2024. All rights reserved.