使用子列表在 List 中以递归方式读取 XML 树结构
本文关键字:方式 递归 读取 结构 XML List 列表 | 更新日期: 2023-09-27 17:57:49
我有一个这样的XML:
我有一个带有属性名称的成员类。
如何将每个单元及其子单元读取到多个泛型List<Unit>
中,这些泛型单元可以使用最新的 .NET 技术以递归方式再次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>
这将使用普通递归来做到这一点:
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 个 LINQ 查询,但这超出了我的范围。LINQ 不容易/不适合递归。
我会勾勒出一个解决方案,我不会把它写出来:
- 将 Xml 读入 XDocument(或 XmlDocument(
- 定义
class Unit { ... ; ... List<Unit> Children; }
- 如果需要,定义单元和根类。我将在这里展平该部分
- 获取所有设备标签的平面列表,
var units = doc.Descendants("Unit");
- 遍历这些元素,我假设父节点总是在嵌套单元之前
- 查找
var Lookup = new Dictionary<XNode, Unit> ();
中每个节点的父节点 - 如果找到父节点,则将当前节点(新单元(添加到其子节点
- 否则将其添加到顶部列表
- 将新单元和 XElement 添加到字典中。
- 只有在创建列表时才需要查找字典。
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())
为什么不实现一个用于存储单元的树。这将比列表容易和自然得多。
看看这个评论,了解使用 LinkedList 的良好实现。
看
- MSDN:算法和数据结构
- C# 中的树数据结构
- 树:在 C# 中实现非二叉树
如果你必须使用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;
}