Home > Software engineering >  Flatten nested JSON with JSON.NET in C#
Flatten nested JSON with JSON.NET in C#

Time:04-29

I receive a bill of materials in JSON format via a WebApi, which has a corresponding hierarchy. The hierarchy or the nesting can be any depth.

An example bill of materials is shown below:

{
   "Quantity":0,
   "QuantityUnit":"pcs",
   "PartNumber":"12345",
   "Parent":"",
   "Children":[
      {
         "Quantity":1,
         "QuantityUnit":"pcs",
         "PartNumber":"88774",
         "Parent":"12345",
         "Children":[
            {
               "Quantity":1,
               "QuantityUnit":"pcs",
               "PartNumber":"42447",
               "Parent":"88774"
            },
            {
               "Quantity":0.420,
               "QuantityUnit":"kg",
               "PartNumber":"12387",
               "Parent":"88774"
            }
         ]
      }
   ]
}

How can I resolve this nested structure into a simple structure using JSON.NET in C#?

I want to transform it to:

[
   {
      "Quantity":0,
      "QuantityUnit":"pcs",
      "PartNumber":"12345",
      "Parent":""
   },
   {
      "Quantity":1,
      "QuantityUnit":"pcs",
      "PartNumber":"88774",
      "Parent":"12345"
   },
   {
      "Quantity":1,
      "QuantityUnit":"pcs",
      "PartNumber":"42447",
      "Parent":"88774"
   },
   {
      "Quantity":0.420,
      "QuantityUnit":"kg",
      "PartNumber":"12387",
      "Parent":"88774"
   }
]

For the deserialization I use the following class:

public class Bom
{
    public class TopLevel
    {
        public double Quantity { get; set; }
        public string QuantityUnit { get; set; }
        public string PartNumber { get; set; }
        public string Parent { get; set; }
        public List<Item> Children { get; set; }
    }

    public class Item
    {
        public double Quantity { get; set; }
        public string QuantityUnit { get; set; }
        public string PartNumber { get; set; }
        public string Parent { get; set; }
    }

    public double Quantity { get; set; }
    public string QuantityUnit { get; set; }
    public string PartNumber { get; set; }
    public string Parent { get; set; }
    public IList<TopLevel> Children { get; set; }
}

Furthermore, I use this code to deserialize the JSON to an object:

Bom bom = JsonConvert.DeserializeObject<Bom>(File.ReadAllText(jsonPath));

CodePudding user response:

Deserialize the original list, flatten it with Enumerable.SelectMany, and serialize the resulting sequence.

CodePudding user response:

First let's define a mapper

JObject Map(JObject source)
{
    var result = (JObject)source.DeepClone();
    result.Remove("Children");
    return result;
}
  • It simply clones the object and removes the Children property

Next let's define a recursive function to accumulate the JObjects

void Flatten(JArray children, JArray accumulator)
{
    if (children == null) return;
    foreach (JObject child in children)
    {
        accumulator.Add(Map(child));
        Flatten((JArray)child["Children"], accumulator);
    }
}

And finally let's make use of them

var semiParsed = JObject.Parse(json);

var accumulator = new JArray();
accumulator.Add(Map(semiParsed));
Flatten((JArray)semiParsed["Children"], accumulator);

The ToString call on the accumulator will return this

[
  {
    "Quantity": 0,
    "QuantityUnit": "pcs",
    "PartNumber": "12345",
    "Parent": ""
  },
  {
    "Quantity": 1,
    "QuantityUnit": "pcs",
    "PartNumber": "88774",
    "Parent": "12345"
  },
  {
    "Quantity": 1,
    "QuantityUnit": "pcs",
    "PartNumber": "42447",
    "Parent": "88774"
  },
  {
    "Quantity": 0.42,
    "QuantityUnit": "kg",
    "PartNumber": "12387",
    "Parent": "88774"
  }
]
  • Related