【问题标题】:VBA DOM ParentNode SelectSingleNodeVBA DOM ParentNode SelectSingleNode
【发布时间】:2015-06-14 02:41:56
【问题描述】:
<?xml version="1.0"?>
<catalog>
<book id="Adventure">
   <author>Gambardella, Matthew</author>
   <title>XML Developer's Guide</title>
   <price>44.95</price>
</book>
<book id="Adventure">
   <author>Ralls, Kim</author>
   <title>Midnight Rain</title>
   <price>5.95</price>
</book>
<book id="Adventure">
   <author>Boal, John</author>
   <title>Mist</title>
   <price>15.95</price>
</book>
<book id="Mystery">
   <author>Ralls, Kim</author>
   <title>Some Mystery Book</title>
   <price>9.95</price>
</book>
</catalog>

我的程序搜索特定作者(“Ralls, Kim”)的所有项目,同时收集 BookType(“book id”)并将值放入数组中。

但现在的问题是图书 ID 并不总是相同。因此,既然我已经确定了父节点是什么,我想取出 BookTitle - 这样我就不必在 XPATH 中放置一个已经存储在数组中的变量(这对我来说听起来像是一场噩梦)。

Sub mySub()

Dim XMLFile As Variant
Dim Author As Variant
Dim athr As String, BookType As String, Title As String
Dim AuthorArray() As String, BookTypeArray() As String, TitleArray() As  String
Dim i As Long, x As Long, j As Long

Dim mainWorkBook As Workbook
Dim n As IXMLDOMNode
Set mainWorkBook = ActiveWorkbook
Set XMLFile = CreateObject("Microsoft.XMLDOM")
XMLFile.Load ("C:\Books.xml")


x = 1
j = 0

Set Author = XMLFile.SelectNodes("/catalog/book/author/text()")
For i = 0 To (Author.Length - 1)
    ReDim Preserve AuthorArray(0 To i)
    ReDim Preserve BookTypeArray(0 To i)
    ReDim Preserve TitleArray(0 To i)
    athr = Author(i).NodeValue
    BookType = Author(i).ParentNode.ParentNode.getAttribute("id")
    Title = Author(i).ParentNode.SelectSingleNode("title")

    If athr = "Ralls, Kim" Then

        AuthorArray(j) = athr
        BookTypeArray(j) = BookType
        TitleArray(j) = Title

        j = j + 1
        x = x + 1
    End If
Next



Range("A3:A" & UBound(AuthorArray) + 1) = WorksheetFunction.Transpose(AuthorArray)
Range("B3:B" & UBound(BookTypeArray) + 1) = WorksheetFunction.Transpose(BookTypeArray)
Range("C3:C" & UBound(BookTypeArray) + 1) = WorksheetFunction.Transpose(TitleArray)


End Sub

我在这行代码中不断收到对象错误,我不明白为什么:

Title = Author(i).ParentNode.SelectSingleNode("title")

感谢您的任何帮助和建议。

【问题讨论】:

    标签: xml vba dom xpath xml-parsing


    【解决方案1】:

    不熟悉 VBA,但很可能因为这一行而出现错误

    Set Author = XMLFile.SelectNodes("/catalog/book/author/text()")
    

    Author 变量(?) 设置为字符串 值,text() 表示作为上下文元素的直接子级的所有文本节点的串联。字符串与元素非常不同,它们没有属性,也没有子元素。

    他们确实有一个父节点,但是

    BookType = Author(i).ParentNode.getAttribute("id")
    

    将尝试检索此类文本节点的父节点的id 属性,这是一个author 元素 - 但author 元素没有id 属性。

    改变

    Set Author = XMLFile.SelectNodes("/catalog/book/author/text()")
    

    Set Author = XMLFile.SelectNodes("/catalog/book/author")
    

    如果有帮助,请告诉我。


    编辑:我想我找到了一个可行的解决方案,以下如何。但是,我对 VBA 绝对不熟悉 - 我确信这不是一个非常优雅的解决方案,并且可以改进很多。

    Sub mySub()
    
    Dim XMLFile As MSXML2.DOMDocument
    Dim Author As Variant
    Dim athr As String, BookType As String, Title As String
    Dim AuthorArray() As String, BookTypeArray() As String, TitleArray() As String
    Dim i As Long, x As Long, j As Long
    
    Dim mainWorkBook As Workbook
    Dim n As IXMLDOMNode
    Set mainWorkBook = ActiveWorkbook
    Set XMLFile = CreateObject("Microsoft.XMLDOM")
    XMLFile.Load ("vba.xml")
    
    
    x = 1
    j = 0
    
    Set Author = XMLFile.SelectNodes("/catalog/book/author")
    For i = 0 To (Author.Length - 1)
        ReDim Preserve AuthorArray(0 To i)
        ReDim Preserve BookTypeArray(0 To i)
        ReDim Preserve TitleArray(0 To i)
        athr = Author(i).Text
        BookType = Author(i).ParentNode.getAttribute("id")
        Title = Author(i).ParentNode.getElementsByTagName("title").Item(0).nodeTypedValue
    
        If athr = "Ralls, Kim" Then
    
            AuthorArray(j) = athr
            BookTypeArray(j) = BookType
            TitleArray(j) = Title
    
            j = j + 1
            x = x + 1
        End If
    Next
    
    
    
    Range("A3:A" & UBound(AuthorArray) + 1) = WorksheetFunction.Transpose(AuthorArray)
    Range("B3:B" & UBound(BookTypeArray) + 1) = WorksheetFunction.Transpose(BookTypeArray)
    Range("C3:C" & UBound(BookTypeArray) + 1) = WorksheetFunction.Transpose(TitleArray)
    
    
    End Sub
    

    结果

    Ralls, Kim  Adventure   Midnight Rain
    Ralls, Kim  Mystery     Some Mystery Book
    

    第二次编辑

    你能解释一下Title = Author(i).ParentNode.getElementsByTagName("title").Item(0).nodeTypedValue这一行中Item(0)在做什么吗?

    getElementsByTagName() 返回一个元素的集合,即使只有一个结果 - 它最终会出现在一个只有一项的集合中。 Item(0) 选择此集合中的第一个元素。

    然后,nodeTypedValue 返回对象的值,具体取决于其数据类型。顺便说一句,NodeValue 属性 only works on attributes - 这就是您的代码返回错误的原因。

    另外,是否需要在节点的 XPath 中使用 /text()(它似乎也不影响数字或任何东西)?

    (终于找到让我满意的东西了!我想你会从 XPath 的介绍或教程中受益。)

    text() 一个被过度使用的结构,但是是的,它有一些用途。可以这样想:当 XML 被读入内存时,会构造一个树状表示。在这种表示中,各种对象都是节点;元素是节点,属性是节点 - 文本内容是节点。

    现在,像这样的 XPath 表达式

    /catalog/book/author
    

    选择一个元素节点(或者,可能是一组元素节点)。在您的情况下,它是一个元素节点,其子节点为文本节点。将路径表达式扩展到

    /catalog/book/author/text()
    

    只选择author 元素的子文本节点。重要的是要了解元素及其文本内容是不同的。

    【讨论】:

    • 感谢您的回复 Mathias :) 不幸的是,在 VBA 中,text() 是必需的,因为它本质上是说“嘿,获取 /author 之后的文本”。具体来说,我得到的错误是运行时错误'91':对象变量或未设置块变量。当我删除那行代码时,我的程序就可以工作了。我认为这与语法有关,因为如果我将其设置为 Title = Author(i).ParentNode.ParentNode.getAttribute("id") 之类的东西,它就可以工作。
    • @NRH 这就是我想要解释的。只有这个文本节点的祖父节点真正具有id 属性。
    • @NRH 另外,为什么在 VBA 中需要text()
    • 嗨,Mathias - 这是我从网上阅读中学到的;不过我可能是错的,因为我对此仍然很陌生。我确实尝试了您的建议,它在athr = Author(i).NodeValue 行给出了 Run-time error '94' Invalid use of Null
    • @NRH 不,总是不鼓励遍历一组想要的节点并搜索下一个兄弟节点。请查看我的编辑 - 我现在自己测试了这个。对 VBA 完全不熟悉,大部分只是反复试验。
    猜你喜欢
    • 2019-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-26
    • 1970-01-01
    • 2019-07-25
    相关资源
    最近更新 更多