情况:
我正在尝试检查变量a
,在本地窗口中显示为DispStaticNodeList
对象;每次我尝试这样做时Excel都会崩溃。
以下是本地窗口中变量a
,显然属于DispStaticNodeList
类型:
重现Excel崩溃:
For Each
循环播放它也会导致崩溃。* TestFail 研究亮点:
Excel
+ Crash
+ DispStaticNodeList
等组合产生的结果为零;至少使用我使用的Google搜索字词。很确定我的Google-Fu很弱。如果我相信这个article我正在处理MSHTML
支持的COM对象。
根据this:
如果名称是DispStaticNodeList,我们可以肯定它是一个 array ..(或者至少有数组语义)。
基于第3点,我编写了下面的代码TestPass
,它成功地循环了它,但我不完全理解为什么。我已经设置了一个对象然后循环它的len!
NodeList对象是节点的集合,例如返回的节点 Node.childNodes和document.querySelectorAll()等属性 方法
所以看起来这个对象可能是NodeList
,它给出了即时窗口中的描述似乎是正确的,作为一个列表,我可以遍历它的长度,但不确定为什么For Each
赢了& #39;工作以及Excel崩溃的原因。同事表示,由于数据的层次性,它可能会崩溃。我还注意到有一个名为IDOMNodeIterator
和NodeIterator
的类,但我不确定是否可以使用符合NodeList
方法here的描述。
问题:
什么是a
,为什么在尝试检查或循环For Each
时会导致Excel崩溃?
成功循环的代码:
Option Explicit
Public Sub TestPass()
Dim html As HTMLDocument
Set html = GetTestHTML
Dim a As Object, b As Object
Set a = html.querySelectorAll("div.intro p")
Dim i As Long
For i = 0 To Len(a) -1
On Error Resume Next
Debug.Print a(i).innerText '<== HTMLParaElement
On Error GoTo 0
Next i
End Sub
Public Function GetTestHTML(Optional ByVal url As String = "https://www.w3schools.com/cssref/trysel.asp") As HTMLDocument
Dim http As New XMLHTTP60
Dim html As New HTMLDocument
With http 'Set http = CreateObject("MSXML2.XMLHttp60")
.Open "GET", url, False
.send
html.body.innerHTML = .responseText
Set GetTestHTML = html
End With
End Function
* TestFail 导致崩溃的代码:
Public Sub TestFail()
Dim html As HTMLDocument
Set html = GetTestHTML
Dim a As Object, b As Object
Set a = html.querySelectorAll("div.intro p")
For Each b In a
Next b
End Sub
注意:
我向一位同事发送了一份测试工作簿,该同事也能够通过给出的示例重现此行为。
项目参考:
HTML示例(还提供了链接)
<div class="noSel">
<h1 style=""><span class="markup"><h1></span>Welcome to My Homepage<span class="markup"></h1></span></h1>
<div id="helpIntro" style="">
<span class="markup"><div class="intro"></span>
<div class="intro">
<p style="margin-top: 4px; border-color: rgb(255, 102, 102); background-color: rgb(255, 255, 153);"><span class="markup"><p></span>My name is Donald <span id="Lastname" style=""><span class="markup"><span id="Lastname"></span>Duck.<span class="markup"></span></span></span><span class="markup"></p></span></p>
<p id="my-Address" style="border-color: rgb(255, 102, 102); background-color: rgb(255, 255, 153);"><span class="markup"><p id="my-Address"></span>I live in Duckburg<span class="markup"></p></span></p>
<p style="margin-bottom: 4px; border-color: rgb(255, 102, 102); background-color: rgb(255, 255, 153);"><span class="markup"><p></span>I have many friends:<span class="markup"></p></span></p>
</div>
<span class="markup"></div></span>
</div>
<br>
<div class="helpUl">
<span class="markup"><ul id="Listfriends></span>
<ul id="Listfriends" style="margin-top:0px;margin-bottom:0px;">
<li><span class="markup"><li></span>Goofy<span class="markup"></li></span></li>
<li><span class="markup"><li></span>Mickey<span class="markup"></li></span></li>
<li><span class="markup"><li></span>Daisy<span class="markup"></li></span></li>
<li><span class="markup"><li></span>Pluto<span class="markup"></li></span></li>
</ul>
<span class="markup"></ul></span>
</div>
<ul style="display:none;"></ul>
<p style=""><span class="markup"><p></span>All my friends are great!<span class="markup"><br></span><br>But I really like Daisy!!<span class="markup"></p></span></p>
<p lang="it" title="Hello beautiful" style=""><span class="markup"><p lang="it" title="Hello beautiful"></span>Ciao bella<span class="markup"></p></span></p>
&#13;
编辑:我也能够以下列方式循环:
Public Sub Test()
Dim html As MSHTML.HTMLDocument, i As Long
Set html = GetTestHTML
For i = 0 To html.querySelectorAll("div.intro p").Length - 1
Debug.Print html.querySelectorAll("div.intro p")(i).innerText
Next i
End Sub
答案 0 :(得分:2)
如果名称是DispStaticNodeList,我们可以肯定它是一个数组..(或者至少具有数组语义)。
数组可以通常使用For Each
循环进行迭代,但it's more efficient使用For
循环迭代它们。看起来你所得到的并不是完全一个数组,虽然它似乎支持索引,但它显然不支持枚举,这可以解释当你尝试使用For Each
循环枚举时爆炸。
看起来 locals 工具窗口可能正在使用For Each
语义来列出集合中的项目。
我不熟悉那个特定的库,所以这是一些(有教养的)猜测,但是很容易制作一个不能用a迭代的自定义COM集合类型。 VBA中的For Each
循环 - 通常错误是在VBA端捕获的......似乎库的枚举器实现中可能存在错误(假设它有一个枚举器)它抛出一个异常,最终得不到处理,并以某种方式将所有东西都拿下来...事情是,你无法修复&amp;重新编译该库...所以你唯一能做的就是避免使用For Each
循环迭代该类型,并避免在 locals 工具窗口中扩展它(等等,...经常保存你的工作!)。
This article从C#/ .NET的角度给出了COM枚举如何工作的好主意。当然,该库不是托管代码(.NET),但是COM的概念是相同的。
TL; DR:不是因为For...Next
你可以For Each
;涉及的COM类型必须明确支持枚举。如果VBA代码使用For Each
循环编译,那么它确实如此,因此它必须是类型的枚举器中的错误。