14

例如,如果我有以下 json 文本:

 object1{
     field1: value1;
     field2: value2;
     field3: value3;
 }

 object1{
     field1: value1;
     field2: newvalue2;
     field3: value3;
 }

我需要 c# 中的一些东西来读取该文件并显示差异。即它可以返回以下对象:

differences {
    object1: { field: field2, old_value: value2, new_value: newvalue2}
}

是否有一些 API 或建议可以做到这一点?

4

3 回答 3

5

我建议您使用弱类型 JSON 序列化并编写一个使用JsonObject的例程,如下所示:

String JsonDifferenceReport(String objectName,
                            JsonObject first,
                            JsonObject second)
{
  if(String.IsNullOrEmpty(objectName))
    throw new ArgumentNullException("objectName");
  if(null==first)
    throw new ArgumentNullException("first");
  if(null==second)
    throw new ArgumentNullException("second");
  List<String> allKeys = new List<String>();
  foreach(String key in first.Keys)
    if (!allKeys.Any(X => X.Equals(key))) allKeys.Add(key);
  foreach(String key in second.Keys)
    if (!allKeys.Any(X => X.Equals(key))) allKeys.Add(key);
  String results = String.Empty;
  foreach(String key in allKeys)
  {
    JsonValue v1 = first[key];
    JsonValue v1 = second[key];
    if (((null==v1) != (null==v2)) || !v1.Equals(v2))
    {
      if(String.IsNullOrEmpty(results))
      {
         results = "differences: {\n";
      }
      results += "\t" + objectName + ": {\n";
      results += "\t\tfield: " + key + ",\n";
      results += "\t\toldvalue: " + (null==v1)? "null" : v1.ToString() + ",\n";
      results += "\t\tnewvalue: " + (null==v2)? "null" : v2.ToString() + "\n";
      results += "\t}\n";
    }
  }
  if(!String.IsNullOrEmpty(results))
  {
    results += "}\n";
  }
  return results;
}

您可以选择是否在 v1 和 v2 中以递归方式获取报告JsonValue,而不是像我在这里所做的那样仅使用它们的字符串表示。

如果你想递归,它可能会像这样改变上面的内容:

  if ((null==v1) || (v1.JsonType == JsonType.JsonPrimitive)
   || (null==v2) || (v2.JsonType == JsonType.JsonPrimitive))
  {
    results += "\t\tfield: " + key + ",\n";
    results += "\t\toldvalue: " + (null==v1) ? "null" : v1.ToString() + ",\n";
    results += "\t\tnewvalue: " + (null==v2) ? "null" : v2.ToString() + "\n";
  }
  else
  {
    results + JsonDifferenceReport(key, v1, v2);
  }

-杰西

于 2012-06-17T17:18:30.760 回答
1

由于某种原因,我无法在我的 Web API 项目中使用 JsonObject。我使用了 JSON.Net,下面是我获取差异的方法。它将给出差异数组。

private static string GetJsonDiff(string action, string existing, string modified, string objectType)
    {
        // convert JSON to object
        JObject xptJson = JObject.Parse(modified);
        JObject actualJson = JObject.Parse(existing);

        // read properties
        var xptProps = xptJson.Properties().ToList();
        var actProps = actualJson.Properties().ToList();

        // find differing properties
        var auditLog = (from existingProp in actProps
            from modifiedProp in xptProps
            where modifiedProp.Path.Equals(existingProp.Path)
            where !modifiedProp.Value.Equals(existingProp.Value)
            select new AuditLog
            {
                Field = existingProp.Path,
                OldValue = existingProp.Value.ToString(),
                NewValue = modifiedProp.Value.ToString(),
                Action = action, ActionBy = GetUserName(),
                ActionDate = DateTime.UtcNow.ToLongDateString(),
                ObjectType = objectType
            }).ToList();

        return JsonConvert.SerializeObject(auditLog);
    }
于 2016-02-10T10:26:39.977 回答
1

我已经构建了自己的 Json 比较方法。它使用 Newtonsoft.Json.Linq。

    public static JObject FindDiff(this JToken Current, JToken Model)
    {
        var diff = new JObject();
        if (JToken.DeepEquals(Current, Model)) return diff;

        switch(Current.Type)
        {
            case JTokenType.Object:
                {
                    var current = Current as JObject;
                    var model = Model as JObject;
                    var addedKeys = current.Properties().Select(c => c.Name).Except(model.Properties().Select(c => c.Name));
                    var removedKeys = model.Properties().Select(c => c.Name).Except(current.Properties().Select(c => c.Name));
                    var unchangedKeys = current.Properties().Where(c => JToken.DeepEquals(c.Value, Model[c.Name])).Select(c => c.Name);
                    foreach (var k in addedKeys)
                    {
                        diff[k] = new JObject
                        {
                            ["+"] = Current[k]
                        };
                    }
                    foreach (var k in removedKeys)
                    {
                        diff[k] = new JObject
                        {
                            ["-"] = Model[k]
                        };
                    }
                    var potentiallyModifiedKeys = current.Properties().Select(c => c.Name).Except(addedKeys).Except(unchangedKeys);
                    foreach (var k in potentiallyModifiedKeys)
                    {
                        diff[k] = FindDiff(current[k], model[k]);
                    }
                }
                break;
            case JTokenType.Array:
                {
                    var current = Current as JArray;
                    var model = Model as JArray;
                    diff["+"] = new JArray(current.Except(model));
                    diff["-"] = new JArray(model.Except(current));
                }
                break;
            default:
                diff["+"] = Current;
                diff["-"] = Model;
                break;
        }

        return diff;
    }
于 2018-12-06T15:40:48.727 回答