遍历XML文档时如何获取指定节点下的Object元素列表?
问题描述
我正在处理XML文档的遍历操作,示例XML如下:
<DOCUMENT_ELEMENT FormName="Form Name"> <Object type="Form" name="form1"> <Object type="BaseDesignPanel" name="Panel1"> <Object type="FormsLabel" name="Label9"> <Property name="BackColor">White</Property> <Property name="Name">Label9</Property> <Property name="Size">76, 16</Property> <Property name="Text">Page 1 of 3</Property> <Property name="Location">723, 985</Property> </Object> <Property name="AutoScrollMargin">800, 3000</Property> <Property name="IsWriteProtected">False</Property> <Property name="TabIndex">0</Property> <Property name="Size">800, 3000</Property> <Property name="Pages">3</Property> <Property name="BackColor">White</Property> <Property name="Tag">Please do not delete</Property> <Property name="Location">0, 0</Property> <Property name="AutoScrollMinSize">800, 3000</Property> <Property name="Name">Panel1</Property> <Property name="BackgroundImageLayout">None</Property> </Object> <Property name="MaximumSize">833, 1033</Property> <Property name="Name">form1</Property> <Property name="AutoScroll">True</Property> <Property name="ClientSize">817, 730</Property> </Object> </DOCUMENT_ELEMENT>
我使用以下递归代码遍历每个节点:
Private Sub XmlDocumentWalker(XmlNode As XmlNode) If TypeOf XmlNode Is XmlComment Then Console.WriteLine("XML Comment:" + XmlNode.Value) If XmlNode.HasChildNodes Then XmlDocumentWalker(XmlNode.FirstChild) If Not IsNothing(XmlNode.NextSibling) Then XmlDocumentWalker(XmlNode.NextSibling) ElseIf TypeOf XmlNode Is XmlElement Then If XmlNode.HasChildNodes And (TypeOf XmlNode.FirstChild Is XmlText) Then Console.WriteLine("XML Element:" + XmlNode.Name & "=""" & XmlNode.FirstChild.Value & """") Else Console.WriteLine("XML Element: " + XmlNode.Name) End If If DirectCast(XmlNode, XmlElement).HasAttributes Then For Each XmlAttribute As XmlNode In DirectCast(XmlNode, XmlElement).Attributes Console.WriteLine("XML Attribute: " + XmlAttribute.Name & "=""" & XmlAttribute.Value & """") Next End If If XmlNode.HasChildNodes And Not (TypeOf XmlNode.FirstChild Is XmlText) Then XmlDocumentWalker(XmlNode.FirstChild) If Not IsNothing(XmlNode.NextSibling) Then XmlDocumentWalker(XmlNode.NextSibling) End If End Sub
现在需要实现:当遍历到Panel1节点时,获取该节点下的所有Object元素列表。
解决方案
可以通过以下几种方式实现需求:
方法1:修改现有递归遍历代码
在递归过程中,判断当前节点是否是目标Panel1节点,然后收集其下的所有Object子节点:
' 定义列表用于存储目标Object节点 Private targetObjects As List(Of XmlNode) = New List(Of XmlNode)() Private Sub XmlDocumentWalker(XmlNode As XmlNode) If TypeOf XmlNode Is XmlComment Then Console.WriteLine("XML Comment:" + XmlNode.Value) If XmlNode.HasChildNodes Then XmlDocumentWalker(XmlNode.FirstChild) If Not IsNothing(XmlNode.NextSibling) Then XmlDocumentWalker(XmlNode.NextSibling) ElseIf TypeOf XmlNode Is XmlElement Then Dim elem As XmlElement = DirectCast(XmlNode, XmlElement) ' 检查当前节点是否是Panel1 If elem.Name = "Object" AndAlso elem.GetAttribute("name") = "Panel1" Then ' 收集该节点下所有Object子节点 For Each childNode As XmlNode In elem.ChildNodes If TypeOf childNode Is XmlElement AndAlso childNode.Name = "Object" Then targetObjects.Add(childNode) End If Next ' 输出收集到的节点信息 Console.WriteLine($"找到Panel1下的{targetObjects.Count}个Object节点:") For Each objNode As XmlNode In targetObjects Dim objElem As XmlElement = DirectCast(objNode, XmlElement) Console.WriteLine($"Object type={objElem.GetAttribute("type")}, name={objElem.GetAttribute("name")}") Next End If ' 原有的遍历输出逻辑 If XmlNode.HasChildNodes And (TypeOf XmlNode.FirstChild Is XmlText) Then Console.WriteLine("XML Element:" + XmlNode.Name & "=""" & XmlNode.FirstChild.Value & """") Else Console.WriteLine("XML Element: " + XmlNode.Name) End If If elem.HasAttributes Then For Each XmlAttribute As XmlNode In elem.Attributes Console.WriteLine("XML Attribute: " + XmlAttribute.Name & "=""" & XmlAttribute.Value & """") Next End If If XmlNode.HasChildNodes And Not (TypeOf XmlNode.FirstChild Is XmlText) Then XmlDocumentWalker(XmlNode.FirstChild) If Not IsNothing(XmlNode.NextSibling) Then XmlDocumentWalker(XmlNode.NextSibling) End If End Sub
方法2:使用XPath直接查询
如果不需要完整遍历整个文档,直接用XPath定位到Panel1节点,再查询其下的Object元素会更高效:
' 假设xmlDoc是已加载的XmlDocument对象 Dim panel1Node As XmlNode = xmlDoc.SelectSingleNode("//Object[@name='Panel1']") If panel1Node IsNot Nothing Then Dim objectNodes As XmlNodeList = panel1Node.SelectNodes("./Object") Console.WriteLine($"找到Panel1下的{objectNodes.Count}个Object节点:") For Each objNode As XmlNode In objectNodes Dim objElem As XmlElement = DirectCast(objNode, XmlElement) Console.WriteLine($"Object type={objElem.GetAttribute("type")}, name={objElem.GetAttribute("name")}") Next End If
方法3:使用LINQ to XML(更简洁)
如果使用XDocument而非XmlDocument,可以用LINQ查询实现:
' 假设xd是已加载的XDocument对象 Dim panel1Object = xd.Descendants("Object").FirstOrDefault(Function(o) o.Attribute("name")?.Value = "Panel1") If panel1Object IsNot Nothing Then Dim childObjects = panel1Object.Elements("Object").ToList() Console.WriteLine($"找到Panel1下的{childObjects.Count}个Object节点:") For Each obj In childObjects Console.WriteLine($"Object type={obj.Attribute("type")?.Value}, name={obj.Attribute("name")?.Value}") Next End If
内容的提问来源于stack exchange,提问作者Peter Sun
相关产品推荐
相关产品推荐

