在带有子列表<t> </t> </t>的List <t>中递归读取XML树结构

时间:2011-05-28 20:43:52

标签: c# recursion tree linq-to-xml

我有这样的XML:

我有一个名为。的成员类。

如何使用最新的.NET技术以递归方式将每个单元及其子单元读入多个通用List<Unit>,这些通用List<Unit>可以再次生成子<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>

{{1}}

4 个答案:

答案 0 :(得分:15)

这样做,使用普通递归:

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();
    }
}

答案 1 :(得分:1)

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

使用LinkedList查看this comment有关良好实现的信息。

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

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;
}

答案 2 :(得分:1)

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

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

  • 将Xml读入XDocument(或XmlDocument)
  • 定义class Unit { ... ; ... List<Unit> Children; }
  • 根据需要定义单位和根类。我会在这里压扁那部分
  • 获取所有单元代码的详细列表,var units = doc.Descendants("Unit");
  • 迭代这些元素,我假设父节点将始终位于嵌套单元
  • 之前
  • var Lookup = new Dictionary<XNode, Unit> ();
  • 中查找每个节点的Parent
  • 如果找到父级,则将当前节点(新单元)添加到其子级
  • 将其添加到topList
  • 将新单位和XElement添加到字典中。
  • 只有在创建列表时才需要查找字典。

答案 3 :(得分:1)

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();
    }
}

你可以像这样使用它:

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