Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find and return JSON differences using newtonsoft in C#?

Tags:

json

c#

json.net

I'd like to get a list of the JSON parts that don't match when doing a comparison using Newtonsoft.

I have this code that compares:

JObject xpctJSON = JObject.Parse(expectedJSON); JObject actJSON = JObject.Parse(actualJSON);  bool res = JToken.DeepEquals(xpctJSON, actJSON); 

But can't find anything that returns the diff's.

like image 390
user167908 Avatar asked Jul 21 '14 22:07

user167908


People also ask

How can I find the difference between two JSON files in C#?

Convert each json to xml and use MS XmlDiff libary. Available on nuget. Differences are given in another xml doc which here I write to the console. This is suitable for unit testing for example.

What is the use of Newtonsoft JSON in C#?

The Newtonsoft. JSON namespace provides classes that are used to implement the core services of the framework. It provides methods for converting between . NET types and JSON types.

What is JToken?

JToken is the abstract base class of JObject , JArray , JProperty , and JValue , which represent pieces of JSON data after they have been parsed. JsonToken is an enum that is used by JsonReader and JsonWriter to indicate which type of token is being read or written.

What is Newtonsoft JSON LINQ?

The Newtonsoft. Json. Linq namespace provides classes that are used to implement LINQ to JSON. Classes. Class.


2 Answers

Just to help future queries. There's a nice json diff tool I came across. It works flawlessly for diff/patch of json structures:

jsondiffpatch.net There's also a nuget package for it.

usage is straightforward.

var jdp = new JsonDiffPatch(); JToken diffResult = jdp.Diff(leftJson, rightJson); 
like image 106
Faheem Avatar answered Sep 21 '22 01:09

Faheem


Here is a recursive version that I wrote. You call CompareObjects with two JObjects and it returns a list of the differences. You call CompareArrays with two JArrays and it compares the arrays. Arrays and Objects can be nested inside each other.

UPDATE: @nttakr points out in the comment below that this method is actually a partial difference algorithm. It only tells you about differences from the point of view of the source list. If a key doesn't exist in the source but does exist in the target list, that difference will be ignored. This is by design for my testing requirements. This allows you to test for just then items you want without having to delete them from the target before the comparisons are done.

    /// <summary>     /// Deep compare two NewtonSoft JObjects. If they don't match, returns text diffs     /// </summary>     /// <param name="source">The expected results</param>     /// <param name="target">The actual results</param>     /// <returns>Text string</returns>      private static StringBuilder CompareObjects(JObject source, JObject target)     {         StringBuilder returnString = new StringBuilder();         foreach (KeyValuePair<string, JToken> sourcePair in source)         {             if (sourcePair.Value.Type == JTokenType.Object)             {                 if (target.GetValue(sourcePair.Key) == null)                 {                     returnString.Append("Key " + sourcePair.Key                                         + " not found" + Environment.NewLine);                 }                 else if (target.GetValue(sourcePair.Key).Type != JTokenType.Object) {                     returnString.Append("Key " + sourcePair.Key                                         + " is not an object in target" + Environment.NewLine);                 }                                     else                 {                     returnString.Append(CompareObjects(sourcePair.Value.ToObject<JObject>(),                         target.GetValue(sourcePair.Key).ToObject<JObject>()));                 }             }             else if (sourcePair.Value.Type == JTokenType.Array)             {                 if (target.GetValue(sourcePair.Key) == null)                 {                     returnString.Append("Key " + sourcePair.Key                                         + " not found" + Environment.NewLine);                 }                 else                 {                     returnString.Append(CompareArrays(sourcePair.Value.ToObject<JArray>(),                         target.GetValue(sourcePair.Key).ToObject<JArray>(), sourcePair.Key));                 }             }             else             {                 JToken expected = sourcePair.Value;                 var actual = target.SelectToken(sourcePair.Key);                 if (actual == null)                 {                     returnString.Append("Key " + sourcePair.Key                                         + " not found" + Environment.NewLine);                 }                 else                 {                     if (!JToken.DeepEquals(expected, actual))                     {                         returnString.Append("Key " + sourcePair.Key + ": "                                             + sourcePair.Value + " !=  "                                             + target.Property(sourcePair.Key).Value                                             + Environment.NewLine);                     }                 }             }         }         return returnString;     }      /// <summary>     /// Deep compare two NewtonSoft JArrays. If they don't match, returns text diffs     /// </summary>     /// <param name="source">The expected results</param>     /// <param name="target">The actual results</param>     /// <param name="arrayName">The name of the array to use in the text diff</param>     /// <returns>Text string</returns>      private static StringBuilder CompareArrays(JArray source, JArray target, string arrayName = "")     {         var returnString = new StringBuilder();         for (var index = 0; index < source.Count; index++)         {              var expected = source[index];             if (expected.Type == JTokenType.Object)             {                 var actual = (index >= target.Count) ? new JObject() : target[index];                 returnString.Append(CompareObjects(expected.ToObject<JObject>(),                     actual.ToObject<JObject>()));             }             else             {                  var actual = (index >= target.Count) ? "" : target[index];                 if (!JToken.DeepEquals(expected, actual))                 {                     if (String.IsNullOrEmpty(arrayName))                     {                         returnString.Append("Index " + index + ": " + expected                                             + " != " + actual + Environment.NewLine);                     }                     else                     {                         returnString.Append("Key " + arrayName                                             + "[" + index + "]: " + expected                                             + " != " + actual + Environment.NewLine);                     }                 }             }         }         return returnString;     } 
like image 36
Walter Avatar answered Sep 24 '22 01:09

Walter