【问题标题】:Loop through a full XML document循环遍历完整的 XML 文档
【发布时间】:2013-01-18 14:38:45
【问题描述】:

我正在寻找一种方法来遍历我的 XML 文档的所有节点。

XML 文件示例

<root>
    <llnode created="2005-05-24T15:26:24" createdby="42912153" createdbyname="" description="" id="107810306" modified="2008-06-05T16:07:44" name="" objname="" objtype="0" ownedby="42912153" ownedbyname="" parentid="107810295" size="4">
        <Nickname domain=""/>
        <MajorMinorContainer>false</MajorMinorContainer>
        <llnode created="2005-05-06T12:54:03" createdby="42912153" createdbyname="" description="" id="107815681" modified="2006-12-04T14:39:51" name="" objname="" objtype="0" ownedby="42912153" ownedbyname="" parentid="107810306" size="0">
            <Nickname domain=""/>
            <MajorMinorContainer>false</MajorMinorContainer>
        </llnode>
        <llnode created="2005-05-06T12:54:31" createdby="42912153" createdbyname="" description="" id="107815683" modified="2006-12-04T14:39:53" name="" objname="" objtype="0" ownedby="42912153" ownedbyname="" parentid="107810306" size="0">
            <Nickname domain=""/>
            <MajorMinorContainer>false</MajorMinorContainer>
        </llnode>
    </llnode>
    <llnode created="2005-05-24T15:26:24" createdby="42912153" createdbyname="" description="" id="107810306" modified="2008-06-05T16:07:44" name="" objname="" objtype="0" ownedby="42912153" ownedbyname="" parentid="107810295" size="4">
        <Nickname domain=""/>
        <MajorMinorContainer>false</MajorMinorContainer>
        <llnode created="2005-05-06T12:54:03" createdby="42912153" createdbyname="" description="" id="107815681" modified="2006-12-04T14:39:51" name="" objname="" objtype="0" ownedby="42912153" ownedbyname="" parentid="107810306" size="0">
            <Nickname domain=""/>
            <MajorMinorContainer>false</MajorMinorContainer>
        </llnode>
        <llnode created="2005-05-06T12:54:31" createdby="42912153" createdbyname="" description="" id="107815683" modified="2006-12-04T14:39:53" name="" objname="" objtype="0" ownedby="42912153" ownedbyname="" parentid="107810306" size="0">
            <Nickname domain=""/>
            <MajorMinorContainer>false</MajorMinorContainer>
        </llnode>
    </llnode>
</root>

文档始终具有相同的结构。每个 llnode 代表一个文件夹。这可以非常深入(对于上面的示例,范围只有 2,但可以达到 10)。

如何遍历所有记录?我不想将一个循环放入一个循环中,然后再放入另一个循环并这样做 20 次以确保处理每个节点。有没有办法只做一个循环?

以下是我目前得到的,仅适用于实际的 XML 文档(范围 = 2),需要随着范围的增加添加尽可能多的循环(它不应该超过范围 = 10)

原始 VBA(来自原始问题)

xmlExportDoc = "myXmlDoc.xml"

Set xmlDoc = New MSXML2.DOMDocument
xmlDoc.Load (xmlExportDoc)

Set xmlNodeList = xmlDoc.SelectNodes("//llnode")

For Each Node In xmlNodeList
   MsgBox "Listing the EXISTING nodes"
   MsgBox Node.nodeName & " " & Node.NodeValue & " " & Node.NodeType

   If Node.HasChildNodes() Then
      MsgBox Node.nodeName & "has child nodes"
      Set xmlNodeList2 = Node.ChildNodes

      For Each Node2 In oNodeList2
          MsgBox Node2.nodeName & " " & Node2.NodeValue & " " & Node2.NodeType

          If Node2.HasChildNodes() Then
             MsgBox Node2.nodeName & "has child nodes"
          End If
      Next
   End If
Next

更新的 VBA

Private Function xmlParse(n As MSXML2.IXMLDOMNode)
    Dim n2 As MSXML2.IXMLDOMNode
    MsgBox n.nodeName & " " & n.NodeValue & " " & n.NodeType

    If n.HasChildNodes() Then
        MsgBox n.nodeName & " has child nodes"

        For Each n2 In n.ChildNodes
            xmlParse (n2)
        Next

        MsgBox "Done listing child nodes for " & n.nodeName
    End If
End Function

以及事件的代码:

    Dim xmlExportDoc As String
    Dim xmlDoc As MSXML2.DOMDocument
    Dim xmlNodeList As MSXML2.IXMLDOMNodeList, xmlNodeList2
    Dim Node As MSXML2.IXMLDOMNode

    xmlExportDoc = "http://myserver.com/myDoc.xml"

    Set xmlDoc = New MSXML2.DOMDocument
    xmlDoc.async = False
    xmlDoc.Load (xmlExportDoc)

    Set xmlNodeList = xmlDoc.SelectNodes("//llnode")

    For Each Node In xmlNodeList
        Call xmlParse(Node)
    Next

这仍然不起作用,在执行递归 xmlParse() 调用时出错,因为 MSXML2.IXMLDOMNode.ChildNodes 似乎不是 MSXML2.IXMLDOMNode 类型。

【问题讨论】:

    标签: xml vba ms-access recursion


    【解决方案1】:

    我认为你需要的是一个递归函数。我真的不知道 VBA 语法,所以请原谅伪代码,但你应该能够做这样的事情:

    Set xmlNodeList = xmlDoc.SelectNodes("/*/llnode")
    For Each node in xmlNodeList
        ListNodes(node)
    Next
    
    Function ListNodes(n As Node) 
         MsgBox n.nodeName & " " & n.NodeValue & " " & n.NodeType
         If n.HasChildNodes() Then
            MsgBox n.nodeName & "has child nodes"
            For Each n2 in n.ChildNodes
               ListNodes(n2)
            Next
            MsgBox "Done listing child nodes for " & n.nodeName
         End If   
    End Function
    

    【讨论】:

    • 我不知道为什么我之前没有考虑递归。非常感谢,我会试试这个。有什么理由为 /*/node 更改 //llnode 吗?
    • 是的,/*/llnode 选择顶级llnodes//llnode 在一个集合中选择文档中所有深度的所有 llnodes
    • 糟糕,我不是很熟悉 XML,我猜 /llnode 和 */llnode 也会产生不同的结果。事实上,我上面例子中的 也是一个 .
    • 我收到一个自动化错误,告诉我数据尚不可用(在执行 For Each node in xmlNodeList 时)。
    • 您是否从 Internet 检索 XML 文件?似乎 xmlDoc.Load() 方法可能是异步的。这个 SO question 似乎是指类似的问题:link
    【解决方案2】:

    到目前为止,这是我带来的:

    xmlExportDoc = "http://www.mysite.com/myDoc.xml"
    
    Dim xmldoc As MSXML2.DOMDocument
    Dim xmlNode As MSXML2.IXMLDOMNode
    Dim xmlNodeList As MSXML2.IXMLDOMNodeList
    Dim myNode As MSXML2.IXMLDOMNode
    
    Set xmldoc = New MSXML2.DOMDocument
    xmldoc.async = False
    xmldoc.Load (xmlExportDoc)
    Set xmlNodeList = xmldoc.getElementsByTagName("*")
    On Error Resume Next
    For Each xmlNode In xmlNodeList
        For Each myNode In xmlNode.ChildNodes
            'Debug.Print xmlNode.Attributes(0).Text
        Next myNode
    Next xmlNode
    Set xmldoc = Nothing
    

    如果层次结构不重要,它就可以工作,因为这个脚本只是循环遍历节点,无论它是什么级别。如果层次结构很重要,请查看 JLRishe 的答案。

    【讨论】:

      猜你喜欢
      • 2013-01-26
      • 1970-01-01
      • 2020-11-12
      • 2021-06-03
      • 1970-01-01
      • 2013-10-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多