VB.NET中如何从XML文件构建唯一树结构并统计节点属性
XML节点与属性统计实现方案(VB.NET)
需求背景
需要从结构不明确的XML文件中生成节点与属性的唯一列表,统计每类节点/属性组合的出现次数。
示例输入XML
<level1> <item id="a">blah</item> <item id="b">blah</item> <item id="c">blah</item> <level2> <item id="d">blah</item> <item id="e">blah</item> <item id="f">blah</item> <level3> <item id="g">blah</item> <item id="h">blah</item> <item id="i">blah</item> <item id="k">blah</item> </level3> <level3> <item id="g">blah</item> <item id="h">blah</item> <item id="i">blah</item> <item id="j">blah</item> </level3> </level2> <level2> <item id="d">blah</item> <item id="e">blah</item> <item id="f">blah</item> <item id="k">blah</item> <level3> <item id="g">blah</item> <item id="i">blah</item> </level3> <level3> <item id="g">blah</item> <item id="h">blah</item> <item id="j">blah</item> </level3> </level2> </level1>
期望输出效果
<level1 count="1"> <item id="a">1</item> <item id="b">1</item> <item id="c">1</item> <level2 count="2"> <item id="d">2</item> <item id="e">2</item> <item id="f">2</item> <item id="k">1</item> <level3 count="4"> <item id="g">4</item> <item id="h">3</item> <item id="i">3</item> <item id="j">2</item> <item id="k">1</item> </level3> </level2> </level1>
现有开发条件
- 开发环境:VS2019 + VB.NET
- 已有基础遍历代码:
For Each Element As XmlElement In XmlDoc.SelectNodes("//*") Console.WriteLine("Processing element with name {0}:", Element.Name) For Each Attribute As XmlAttribute In Element.Attributes Console.WriteLine("{0}: {1}", Attribute.Name, Attribute.Value) Next Console.WriteLine() Next
实现方案
1. 自定义数据存储结构
使用嵌套类存储每个节点的统计信息,天然匹配XML树状结构:
Public Class XmlNodeStat ' 节点名称 Public Property Name As String ' 节点出现次数 Public Property Count As Integer = 0 ' 该节点下的属性值统计:Key为"属性名:属性值",Value为出现次数 Public Property AttributeCounts As New Dictionary(Of String, Integer) ' 子节点统计:Key为子节点名称,Value为子节点的统计对象 Public Property ChildStats As New Dictionary(Of String, XmlNodeStat) End Class
2. 统计逻辑实现
递归遍历XML节点,逐层累加计数:
' 根统计对象 Dim rootStat As New XmlNodeStat() With {.Name = "Root"} ' 入口调用:传入XML文档根节点、根统计对象 ProcessNode(XmlDoc.DocumentElement, rootStat) ' 递归处理节点的方法 Sub ProcessNode(node As XmlElement, parentStat As XmlNodeStat) ' 1. 累加当前节点计数 If Not parentStat.ChildStats.ContainsKey(node.Name) Then parentStat.ChildStats(node.Name) = New XmlNodeStat() With {.Name = node.Name} End If Dim currentStat = parentStat.ChildStats(node.Name) currentStat.Count += 1 ' 2. 累加属性值计数 For Each attr As XmlAttribute In node.Attributes Dim attrKey = $"{attr.Name}:{attr.Value}" If Not currentStat.AttributeCounts.ContainsKey(attrKey) Then currentStat.AttributeCounts(attrKey) = 0 End If currentStat.AttributeCounts(attrKey) += 1 Next ' 3. 递归处理所有子元素节点 For Each child As XmlElement In node.ChildNodes.OfType(Of XmlElement)() ProcessNode(child, currentStat) Next End Sub
3. 结果输出示例
可以按需输出为XML或者文本格式,以下是生成类示例输出的方法:
Sub PrintStat(stat As XmlNodeStat, Optional indent As Integer = 0) Dim indentStr = New String(" "c, indent * 4) ' 输出节点本身统计 Console.WriteLine($"{indentStr}<{stat.Name} count=""{stat.Count}"">") ' 输出属性统计 For Each attr In stat.AttributeCounts Dim attrParts = attr.Key.Split(":"c) Console.WriteLine($"{indentStr} <item {attrParts(0)}=""{attrParts(1)}"">{attr.Value}</item>") Next ' 输出子节点 For Each child In stat.ChildStats.Values PrintStat(child, indent + 1) Next Console.WriteLine($"{indentStr}</{stat.Name}>") End Sub ' 调用输出: PrintStat(rootStat.ChildStats.Values.First()) ' 传入根节点统计对象
内容的提问来源于stack exchange,提问作者Paul Stearns
相关产品推荐
相关产品推荐

