Read a XML tree structure recursively in a List with children lists

前端 未结 4 807
孤独总比滥情好
孤独总比滥情好 2021-02-06 03:10

I have an XML like this:

And I have a Member class with property Name.

How can I read every Unit and its children Units into multiple generic List

相关标签:
4条回答
  • 2021-02-06 03:38

    The challenge would be to write it as 1 LINQ query, but that's beyond me. LINQ isn't easy/suitable for recursion.

    I'll sketch a solution, I'm not going to write it out :

    • read the Xml into an XDocument (or XmlDocument)
    • define a class Unit { ... ; ... List<Unit> Children; }
    • define Units and Root classes if desired. I'll flatten that part here
    • get a flat list of all Unit tags, var units = doc.Descendants("Unit");
    • Iterate over those elements, I assume that a parent node will always come before a nested Unit
    • look up the Parent of each node in a var Lookup = new Dictionary<XNode, Unit> ();
    • if a Parent is found, add the current node (new Unit) to its Children
    • else add it to a topList
    • add the new Unit and the XElement to the dictionary.
    • the lookup dictionary is only needed while creating the lists.
    0 讨论(0)
  • 2021-02-06 03:48

    Why don't you implement a Tree for storing units. That would be much easier and natural than Lists.

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

    See

    • MSDN: Algorithms and Data Structures
    • Tree data structure in C#
    • Tree: Implementing a Non-Binary Tree in C#

    If you HAVE to use List, then you may use recursion to build it. I'm assuming your Unit has a property (IList Unit.ChildUnits) to hold all children List. If not you may want to wrap Unit into 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;
    }
    
    0 讨论(0)
  • 2021-02-06 03:51
    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 like this:

    Unit.Convert(XDocument.Parse(xml).Root.Elements())
    
    0 讨论(0)
  • 2021-02-06 03:57

    This would do it, using plain 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();
        }
    }
    
    0 讨论(0)
提交回复
热议问题