16

For example, if I have the following json texts:

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

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

I need something in c# that reads that files and shows the difference. i.e. it can return the following object:

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

Is there some API or suggestions to do this?

3

3 Answers 3

6

I recommend you use Weakly-Typed JSON Serialization and write a routine that uses JsonObject like this:

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;
}

Your choice whether to get reports recursively inside JsonValue v1 and v2, instead of just using their string representation as I did here.

If you wanted to go recursive, it might change the above like this:

  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);
  }

-Jesse

Sign up to request clarification or add additional context in comments.

Comments

1

For some reason, I was not able to use JsonObject in my Web API project. I used JSON.Net and below is my method to get diff. It will give out Array of differences.

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);
    }

Comments

1

I've constructed my own method for Json comparison. It uses 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;
    }

1 Comment

Perfect ! Bravo

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.