Read the XML tree structure recursively in List <T> with child lists <T>

I have an XML like this:

And I have a Member class with a property name.

How can I read each Unit and its child Units into multiple generic List<Unit> that can have children of List<Unit> recursively using the latest .NET technology?

 <Root> <Units Name="Test1"> <Unit Name="Test11" /> <Unit Name="Test12"> <Unit Name="Test21" /> <Unit Name="Test22" /> <Unit Name="Test23"> <Unit Name="Test31" /> <Unit Name="Test32" /> <Unit Name="Test33" /> </Unit> <Unit Name="Test24" /> </Unit> </Units> <Units Name="Test2" /> <!-- ... --> <Units Name="Test3" /> <!-- ... --> <Units Name="Test4" /> </Root> 
+8
c # recursion linq-to-xml tree
source share
4 answers

This would do this using regular recursion:

 public class Unit { public string Name { get; set; } public List<Unit> Children { get; set; } } class Program { public static void Main() { XDocument doc = XDocument.Load("test.xml"); List<Unit> units = LoadUnits(doc.Descendants("Units").Elements("Unit")); } public static List<Unit> LoadUnits(IEnumerable<XElement> units) { return units.Select( x=> new Unit() { Name = x.Attribute("Name").Value, Children = LoadUnits(x.Elements("Unit")) }).ToList(); } } 
+13
source share

Why don't you implement a tree to store units. This would be much simpler and more natural than lists.

Take a look at this comment for a good implementation using LinkedList.

Cm.

If you need to use List, you can use recursion to create it. I assume that your unit has a property (IList Unit.ChildUnits) for storing all child lists. If not, you might want to transfer Unit to another class that has this.

 public List<Unit> LoadAllUnits(XMLNode rootNode){ List<Unit> allUnits = new List<Unit>(); foreach(var childNode in rootNode.ChildNodes){ allUnits.Add(LoadAllSubUnits(childNode); } return allUnits; } private Unit LoadAllSubUnits(XMLNode node){ Unit u = GetUnitFromCurrentNode(node); // Converts current node into Unit object if(root.HasChildNode){ foreach(var childNode in node.ChildNodes){ u.ChildUnits.Add(LoadAllSubUnits(childNode); } } return u; } 
+1
source share

The challenge is to write it as 1 LINQ query, but that is outside of me. LINQ is not easy / suitable for recursion.

I will draw a solution, I will not write it:

  • read Xml in XDocument (or XmlDocument)
  • define a class Unit { ... ; ... List<Unit> Children; } class Unit { ... ; ... List<Unit> Children; }
  • if necessary, define the Units and Root classes. I will unravel this part here.
  • Get a flat list of all Unit tags, var units = doc.Descendants("Unit");
  • Iterating over these elements, I assume that the parent node will always be before the nested Unit
  • find the parent of each node in var Lookup = new Dictionary<XNode, Unit> ();
  • If a parent element is found, add the current node (new element) to its daughters
  • still add it to topList
  • add a new element and XElement to the dictionary.
  • A search dictionary is only needed when creating lists.
+1
source share
 class Unit { public string Name; public List<Unit> Children; public Unit(string name, List<Unit> children) { Name = name; Children = children; } public static Unit Convert(XElement elem) { return new Unit(elem.Attribute("Name").Value, Convert(elem.Elements())); } public static List<Unit> Convert(IEnumerable<XElement> elems) { return elems.Select(Unit.Convert).ToList(); } } 

You can use it as follows:

 Unit.Convert(XDocument.Parse(xml).Root.Elements()) 
+1
source share

All Articles