1

I have a JSON object as below

[
  {
    "Id": 7,
    "Name": "Colocation Folder",
    "ParentId": 1,
    "depth": 0
  },
  {
    "Id": 8,
    "Name": "CoLo Real Estate",
    "ParentId": 7,
    "depth": 1
  },
  {
    "Id": 10,
    "Name": "CoLo: Burst",
    "ParentId": 7,
    "depth": 1
  },
  {
    "Id": 34,
    "Name": "CoLo Dedicated Bandwidth",
    "ParentId": 7,
    "depth": 1
  },
  {
    "Id": 10035,
    "Name": "Infrastructure as a Service",
    "ParentId": 7,
    "depth": 1
  },
  {
    "Id": 10037,
    "Name": "Software as a Service",
    "ParentId": 7,
    "depth": 1
  },
  {
    "Id": 10038,
    "Name": "IaaS Component Upgrade",
    "ParentId": 7,
    "depth": 1
  },
  {
    "Id": 668,
    "Name": "CoLo Misc Folder",
    "ParentId": 7,
    "depth": 1
  },
  {
    "Id": 758,
    "Name": "CoLo: Conduit Fee",
    "ParentId": 668,
    "depth": 2
  },
  {
    "Id": 765,
    "Name": "CoLo: Private VLAN",
    "ParentId": 668,
    "depth": 2
  }
]

The Id and ParentId fields show the relation between the items. I need to make it as a nested JSON using C#. Since there will be many such models, I don't want to create individual classes for each model. Is there a generic approach in C# that will take a flat JSON array, take the ID and ParentId fields as input and then return me a nested JSON with all other fields in the array as well? For example, I am looking for an output of nested JSON as below:

[
  {
    "Id": 7,
    "Name": "Colocation Folder",
    "items": [
      {
        "Id": 8,
        "Name": "CoLo Real Estate",
        "ParentId": 7
      },
      {
        "Id": 10,
        "Name": "CoLo: Burst",
        "ParentId": 7
      },
      {
        "Id": 34,
        "Name": "CoLo Dedicated Bandwidth",
        "ParentId": 7
      },
      {
        "Id": 10035,
        "Name": "Infrastructure as a Service",
        "ParentId": 7
      },
      {
        "Id": 10037,
        "Name": "Software as a Service",
        "ParentId": 7
      },
      {
        "Id": 10038,
        "Name": "IaaS Component Upgrade",
        "ParentId": 7
      },
      {
        "Id": 668,
        "Name": "CoLo Misc Folder",
        "ParentId": 7,
        "items": [
          {
            "Id": 758,
            "Name": "CoLo: Conduit Fee",
            "ParentId": 668
          },
          {
            "Id": 765,
            "Name": "CoLo: Private VLAN",
            "ParentId": 668
          }
        ]
      }
    ]
  }
]
4
  • Give an example of your desired results. It isn't clear what you're trying to do. Commented May 12, 2017 at 15:15
  • I have edited my question to show the desired results. Thanks Commented May 12, 2017 at 15:41
  • In your example JSON, why does the root object have a ParentId of 1? What does that refer to? Commented May 12, 2017 at 16:40
  • Brian - It basically means that it has a parent which is not shown here. Basically, this is just like one branch in the tree.. I want only the children to be nested based on the ParentId Commented May 12, 2017 at 16:51

3 Answers 3

1

If you use Json.Net, you can do this conversion in a generic way using the LINQ-to-JSON API (JObjects). The idea is to parse the JSON array and add all the individual items to a dictionary keyed by Id. Then, loop over the dictionary items, and for each one, try to look up the parent. If the parent is found, add the item to the parent's items array (creating it if needed). Otherwise, add the item to the root array. Along the way, remove the depth property from each item, since you don't seem to want that in the output. Lastly, just dump the root array to string to get the final result.

var dict = JArray.Parse(json)
    .Children<JObject>()
    .ToDictionary(jo => (string)jo["Id"], jo => new JObject(jo));

var root = new JArray();

foreach (JObject obj in dict.Values)
{
    JObject parent;
    string parentId = (string)obj["ParentId"];
    if (parentId != null && dict.TryGetValue(parentId, out parent))
    {
        JArray items = (JArray)parent["items"];
        if (items == null)
        {
            items = new JArray();
            parent.Add("items", items);
        }
        items.Add(obj);
    }
    else
    {
        root.Add(obj);
    }

    JProperty depth = obj.Property("depth");
    if (depth != null) depth.Remove();
}

Console.WriteLine(root.ToString());

Fiddle: https://dotnetfiddle.net/Buza6T

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

3 Comments

Brian - the code works when ParentId is available but when the ParentId is null, I get an exception Can not convert Null to Int32. and I therefore changed the dictionary to object instead of int var dict = JArray.Parse(JSONString) .Children<JObject>() .ToDictionary(jo => (object)jo[IdFieldName], jo => new JObject(jo));
I added a fix which checks whether ParentId has a value before trying to use it.
In that case, I would just make the dictionary keys strings. It will work for ints also.
0

You can use a dynamic object with JSON.Net like so to detect your properties dynamically then you could build a new json object with the desired nesting: using Newtonsoft.Json; using Newtonsoft.Json.Linq;

            dynamic d = JArray.Parse(stringy);
            foreach(var ob in d)
            {
                if(ob.ParentID != ob.Id)
                {
                    string debug = "oh snapple, it's a child object";
                }
            }

Comments

0

Share my working code for you at jsFiddle full source code

recursive function is:

  function getNestedChildren(arr, parent) {
var out = []
for(var i in arr) {
    if(arr[i].parent == parent) {
        var children = getNestedChildren(arr, arr[i].id)

        if(children.length) {
            arr[i].children = children
        }
        out.push(arr[i])
    }
  }
 return out
}

full source code:

        function getNestedChildren(arr, parent) {
        var out = []
        for(var i in arr) {
            if(arr[i].ParentId == parent) {
                var items = getNestedChildren(arr, arr[i].Id)

                if(items.length) {
                    arr[i].items = items
                }
                out.push(arr[i])
            }
        }
        return out
    }


    var flat_array = [
      {
        "Id": 7,
        "Name": "Colocation Folder",
        "ParentId": 1,
        "depth": 0
      },
      {
        "Id": 8,
        "Name": "CoLo Real Estate",
        "ParentId": 7,
        "depth": 1
      },
      {
        "Id": 10,
        "Name": "CoLo: Burst",
        "ParentId": 7,
        "depth": 1
      },
      {
        "Id": 34,
        "Name": "CoLo Dedicated Bandwidth",
        "ParentId": 7,
        "depth": 1
      },
      {
        "Id": 10035,
        "Name": "Infrastructure as a Service",
        "ParentId": 7,
        "depth": 1
      },
      {
        "Id": 10037,
        "Name": "Software as a Service",
        "ParentId": 7,
        "depth": 1
      },
      {
        "Id": 10038,
        "Name": "IaaS Component Upgrade",
        "ParentId": 7,
        "depth": 1
      },
      {
        "Id": 668,
        "Name": "CoLo Misc Folder",
        "ParentId": 7,
        "depth": 1
      },
      {
        "Id": 758,
        "Name": "CoLo: Conduit Fee",
        "ParentId": 668,
        "depth": 2
      },
      {
        "Id": 765,
        "Name": "CoLo: Private VLAN",
        "ParentId": 668,
        "depth": 2
      }
    ]


    var nested = getNestedChildren(flat_array, 1)

    console.log(nested)

Comments

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.