Reputation: 5161
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
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
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:
d3_mitch
sounds like something from the next Star Wars movie.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:
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>())
})
})
});
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
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));
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));
Upvotes: 5