在具有子列表的List 中递归读取XML树结构

我有这样的XML:

我有一个属性Name的成员类。

如何使用最新的.NET技术以递归方式将每个单元及其子单元读入多个通用List ,这可以再次具有子List

                     

这样做,使用普通递归:

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

挑战在于将其写为1 LINQ查询,但这超出了我的范围。 LINQ不容易/适合递归。

我将草拟一个解决方案,我不打算写出来:

  • 将Xml读入XDocument(或XmlDocument)
  • 定义一个class Unit { ... ; ... List Children; } class Unit { ... ; ... List Children; }
  • 如果需要,定义单元和根类。 我会在这里压扁那部分
  • 得到所有单位标签的平面列表, var units = doc.Descendants("Unit");
  • 迭代这些元素,我假设父节点将始终位于嵌套单元之前
  • 查找var Lookup = new Dictionary ();中每个节点的Parent var Lookup = new Dictionary ();
  • 如果找到父级,则将当前节点(新单元)添加到其子级
  • 否则将其添加到topList
  • 将新单元和XElement添加到字典中。
  • 只有在创建列表时才需要查找字典。
 class Unit { public string Name; public List Children; public Unit(string name, List children) { Name = name; Children = children; } public static Unit Convert(XElement elem) { return new Unit(elem.Attribute("Name").Value, Convert(elem.Elements())); } public static List Convert(IEnumerable elems) { return elems.Select(Unit.Convert).ToList(); } } 

你可以像这样使用它:

 Unit.Convert(XDocument.Parse(xml).Root.Elements()) 

为什么不实现树存储单元。 这比列表更容易和自然。

使用LinkedList查看此注释以获得良好的实现。

看到

  • MSDN:算法和数据结构
  • C#中的树数据结构
  • 树:在C#中实现非二叉树

如果您必须使用List,那么您可以使用递归来构建它。 我假设您的单位有一个属性(IList Unit.ChildUnits)来容纳所有孩子列表。 如果不是,您可能希望将Unit包装到另一个具有此function的类中。

 public List LoadAllUnits(XMLNode rootNode){ List allUnits = new List(); 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; }