TAHA SULTAN TEMURI
TAHA SULTAN TEMURI

Reputation: 5161

Create nested child JSON

How can I create this nested child json in C#? I am unable to figure out how to add into list to child nestedly. I am using this.

JSON

 {
"name": "Top Level",
"parent": "null",
"children": [
  {
    "name": "Level 2: A",
    "parent": "Top Level",
    "children": [
      {
        "name": "Son of A",
        "parent": "Level 2: A"
        ,
         "children": [
      {
        "name": "Son of A",
        "parent": "Level 2: A"

      },
      {
        "name": "Daughter of A",
        "parent": "Level 2: A"
      }
    ]

      },
      {
        "name": "Daughter of A",
        "parent": "Level 2: A"
      }
    ]
  },
  {
    "name": "Level 2: B",
    "parent": "Top Level"
  }
 ]
}

Diagramatic Representation of Root and Child

enter image description here

Class

 public class d3_mitch
{


    public string  name { get; set; }


    public string parent { get; set; }

    public List<d3_mitch> children { get; set; }
}

What I am doing

  d3_mitch d3 = new d3_mitch();
        d3.id = 1;
        d3.name = "Root";
        d3.type = "Root";
        d3.description = "abc blah blah";
        d3.children = new List<d3_mitch>()
        {

              new d3_mitch() { name = "Carnivores", type = "Type", id = 2, description = "Diet consists solely of animal materials",
            children=new List<d3_mitch>(){ new d3_mitch() { id= 3 ,name="Felidae",type="Family",description="Also known as cats"} }
           }
        };

Now Problem Is

How can I add child to each list of parent having id = N?

Like this

 d3.children = new List<d3_mitch>()
        {

              new d3_mitch() { name = "Carnivores", type = "Type", id = 2, description = "Diet consists solely of animal materials",
            children=new List<d3_mitch>(){ new d3_mitch() { id= 3 ,name="Felidae",type="Family",description="Also known as cats",



           //This one
            children=new List<d3_mitch>(){ new d3_mitch() { id = 4, name = "Felidae4", type = "Family", description = "Also known as cats" } }



            } }
           }
        };

Upvotes: 2

Views: 3170

Answers (2)

Funk
Funk

Reputation: 11201

@John has already shown a couple of automated ways of how to accomplish this, perhaps you'll see the pattern more clearly if we construct the tree by hand.

First, a couple of pointers:

  1. Name your classes meaningfully, d3_mitch sounds like something from the next Star Wars movie.
  2. C# properties start with Capital letters by convention.

Note your diagrammatic representation would also benefit from a better naming convention. As it stands the node C1R3 appears at two places in the tree, which is impossible as trees don't allow cycles. You'd need to use a graph for that. Anyway, I created a new Node with the same name just to resemble the diagram.

Two options depending on the class representation, and how the data is fed:

  1. Through Constructor Injection

The node class

public class Node
{
    public Node(int id, int parentId, string name, List<Node> children)
    {
        Id = id;
        ParentId = parentId;
        Name = name;
        Children = children;
    }

    public int Id { get; }
    public int ParentId { get; }
    public string Name { get; }
    public List<Node> Children { get; }
}

The tree assembly by hand

var tree =
    new Node(1, -1, "R", new List<Node>
    {
        new Node(2, 1, "C1R1", new List<Node>()),
        new Node(3, 1, "C2R2", new List<Node>()),
        new Node(4, 1, "C3R3", new List<Node>
        {
            new Node(5, 4, "C1R3", new List<Node>()),
            new Node(6, 4, "C2R3", new List<Node>
            {
                new Node(7, 6, "C1R3", new List<Node>())
            })
        })
    });
  1. By setting Properties

The node class

public class Node
{
    public int Id { get; set; }
    public int ParentId { get; set; }
    public string Name { get; set; }
    public List<Node> Children { get; set; }
}

The tree assembly by hand

var tree =
    new Node
    {
        Id = 1,
        ParentId = -1,
        Name = "R",
        Children = new List<Node>
        {
            new Node
            {
                Id = 2,
                ParentId = 1,
                Name = "C1R1",
                Children = new List<Node>()
            },
            new Node
            {
                Id = 3,
                ParentId = 1,
                Name = "C2R2",
                Children = new List<Node>()
            },
            new Node
            {
                Id = 4,
                ParentId = 1,
                Name = "C3R3",
                Children = new List<Node>
                {
                    new Node
                    {
                        Id = 5,
                        ParentId = 4,
                        Name = "C1R3",
                        Children = new List<Node>()
                    },
                    new Node
                    {
                        Id = 6,
                        ParentId = 4,
                        Name = "C2R3",
                        Children = new List<Node>
                        {
                            new Node
                            {
                                Id = 7,
                                ParentId = 6,
                                Name = "C1R3",
                                Children = new List<Node>()
                            },
                        }
                    }
                }
            },
        }
    };

Upvotes: 5

ProgrammingLlama
ProgrammingLlama

Reputation: 38737

Since your class definition differs in your examples, I've made my own for the purposes of this example:

public class MyNode
{
    public int Id { get; set; }
    public int ParentId { get; set; }
    public string Name { get; set; }
    public List<MyNode> Nodes { get; set; }

    public MyNode()
    {
        Nodes = new List<MyNode>();
    }
}

Next we can create a flat list of nodes with their relationships defined by their ids:

var rootNode = new MyNode() { ParentId = -1, Id = 1, Name = "Root" };
var nodes = new [] {
    rootNode,
    new MyNode() { ParentId = 1, Id = 2, Name = "ChildA" },
    new MyNode() { ParentId = 1, Id = 3, Name = "ChildB" },
    new MyNode() { ParentId = 2, Id = 4, Name = "ChildA.A" },
    new MyNode() { ParentId = 2, Id = 5, Name = "ChildA.B" },
    new MyNode() { ParentId = 3, Id = 6, Name = "ChildB.A" },
    new MyNode() { ParentId = 3, Id = 7, Name = "ChildB.B" }
};

Then we can go through each item looking up its parent and adding it to its parent's child list:

var nodeDict = nodes.ToDictionary(n => n.Id);
foreach (var item in nodes)
{
    MyNode parentNode = null;
    if (item.ParentId == -1 || !nodeDict.TryGetValue(item.ParentId, out parentNode)) // we don't want to look up the root node since it doesn't have a parent. you might want to add error handling if the parent node isn't found
    {
        continue;
    }

    parentNode.Nodes.Add(item);
}

And then we can serialize the result:

Console.WriteLine(JsonConvert.SerializeObject(rootNode, Formatting.Indented));

Try it online


A slightly more complicated approach using a similar technique is to create a "builder":

public interface IRootHierarchyBuilder 
{
    IHierarchyBuilder AddRootNode(MyNode rootNode);
}

public interface IHierarchyBuilder
{
    IHierarchyBuilder AddNode(MyNode childNode);
    MyNode Build();
}

public class HierarchyBuilder : IRootHierarchyBuilder, IHierarchyBuilder
{
    private readonly IDictionary<int, MyNode> _nodes;
    private MyNode _rootNode;

    private HierarchyBuilder()
    {
        _nodes = new Dictionary<int, MyNode>();
    }

    public static IRootHierarchyBuilder Create()
    {
        return new HierarchyBuilder();
    }

    IHierarchyBuilder IRootHierarchyBuilder.AddRootNode(MyNode rootNode)
    {
        if (_rootNode != null)
        {
            throw new InvalidOperationException("Root node already exists.");
        }
        _rootNode = rootNode;
        _nodes[rootNode.Id] = rootNode;
        return this;
    }

    IHierarchyBuilder IHierarchyBuilder.AddNode(MyNode childNode)
    {
        if (_rootNode == null)
        {
            throw new InvalidOperationException("Root node not set.");
        }

        if (_nodes.ContainsKey(childNode.Id))
        {
            throw new Exception("This child has already been added.");
        }

        MyNode parentNode;
        if (!_nodes.TryGetValue(childNode.ParentId, out parentNode))
        {
            throw new KeyNotFoundException("Parent node not found.");
        }
        parentNode.Nodes.Add(childNode);

        _nodes[childNode.Id] = childNode;
        return this;
    }

    MyNode IHierarchyBuilder.Build()
    {
        if (_rootNode == null)
        {
            throw new InvalidOperationException("Root node not set.");
        }
        return _rootNode;            
    }
}

Which you can then use like so:

var rootNode = HierarchyBuilder.Create()
    .AddRootNode(new MyNode() { Id = 1, ParentId = -1, Name = "Root" })
    .AddNode(new MyNode() { Id = 2, ParentId = 1, Name = "ChildA" })
    .AddNode(new MyNode() { Id = 3, ParentId = 1, Name = "ChildB" })
    .AddNode(new MyNode() { Id = 4, ParentId = 2, Name = "ChildA.A" })
    .AddNode(new MyNode() { Id = 5, ParentId = 2, Name = "ChildA.B" })
    .AddNode(new MyNode() { Id = 6, ParentId = 3, Name = "ChildB.A" })
    .AddNode(new MyNode() { Id = 7, ParentId = 3, Name = "ChildB.B" })
    .Build();

And again, we can serialize the result:

Console.WriteLine(JsonConvert.SerializeObject(rootNode, Formatting.Indented));

Try it online

Upvotes: 5

Related Questions