C# JSON diff

In this tutorial we will learn how to calculate the difference between two JSON objects, in C#.

Introduction

In this tutorial we will learn how to calculate the difference between two JSON objects, in C#.

We will be using jsondiffpatch.net library, which offers a very easy to use interface to perform the operation. If you are using the Visual Studio IDE, you can easily install the nuget from the Package Manager.

This tutorial was tested with .NET Core 3.1 and with version 2.2.0 of the jsondiffpatch.net library.

Text property diff

As usual, we start the code by stating the namespaces we are using. We will need the JsonDiffPatchDotNet namespace, so we can access the class that will allow us to compute the differences between the JSONs.

Additionally, we will need the System namespace, so we can print content to the console. Note that we will use these namespaces in all the other sections below.

using JsonDiffPatchDotNet;
using System;

Moving to the Main function, we will start by creating an object of class JsonDiffPatch. This object will expose to us the method we need to compute the diff between two JSONs.

We will use the parameterless version of the constructor, but take in consideration that there is other constructor signature that receives an Options object, so we can fine tune some of the diff behavior.

var diffObj = new JsonDiffPatch();

After that, we will define two JSON strings. Both will have a “name” property, but with different values.

var json1 = @"{ ""name"": ""John""}";
var json2 = @"{ ""name"": ""Tod"" }";

Followed by that, we will call the Diff method on our JsonDiffPatch object. As input, we will pass both JSON strings and as output we will get another JSON string, representing the diff.

Note that the order of the JSON parameters influence the order of the diff in the result. So, the first parameter can be seen as the “original JSON” and the second as the “modified JSON”, in case order matters.

var result = diffObj.Diff(json1, json2);

Other important thing to mention is that the Diff method can also receive as parameters JTokens (and, in this case, it returns a JToken with the diff), which might be useful if you are working with Json.net.

After getting the diff JSON, we can simply print it to the console. The complete code can be seen below.

namespace JsonDiff
{
    using JsonDiffPatchDotNet;
    using System;

    class Program
    {
        static void Main(string[] args)
        {
            var diffObj = new JsonDiffPatch();

            var json1 = @"{ ""name"": ""John""}";
            var json2 = @"{ ""name"": ""Tod"" }";

            var result = diffObj.Diff(json1, json2);

            Console.WriteLine(result);
        }
    }
}

After compiling and running the code in a tool of your choice, you should get an output like shown in figure 1. As can be seen, the result of the diff operation is a JSON string, like mentioned before.

It also contains a property called “name” (like our original JSON strings), but with an array as value. This array has two positions: position zero contains the value of the name property on the “original JSON”, and position one contains the value in the “modified JSON”.

Output of the program, with the diff JSON.
Figure 1 – Output of the program, with the diff JSON.

So, we can generalize the structure of the diff, when both properties exist in both JSONs and they are both modified, with the following format:

{ changedPropertyName: [ 'old value', 'new value' ] }

It’s important to mention that this will work as described for strings to up 50 characters. This happens because the library supports two different text diff modes:

  • Efficient (default)
  • Simple

In simple mode, both strings appear in the diff result, regardless of how many characters change [1].

In efficient mode, past 50 characters of either of the strings, the library uses the uses google-diff-match-patch algorithm for calculating the differences [1]. The representation of the result is also different and we won’t cover it on this tutorial.

Note that, in our case, since we used the default options, so we were on the Efficient mode. Nonetheless, we did not pass the 50 characters limit. Thus, we got the same behavior we would have in Simple mode.

If needed, both the 50 characters threshold and the text diff mode can be changed using the Options object.

Multiple properties diff

Just to illustrate some additional use cases, we will analyze the result of a diff of two objects with multiple properties. We will also test with some data types other than strings.

We will need the same namespaces as we stated in the previous section. After that, we will move to the Main code, where we will start by creating an instance of the JsonDiffPatch class.

Like before, we will define two JSON strings to be compared. In this case, we will have four properties for both objects:

  • name (a string)
  • nickname (a string)
  • age (number)
  • married (boolean)
var json1 = @"{ 
     ""name"": ""John"",
     ""nickname"":""Jay"",
     ""age"": 20,
     ""married"": false
}";

var json2 = @"{ 
     ""name"": ""John"",
     ""nickname"":""Jayd"",
     ""age"": 22,
     ""married"": true
}";

As can be seen above, we left the name property unchanged, so we can also observe what happens in this case.

To finalize, we will call the Diff method on the JsonDiffPatch object, passing as input both our strings. As output, like before, we get a JSON string with the diffs.

var result = diffObj.Diff(json1, json2);

The final code, with the print of the result to the console, can be seen below.

namespace JsonDiff
{
    using JsonDiffPatchDotNet;
    using System;

    class Program
    {
        static void Main(string[] args)
        {
            var diffObj = new JsonDiffPatch();

            var json1 = @"{ 
                ""name"": ""John"",
                ""nickname"":""Jay"",
                ""age"": 20,
                ""married"": false
            }";

            var json2 = @"{ 
                ""name"": ""John"",
                ""nickname"":""Jayd"",
                ""age"": 22,
                ""married"": true
            }";


            var result = diffObj.Diff(json1, json2);

            Console.WriteLine(result);
        }
    }
}

If we compile and run the code, we should get an output similar to figure 2. The behavior for the properties that have changed is exactly the same as in the previous section: we obtain a property with the same name, containing an array with the “old value” and the “new value”.

Note that the property that did not change (“name”) doesn’t appear in the result. This makes sense since the result of the process is an object containing the diff between the JSONs, and this property didn’t change.

Output of the JSON diff program, for two objects with multiple properties.
Figure 2 – Output of the JSON diff program, for two objects with multiple properties.

Arrays diff

In this section we will check how to do the diff between array properties.

Like we saw for the string properties, there are also two array diffing modes available on this library (values defined on this enum):

  • Efficient (default)
  • Simple

The efficient mode does an examination of the array and produces a diff result that only contains elements in the array that were added or removed [2]. The format of the result using this method is more complex, so we will not cover it on this introductory tutorial. Nonetheless, you can learn more about it here.

As mentioned before, the Efficient mode is the default one, which means we will need to pass some additional configurations to use the Simple mode.

In Simple mode, an exact match comparison over the arrays is performed. If something differs, both the “original” and “modified” arrays appear entirely in the result, without specifying which positions were changed [2].

So, jumping to the actual code, we start by creating an Options object, with the ArrayDiff property set to Simple. Note that below we are going to use the Object initializer syntax.

var options = new Options()
{
     ArrayDiff = ArrayDiffMode.Simple
};

Then we just create an object of class JsonDiffPatch, like before, but we pass our Options object as input.

var diffObj = new JsonDiffPatch(options);

Followed by that we are going to define two strings with an array property.

var json1 = @"{ 
      ""languages"": [""Portuguese"", ""English""]
}";

var json2 = @"{ 
      ""languages"": [""Portuguese"", ""English"", ""Spanish""]
}";

To finalize, we do the diff.

var result = diffObj.Diff(json1, json2);

The complete code can be seen below.

namespace JsonDiff
{
    using JsonDiffPatchDotNet;
    using System;

    class Program
    {
        static void Main(string[] args)
        {
            var options = new Options()
            {
                ArrayDiff = ArrayDiffMode.Simple
            };

            var diffObj = new JsonDiffPatch(options);

            var json1 = @"{ 
                ""languages"": [""Portuguese"", ""English""]
            }";

            var json2 = @"{ 
               ""languages"": [""Portuguese"", ""English"", ""Spanish""]
            }";


            var result = diffObj.Diff(json1, json2);

            Console.WriteLine(result);
        }
    }
}

Upon running the code, we should get an output similar to figure 3. As can be seen, since there was a change in the array, we obtain both the “old array” and the “new array”. As mentioned before, for the simple mode, we do not obtain a drill-down of which positions changed, but rather the complete arrays.

Output of the program, showing the diff of the two arrays.
Figure 3 – Output of the program, showing the diff of the two arrays.

References

[1] https://github.com/wbish/jsondiffpatch.net/blob/master/Src/JsonDiffPatchDotNet/TextDiffMode.cs

[2] https://github.com/wbish/jsondiffpatch.net/blob/master/Src/JsonDiffPatchDotNet/ArrayDiffMode.cs

Leave a Reply

%d bloggers like this: