excel - 如果前一个节点为空,为什么 Object.Selectnodes(XPath) 会获得第一个节点值

标签 excel xml vba xmldom

为什么Object.SelectNodes(XPath)如果前一个节点(真正的第一个节点值)为空,则作为第一个节点值获取第二个节点值。
下面的例子:

XML:

<?xml version="1.0" encoding="UTF-8"?>
<Document>
    <person>
    </person>
    <person>
           <name>Peter</name>
    </person>
</Document>

VBA代码:

Dim j as Integer
Dim FileToOpen as Variant
FileToOpen = Application.GetOpenFilename(Filefilter:="XML Files (*.xml), *.xml", _
Title:="Choose XML document ", MultiSelect:=False)
Set XDoc = CreateObject("MSXML2.DOMDocument")
    XDoc.async = False: XDoc.validateOnParse = False
    XDoc.Load FileToOpen

    For j = 1 To 2
        Set tofields = XDoc.SelectNodes("//Document/person/name")
        If Not (tofields.Item(j)) Is Nothing Then
            Debug.Print tofields.Item(j).Text
        Else
            Debug.Print "Nothing"
        End If
    Next j

结果:
Peter
Nothing

为什么结果中没有“Nothing”?如何达到?如果父节点不包括第一个子节点,则省略第一次迭代。
谢谢你。

最佳答案

XMLDOM 中的枚举不同于 XPath

XMLDOM 语法枚举 nodes作为 基于零的 NodeList 中的项目,即从 0 开始,而标识子节点的 XPath 表达式从 1 开始(例如,调用名字项目 "//name[1]" )。考虑 2 时的错误作为最后一项索引,而不是从 .Item(0) 循环至.Item(1)在您的示例代码中。您可以通过节点列表的 .Length 获得找到的项目数结果。方法(2 减 1 导致 1 作为最后一个索引号,因此给出 0 到 1 的名称节点系列)。

此外,建议引用 MSXML2 版本 6.0 (MSXML2.DOMDocument 指的是仅出于兼容性原因使用的最后一个稳定版本 3.0)。

进一步的提示,假设您想要遍历所有 在您的 XML 文档中(OP 中的节点列表仅提供一项,因为 name 节点仅存在一次):

  • 表达式 xDoc.SelectNodes("//Document/person")//person将在给定节点结构内的任何层次结构级别搜索定义的节点集。因此,明确使用 Set toFields = xDoc.DocumentElement.SelectNodes("person") 更省时在你的情况下。
  • 以下代码示例不会显示 Nothing例,因为节点列表显示两个 name仅节点(For i = 0 To toFields.Length - 1)。只是为了检查您的原始尝试,您可以通过专心更改为 For i = 0 To toFields.Length 来枚举最多三个项目。 (即 0 to 2 )。

  • 附加链接

    通过递归调用分析您的 XML 结构;一个工作函数可以在 Parse XML using XMLDOM 找到.

    代码示例
        Dim xDoc As Object, toFields As Object
        Dim myName As String, i As Long
        Set xDoc = CreateObject("MSXML2.DOMDocument.6.0")   ' recommended version 6.0 (if late bound MSXML2)
        xDoc.async = False: xDoc.validateOnParse = False
        ' ...
    
        Set toFields = xDoc.DocumentElement.SelectNodes("person")
        For i = 0 To toFields.Length - 1
            If Not toFields.Item(i) Is Nothing Then
                If toFields.Item(i).HasChildNodes Then
                   myName = toFields.Item(i).SelectSingleNode("name").Text
                   Debug.Print i, IIf(Len(Trim(myName)) = 0, "**Empty name", myName)
    
                Else
                   Debug.Print i, "**No name node**"
                End If
            Else
                Debug.Print i, "**Nothing**"            ' shouldn't be needed from 0 to .Length-1 items :-)
            End If
        Next i
    
    

    关于excel - 如果前一个节点为空,为什么 Object.Selectnodes(XPath) 会获得第一个节点值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55960631/

    相关文章:

    vba - 使用 VBA if 语句通过按钮隐藏/取消隐藏列

    Java 将 'Excel Date Serial Number' 转换为 'DateTime'

    excel - 自动将 B 列上的链接添加到 Excel 中 A 列中的字符串

    excel - excel中的动态下拉菜单(最好不是VBA)

    python - 我们可以在 Beautifulsoup 中将所有 XML 标签转换为小写吗

    java - 编写以 xml 格式返回表数据的 servlet 的简单方法

    r - 如何编写R来循环设置目录中每个文件的每个工作表

    ios - 从解析的 XML 将数据加载到 TableView

    Excel 加载项有时无法加载

    vba - 遍历已发送邮件文件夹-点击非邮件项目时出错