You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中无法正确比对两个JSON,多变更场景下报错求助

JSON差异对比与提取需求(C#实现)

我有两个JSON字符串,分别为left(原始JSON)和right(编辑后JSON)。需要找出两者的差异,并生成仅包含变更内容及指定键“ID”和“TYPE”的新JSON。尝试在C#中使用JsonDiffPatchDotNet和JsonDiffer包,但未能实现需求,寻求解决方案。

引用的包

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using JsonDiffPatchDotNet;
using JsonDiffer;

JSON压缩代码

public static string Minify(string json)
{
    if (json == null)
    {
        throw new ArgumentNullException(nameof(json));
    }

    return Regex.Replace(json, "(\"(?:[^\\\"]|\\.)*\")|\\s+", "$1");
}

主逻辑代码

public static void Main(string[] args)
{
    string Tleft = @"{
            ""TEST JSON"" : ""JSON"",
            ""JSON"":{
                        ""ANIMALS"":[
                            {
                        ""ID"":0,
                                ""TYPE"":""DOG"",
                                ""DOG"":{
                            ""TYPE"":""RETRIEVER"",
                                    ""RETRIEVER"":{
                                ""NAME"":""LEO"",
                                        ""AGE"":3,
                                        ""YEARS"":[2019 , 2020, 2021],
                                ""WEIGHTS"": [2,10,13]
                }
                },
                        ""REMARKS"":{
                            ""ID"":1,
                            ""STATUS"":""GOOD"",
                            ""REFERENCE"": {
                                ""SOURCE"": ""XYZ"",
                                ""FIT"":  1,
                                ""BMI"" : 1
                            }
                        }
                    },
                    {
                        ""ID"":1,
                        ""TYPE"":""DOG2"",
                        ""DOG2"":{
                            ""TYPE"":""PUG"",
                            ""RETRIEVER"":{
                                ""NAME"":""HUTCH"",
                                ""AGE"":4,
                                ""YEARS"":[2019 , 2020, 2021, 2022],
                                ""WEIGHTS"": [2,3,4,4]
                            }
                        },
                        ""REMARKS"":{
                            ""ID"":1,
                            ""TYPE"" : ""REFERENCE"",
                            ""STATUS"":""GOOD"",
                            ""REFERENCE"": {
                                ""SOURCE"": ""XYZ"",
                                ""FIT"":  1,
                                ""BMI"" : 1
                            }
                        }
                    },
                    {
                        ""ID"": 2,
                        ""TYPE"": ""DIAGNOSTICS"",
                        ""STATUS"": ""ENABLED""
                    },
                    {
                        ""ID"": 3,
                        ""TYPE"": ""ORGANISATION"",
                        ""ORGANISATION"":{
                            ""NAME"":""RED CROSS"",
                            ""YEAR"": 2023
                        }
                    }
                ]
            }
        }";

    string Tright = @"{
            ""TEST JSON"" : ""JSON"",
            ""JSON"":{
                        ""ANIMALS"":[
                            {
                        ""ID"":0,
                                ""TYPE"":""DOG"",
                                ""DOG"":{
                            ""TYPE"":""RETRIEVER"",
                                    ""RETRIEVER"":{
                                ""NAME"":""LEO"",
                                        ""AGE"":3,
                                        ""YEARS"":[2019 , 2020, 2021],
                                ""WEIGHTS"": [2,10,13]
                }
                },
                        ""REMARKS"":{
                            ""ID"":1,
                            ""STATUS"":""GOOD"",
                            ""REFERENCE"": {
                                ""SOURCE"": ""XYZ"",
                                ""FIT"":  1,
                                ""BMI"" : 1
                            }
                        }
                    },
                    {
                        ""ID"":1,
                        ""TYPE"":""DOG2"",
                        ""DOG2"":{
                            ""TYPE"":""PUG"",
                            ""RETRIEVER"":{
                                ""NAME"":""HUTCH"",
                                ""AGE"":4,
                                ""YEARS"":[2019 , 2020, 2021, 2022],
                                ""WEIGHTS"": [2,3,4,4]
                            }
                        },
                        ""REMARKS"":{
                            ""ID"":1,
                            ""TYPE"" : ""REFERENCE"",
                            ""STATUS"":""GOOD"",
                            ""REFERENCE"": {
                                ""SOURCE"": ""XYZ"",
                                ""FIT"":  1,
                                ""BMI"" : 1
                            }
                        }
                    },
                    {
                        ""ID"": 2,
                        ""TYPE"": ""DIAGNOSTICS"",
                        ""STATUS"": ""ENABLED ZZZ""
                    },
                    {
                        ""ID"": 3,
                        ""TYPE"": ""ORGANISATION"",
                        ""ORGANISATION"":{
                            ""NAME"":""RED CROSS ZZZ"",
                            ""YEAR"": 2023
                        }
                    }
                ]
            }
        }";

    var left = JToken.Parse(Minify(Tleft));
    var right = JToken.Parse(Minify(Tright));
    var jdp = new JsonDiffPatch();

    // 使用JsonDiffPatchDotNet包生成差异
    var diff2 = JsonDifferentiator.Differentiate(left, right, OutputMode.Symbol, showOriginalValues: true);


    Console.WriteLine("--------------------------------------");
    Console.WriteLine("----diff using JsonDiffPatchDotNet----");
    Console.WriteLine("--------------------------------------");
    Console.WriteLine(diff2);
    Console.WriteLine("***************************************");
    Console.WriteLine("***************************************\n\n");

    if (diff2 != null)
    {
        // 移除差异结果中的*字符
        var formatedDiff = JToken.Parse(diff2.ToString().Replace("*", ""));
        
        // 应用补丁
        // 当变更超过3个不同索引时会报错
        var Diff2PatchOutput = jdp.Patch(left, formatedDiff).ToString();

        Console.WriteLine("--------------------------------------");
        Console.WriteLine("---------- CURRENT OUTPUT --------");
        Console.WriteLine("--------------------------------------");
        Console.WriteLine(Diff2PatchOutput);
        Console.WriteLine("***************************************");
        Console.WriteLine("***************************************\n\n");
    }
    else
    {
        Console.WriteLine("Diff failed  or Invalid json inputs left and rigth !");
    }
}

当前输出

--------------------------------------
----diff using JsonDiffPatchDotNet----
--------------------------------------
{
  "*JSON": {
    "*ANIMALS": [
      {
        "*STATUS": "ENABLED ZZZ"
      },
      {
        "*ORGANISATION": {
          "*NAME": "RED CROSS ZZZ"
        }
      }
    ]
  }
}
***************************************
***************************************


--------------------------------------
---------- CURRENT OUTPUT --------
--------------------------------------
{
  "TEST JSON": "JSON",
  "JSON": {
    "ANIMALS": {
      "ORGANISATION": {
        "NAME": "RED CROSS ZZZ"
      }
    }
  }
}
***************************************
***************************************

期望输出

--------------------------------------
---------- EXPECTED OUTPUT --------
--------------------------------------
{
  "TEST JSON": "JSON",
  "JSON": {
    "ANIMALS": [
      {
        "ID": 2,
        "TYPE": "DIAGNOSTICS",
        "STATUS": "ENABLED ZZZ"
      },
      {
        "ID": 3,
        "TYPE": "ORGANISATION",
        "ORGANISATION": {
          "NAME": "RED CROSS ZZZ"
        }
      }
    ]
  }
}
***************************************
***************************************

存在的问题

  • 当变更发生在JSON数组的不同索引中时,第一个变更会被忽略;
  • 当变更超过3个不同索引时,抛出错误:
System.IO.InvalidDataException
        HResult = 0x80131501
        Message = Invalid patch object
        Source = JsonDiffPatchDotNet
        StackTrace:
                at JsonDiffPatchDotNet.JsonDiffPatch.Patch(JToken left, JToken patch)
                at JsonDiffPatchDotNet.JsonDiffPatch.ObjectPatch(JObject obj, JObject patch)
                at JsonDiffPatchDotNet.JsonDiffPatch.Patch(JToken left, JToken patch)
                at JsonDiffPatchDotNet.JsonDiffPatch.ObjectPatch(JObject obj, JObject patch)
                at JsonDiffPatchDotNet.JsonDiffPatch.Patch(JToken left, JToken patch)

欢迎提出其他实现思路。

内容的提问来源于stack exchange,提问作者DeLorean

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 13:40:34