So I have a C# app I'm working on, which for one method retrieves an OData response body. These represent item categories. Any parent-child relationship is defined with a Parent_Category element.
My ultimate goal is to present the user with a tree view of the item categories. So that the hierarchy is apparent. Like this.
Below is the OData response body that's being sent back to me.
{
"@odata.context": "https://api.businesscentral.dynamics.com/v2.0/13bb3475-ed48-4836-8e0d-6188cc004599/Sandbox2/ODataV4/$metadata#Company('CRONUS%20USA%2C%20Inc.')/ItemCategories",
"value": [
{
"@odata.etag": "W/\"JzE5Ozc0MDEzNzM2MzQ2Mjc3MDQ5MzQxOzAwOyc=\"",
"Code": "BEANS",
"Description": "BEANS",
"Parent_Category": "",
"LSE_Outbound_Code": ""
},
{
"@odata.etag": "W/\"JzE4OzU5MTI1NDIzNTQ0MDU4MDc2OTE7MDA7Jw==\"",
"Code": "CM",
"Description": "Coffee Makers",
"Parent_Category": "",
"LSE_Outbound_Code": ""
},
{
"@odata.etag": "W/\"JzIwOzE3MzEyMjA5NzY5NzA2NzQ1MjYyMTswMDsn\"",
"Code": "CM_COMMER",
"Description": "Commercial Models",
"Parent_Category": "CM",
"LSE_Outbound_Code": ""
},
{
"@odata.etag": "W/\"JzE4OzkyNzkxOTcxNzAyNjYyMTI3ODE7MDA7Jw==\"",
"Code": "CM_CONSUM",
"Description": "Consumer Models",
"Parent_Category": "CM",
"LSE_Outbound_Code": ""
},
{
"@odata.etag": "W/\"JzIwOzEyODQzNzYyMTU3OTI4NTE5Mzk1MTswMDsn\"",
"Code": "FASHION",
"Description": "Fashion Jewelry",
"Parent_Category": "",
"LSE_Outbound_Code": ""
},
{
"@odata.etag": "W/\"JzIwOzEyMjU5NzE2Njg0MzE3ODg3MTc4MTswMDsn\"",
"Code": "FURNITURE",
"Description": "Office Furniture",
"Parent_Category": "",
"LSE_Outbound_Code": ""
},
{
"@odata.etag": "W/\"JzIwOzE0NTg1NTU0Njg2NjkzNzc2MjM1MTswMDsn\"",
"Code": "CHAIR",
"Description": "Office Chair",
"Parent_Category": "FURNITURE",
"LSE_Outbound_Code": ""
},
{
"@odata.etag": "W/\"JzE4OzkyMzYzNjkwNTExMzY3MzAwMDE7MDA7Jw==\"",
"Code": "DESK",
"Description": "Office Desk",
"Parent_Category": "FURNITURE",
"LSE_Outbound_Code": ""
},
{
"@odata.etag": "W/\"JzIwOzExNzIzNjI3NzUxMjcxMTI2MjY3MTswMDsn\"",
"Code": "TABLE",
"Description": "Assorted Tables",
"Parent_Category": "FURNITURE",
"LSE_Outbound_Code": ""
},
{
"@odata.etag": "W/\"JzE2Ozc3MjM1ODY4ODY4MDQyNjcxOzAwOyc=\"",
"Code": "MISC",
"Description": "Miscellaneous",
"Parent_Category": "",
"LSE_Outbound_Code": ""
},
{
"@odata.etag": "W/\"JzE5OzU0NjM3MTMyNTc0NDI5MDk0NDIxOzAwOyc=\"",
"Code": "SUPPLIERS",
"Description": "Office Supplies",
"Parent_Category": "MISC",
"LSE_Outbound_Code": ""
},
{
"@odata.etag": "W/\"JzIwOzEyNDU0NDkzNDczMDM2NjAxNDk4MTswMDsn\"",
"Code": "PARTS",
"Description": "Parts",
"Parent_Category": "",
"LSE_Outbound_Code": ""
}
]
}
Any suggestions about where I can start breaking these out? Before I get into the UI aspects of the result, even a text listing of them would be a start. Such as:
BEANS
CM
--> CM_COMMER
--> CM_CONSUM
...
I figure I need to add these elements into a List and then recursively iterate through that. Just having trouble getting started on the thought process.
This is the easiest i can think of. As linked in the comments there might be better options for creating a tree like structure from a flat list. However this is complete:
using Newtonsoft.Json;
public class Root
{
[JsonProperty("@odata.context")]
public string OdataContext { get; set; }
[JsonProperty("value")]
public List<ItemCategory> Categories { get; set; }
}
public class ItemCategory
{
public string Code { get; set; }
public string Description { get; set; }
public string Parent_Category { get; set; }
}
public class TreeNode
{
public string Key { get; set; }
public string Value { get; set; }
public List<TreeNode> Children { get; set; }
public TreeNode()
{
Children = new List<TreeNode>();
}
}
class Program
{
static void Main(string[] args)
{
// I stored te json in a file
// Your api call would be here
string filePath = "data.json";
string json = File.ReadAllText(filePath);
// Get the Categories
var rootjson = JsonConvert.DeserializeObject<Root>(json);
List<ItemCategory> itemList = rootjson.Categories;
// Build the tree
var root = new TreeNode();
// I use a dictionary for lookup this could be done without
Dictionary<string, TreeNode> tree = new Dictionary<string, TreeNode>();
foreach (var category in itemList)
{
// Create the node
var treeNode = new TreeNode
{
Key = category.Code,
Value = category.Description
};
// Add the node
if (string.IsNullOrEmpty(category.Parent_Category))
{
root.Children.Add(treeNode);
}
else
{
// If the parent is found, the current category is added to Children list.
if (tree.TryGetValue(category.Parent_Category, out var parent))
{
parent.Children.Add(treeNode);
}
}
tree.Add(category.Code, treeNode);
}
PrintTree(root, 0);
}
static void PrintTree(TreeNode node, int level)
{
// PadLeft does the indentation
Console.WriteLine($"{"".PadLeft(level * 2)}{node.Key} - {node.Value}");
foreach (var child in node.Children)
{
PrintTree(child, level + 1);
}
}
}
Prints :
BEANS - BEANS
CM - Coffee Makers
CM_COMMER - Commercial Models
CM_CONSUM - Consumer Models
FASHION - Fashion Jewelry
FURNITURE - Office Furniture
CHAIR - Office Chair
DESK - Office Desk
TABLE - Assorted Tables
Test - Office Supplies //Note i added a 3rd lvl for test
MISC - Miscellaneous
SUPPLIERS - Office Supplies
PARTS - Parts