DOM + XML问题+真正发生了什么?

时间:2014-09-23 22:38:05

标签: xml vba dom

我对XML和DOM很陌生。我试图从http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml

获取美元汇率

这段代码现在很有用,但我并没有真正掌握所发生的几个部分。

问题

  • 在XML文件中,我看到了几个" xmlns"标签,我知道这些是用于命名空间的,但我从未遇到过你有两个的情况。当我创建我的命名空间引用器时,为什么它是我使用的最后一个命名空间?

  • 当我选择我的节点时,我认为要进入Cube节点我应该使用xDOM.selectNodes(" / f:gesmes / f:gesmes / f:Cube&#34 ;)但是这个和f:gesmes的任何其他组合返回零(!)节点。我能够访问多维数据集节点的唯一方法是使用//表达式

  • 为什么没有错误处理程序代码不起作用?没有On Error Resume接下来代码会发出一个"对象变量或者没有设置块"错误

我的代码

Option Explicit

Private Sub run() ' run the whole operation'

Dim http_req As http_req: Set http_req = New http_req
Dim xDom As MSXML2.DOMDocument60
Set xDom = New MSXML2.DOMDocument60

Dim url As String: url = "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"
xDom.async = False
xDom.Load url

Do Until xDom.ReadyState = READYSTATE_COMPLETE
    DoEvents
Loop

Call find_ClassElement(xDom)

End Sub

Private Sub find_ClassElement(xDom As MSXML2.DOMDocument60)

Dim ticker As String
Dim if_USD As String

Dim xDOM_element As MSXML2.IXMLDOMElement
Dim xDOM_attribute As MSXML2.IXMLDOMAttribute
Dim xDom_selection As MSXML2.IXMLDOMSelection
Dim xDOM_nodeList As MSXML2.IXMLDOMNodeList

xDom.setProperty "SelectionNamespaces", "xmlns:f='http://www.ecb.int/vocabulary/2002-08-01/eurofxref'"

Set xDOM_nodeList = xDom.SelectNodes("//f:Cube")

For Each xDOM_element In xDOM_nodeList
        On Error Resume Next
        if_USD = xDOM_element.Attributes(0).text
        On Error GoTo 0
        If if_USD = "USD" Then
            ticker = xDOM_element.Attributes(1).text
        End If
        Next
    Debug.Print ticker
End Sub

2 个答案:

答案 0 :(得分:2)

关于问题#1,没有什么特别的,有多个名称空间,许多XML都有它。没有前缀(xmlns="....")的命名空间被识别为默认命名空间。基本上具有默认命名空间,所有后代节点和声明默认命名空间的节点都继承相同的命名空间。除非节点明确使用指向不同名称空间URI的前缀,或者在本地声明了不同的默认名称空间。

这就是为什么你需要注册f前缀并将其用于<Cube>节点的原因,尽管<Cube>没有自己的前缀或命名空间声明(因为它们从父节点<gesmes:Envelope>继承了默认命名空间。而且它自己的Envelope节点不在默认命名空间中,因为它有gesmes前缀。

关于问题#2,如果仔细查看XML,您将看到最内层<Cube>节点的正确路径如下:

/gesmes:Envelope/f:Cube/f:Cube/f:Cube

..在XPath中使用之前,您可能需要注册gesmes命名空间前缀(以及f前缀)。

关于问题#3,您可以使用纯XPath表达式来获得更清晰的美元汇率。更安全的方式:

//f:Cube[@currency='USD']

此XPath告诉只返回<Cube>属性值等于currency的{​​{1}}个节点。

答案 1 :(得分:1)

我不是一个高手,但通常可以通过它破解我的方式。我认为Cube节点不是“gesmes”命名空间的一部分。这回答#2。

不幸的是,我不知道你的第一点的答案。

对于#3,这不是我如何处理它,但你需要一种方法来处理没有属性的节点,或者不是你期望的节点。你可以这样做:

For Each xDOM_element In xDOM_nodeList
    If xDom_Element.attributes.length > 0 Then 
        if_USD = xDOM_element.attributes(0).Text
    Else
        if_USD = ""
    End If

    If if_USD = "USD" Then
        ticker = xDOM_element.Attributes(1).text
    End If
    Debug.Print ticker
Next