VBA如果<object>是Nothing </object>

时间:2015-04-21 22:08:48

标签: excel vba excel-vba dom xml-parsing

我想测试一个对象,看看它是否不存在。如果它不存在,我只想显示一个MsgBox(或在单元格A1或其他东西中写入错误)。此XML中不存在Banana。

<?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>

测试代码:

Sub mySub()

Dim XMLFile As Variant
Dim Author As Object
Dim athr As String, BookType As String, Title As String, StoreLocation As String
Dim AuthorArray() As String, BookTypeArray() As String, TitleArray() As String, StoreLocationArray() As String
Dim i As Long, x As Long, j As Long, pn As Object, loc As Object, arr, ln As String, loc2 As Object

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

x = 1
j = 0


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

If Author Is Nothing Then
    MsgBox ("Not Found")
    Range("A1").Value = "Not found"
End If

If Not Author Is Nothing Then
    For i = 0 To (Author.Length - 1)

    athr = Author(i).Text

    If athr = "Ralls, Kim" Then

        Set pn = Author(i).ParentNode
        BookType = pn.getAttribute("id")
        Title = pn.getElementsByTagName("title").Item(0).nodeTypedValue

        AddValue AuthorArray, athr
        AddValue BookTypeArray, BookType
        AddValue TitleArray, Title
        AddValue StoreLocationArray, StoreLocation

        j = j + 1
        x = x + 1
    End If
Next
    Range("A3").Resize(j, 1).Value = WorksheetFunction.Transpose(AuthorArray)
    Range("B3").Resize(j, 1).Value = WorksheetFunction.Transpose(BookTypeArray)
End If

End Sub

'Utility method - resize an array as needed, and add a new value
Sub AddValue(arr, v)
    Dim i As Long
    i = -1
    On Error Resume Next
    i = UBound(arr) + 1
    On Error GoTo 0
    If i = -1 Then i = 0
    ReDim Preserve arr(0 To i)
    arr(i) = v
End Sub

为什么这个阻止什么都不做?我觉得VBA完全忽视了它。我甚至尝试在If语句中添加一个End。

If Author Is Nothing Then
    MsgBox ("Not Found")
    Range("A1").Value = "Not found"
    End
End If

此外,错误也会在打印范围行中引发..这是在If Not Author Is Nothing语句中。很奇怪。

1 个答案:

答案 0 :(得分:1)

循环仍在执行的原因只是If Author Is Nothing的计算结果为true。对XMLFile.SelectNodes的调用返回IXMLDOMNodeList,它是一个可枚举的容器。实际上,它可以与For Each语法一起使用的原因取决于此。通常,函数返回的任何枚举都会为您提供一个没有项目的枚举,而不是null对象。 For Each语法相当于这样做:

Do While Author.NextNode()
    '...
Loop

...或...

For i = 0 To (Author.Length - 1)
    '...
Next i

For Each只是具有更易读的好处。

您获得的错误实际上并不与您提出的问题相关,如果您没有&#,则更正XMLFile.SelectNodes("/catalog/book/banana")返回值的检查不会解决错误39;得到任何结果。错误在于如果它们没有被实例化,那么在循环之后尝试使用你的数组(尽管添加的End会解决这个问题)。

退出循环并到达此处时......

Range("A3").Resize(j, 1).Value = WorksheetFunction.Transpose(AuthorArray)
Range("B3").Resize(j, 1).Value = WorksheetFunction.Transpose(BookTypeArray)

...只有在您完成循环后,您的AuthorArray和BookTypeArray才会被初始化,因为您依靠Sub AddValue中的ReDim Preserve来初始化它们。这有2个解决方案。您可以在退货值的测试中放置一个Exit Sub:

If Author.Length = 0 Then
    MsgBox ("Not Found")
    Range("A1").Value = "Not found"
    Exit Sub
End If

或者您可以在函数开头初始化数组。

AuthorArray = Split(vbNullString)
BookTypeArray = Split(vbNullString)

这还有一个额外的好处,允许您跳过数组调整大小的所有环,以确定它们是否已初始化。 Split(vbNullString)将返回一个UBound为-1的数组(MyVariantArray = Array()将对Variant数组执行相同操作)。这允许您像这样重写Sub AddValue:

Sub AddValue(arr, v)
    ReDim Preserve arr(UBound(arr) + 1)
    arr(UBound(arr)) = v
End Sub

最后,我采取@ SOofXWLS的建议和@ barrowc的建议,并使用显式对象类型,因为你是迟到的绑定。这样,您的IntelliSense至少会显示自动完成列表。如果您不知道返回的对象类型,只需在对象浏览器中点击F2并检查:

SelectNodes in the Object Browser window

如果你不知道从哪里开始使用新的对象模型,你也可以使用这个快速而肮脏的技巧......

Dim XMLFile As Object
Set XMLFile = CreateObject("Microsoft.XMLDOM")
Debug.Print TypeName(XMLFile)   'DOMDocument

......然后......

Dim XMLFile As DOMDocument