C#: Flattening JSON

In this tutorial we will learn how to flatten a JSON object in C#.

Introduction

In this tutorial we will learn how to flatten a JSON object in C#. We will be using the JsonFlatten package, which exposes this functionality in a very easy to use extension method.

As can bee seen in figure 1, you can install JsonFlatten from the NuGet Package Manager of Visual Studio.

Installing the package from the NuGet Package Manager.
Figure 1 – Installing the package from the NuGet Package Manager.

When flattening a JSON object, we will obtain a new JSON object with one level deep, regardless of how nested the original object was. This makes it very easy to iterate through all the leaves, for example.

In the resulting flattened object, the property names will correspond to the full path of each property in the original object (separated by a dot). To exemplify, let’s assume we start from the following object:

{
   "prop1": {
       "nestedProp1": "nestedVal1",
       "nestedProp2": "nestedVal2"
   }
}

As output, we would get the following:

{ 
   "prop1.nestedProp1": "nestedVal1",
   "prop1.nestedProp2": "nestedVal2"
}

Note that we still have the information about the original structure of the object. It can be recovered in a process called “Unflatten“, which is also supported by this package.

This tutorial was tested with .NET Core 3.1 and with version 1.0.1 of the JsonFlatten library.

A simple example

We will start our code by stating the namespaces used. First, we will need the JsonFlatten namespace, from the NuGet we have just installed.

using JsonFlatten;

We will also need the Newtonsoft.Json and the Newtonsoft.Json.Linq namespaces from the Json.NET library. Note that the Json.Net library is a dependency from the JsonFlatten one, so you should be able to use these two namespaces without needed to install additional NuGet packages.

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

To finalize, we will also need the System namespace to be able to print the results of our program to the console.

using System;

Next we will analyze the Main function. We will define a variable with a JSON string containing an object with the following structure:

  • name: a property containing the name of a person;
  • address: a property containing the address of a person. This property corresponds to an object that contains two nested properties:
    • city: city where the person lives;
    • street: street where the person lives.
var jsonString = @"{
     ""name"": ""John"",
     ""address"":{
          ""city"": ""Lisbon"",
          ""street"": ""Central street""
     }
}";

As can be seen, the object contains two nested properties, which we want to get flattened in the final object.

After this we will parse the string to a JObject. We will use this object to perform the flatten procedure.

var jObject = JObject.Parse(jsonString);

The flattening functionality is provided as an extension method that we can call on our JObject to obtain its flattened version. This method takes no arguments and returns as output a Dictionary of string – object pairs.

var flattened = jObject.Flatten();

After this, we will simply serialize the object back to a JSON string and print it to the console.

var flattenedJsonString = JsonConvert.SerializeObject(flattened, Formatting.Indented);
Console.WriteLine(flattenedJsonString);

The final code can be seen below.

namespace JsonFlat
{
    using JsonFlatten;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using System;

    class Program
    {
        static void Main(string[] args)
        {
            var jsonString = @"{
                ""name"": ""John"",
                ""address"":{
                    ""city"": ""Lisbon"",
                    ""street"": ""Central street""
                }
            }";

            var jObject = JObject.Parse(jsonString);
            var flattened = jObject.Flatten();

            var flattenedJsonString = JsonConvert.SerializeObject(flattened, Formatting.Indented);
            Console.WriteLine(flattenedJsonString);
        }
    }
}

To test the previous code, simply compile it and run it in a tool of your choice. I’m using Visual Studio 2019.

You should get an output similar to figure 2.

Output of the program with the flattened JSON.
Figure 2 – Output of the program with the flattened JSON.

A more complex use case

In this section we will cover a more complex use case where we will define a JSON with a property that is 4 levels nested. Additionally, that JSON will also contain an array. The rest of the code will be exactly the same.

var jsonString = @"{
      ""x"":{
           ""y"": {
               ""z"": {
                  ""w"": 10
               }
           }
      },
      ""array"": [10, 20, 30]                
}";

So, in the nested property, we expect to obtain the whole path to it, regardless of the fact that it is 4 levels nested:

x.y.z.w

Arrays will also be flattened. For arrays, each element of the array will be mapped to a different property in the final object and the path will contain a number corresponding to the position in the array:

array[0]
array[1]
array[2]

The complete code can be seen below.

namespace JsonFlat
{
    using JsonFlatten;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using System;

    class Program
    {
        static void Main(string[] args)
        {
            var jsonString = @"{
                ""x"":{
                    ""y"": {
                        ""z"": {
                            ""w"": 10
                        }
                    }
                },
                ""array"": [10, 20, 30]                
            }";

            var jObject = JObject.Parse(jsonString);
            var flattened = jObject.Flatten();

            var flattenedJsonString = JsonConvert.SerializeObject(flattened, Formatting.Indented);

            Console.WriteLine(flattenedJsonString);
        }
    }
}

Upon compiling and running the code, we should get a result similar to figure 3. As can be seen, the format of the array matches the expected one.

Flattened JSON that contained a 4 levels deep property and an array.
Figure 3 – Flattened JSON that contained a 4 levels deep property and an array.

Leave a Reply

%d bloggers like this: