VBA中的LoadXML无法将字符串解析为可用的DOMDocument60

时间:2019-02-22 07:09:39

标签: excel xml vba xml-parsing

长期的读者,但在此先发帖。任何帮助都将受到高度赞赏!

我正在研究一个数据收集器,以从网格运算符获取我们客户的市场结果,并且需要一系列的xml查询。我能够使用SOAP模式(网格操作员要求)连接,认证并接收对我的查询的响应。但是,当我尝试使用LoadXML函数将从服务器接收到的xml字符串加载到DOMDocument60对象中时,它会从响应中剥离所有节点,并生成一个xml文档,其中只有一个节点中的标头,并串联一个存储在第二个节点中的字符串所有节点中的所有值。

因此,我无法提取所需的值。它们的长度各不相同,我无法知道一个值何时结束而下一个值开始。此外,由于已删除节点名称,因此当我尝试获取所有名为“ DSRSRREGAwardHourly”的节点的节点列表时,会得到一个空列表。

查询后从服务器收到的XML(为简化起见,我只留下了一个小时节点)

<?xml version='1.0' encoding='UTF-8'?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
  <Body>
    <QueryResponse xmlns="http://emkt.pjm.com/emkt/xml">
      <DSRSRREGAwardSet>
        <DSRSRREGAward day="2018-12-01" location="1960147390">
          <DSRSRREGAwardHourly hour="1">
            <SynchOfferMW>0.5</SynchOfferMW>
            <RegOfferMW>0</RegOfferMW>
            <SelfScheduledMW>0</SelfScheduledMW>
            <SynchAwardedMW>0</SynchAwardedMW>
            <RegAwardedMW>0</RegAwardedMW>
            <RegOfferPriceUsed>0</RegOfferPriceUsed>
            <RegdOfferMW>0</RegdOfferMW>
            <RegdMW>0</RegdMW>
          </DSRSRREGAwardHourly>
        </DSRSRREGAward>
      </DSRSRREGAwardSet>
    </QueryResponse>
  </Body>
</Envelope>

我正在使用的相关VBA代码

'Variable definition
Dim oWinhttp As WinHttpRequest
Dim ReturnXML As MSXML2.DOMDocument60
Dim ItemList As IXMLDOMNodeList
Dim XMLItem As IXMLDOMNode

'Variable initialization
Set oWinhttp = New WinHttpRequest
Set ReturnXML = New MSXML2.DOMDocument60

'Run the query against the server
With oWinhttp
  Call .Open("POST", WebURL)
  Call .SetRequestHeader("Cookie", "pjmauth=" & tokenStr)
  Call .SetRequestHeader("Content-Type", "text/xml")
  Call .SetRequestHeader("Content-Length", Len(xmlSubmittal))
  Call .Send(xmlSubmittal)
  Call .WaitForResponse

  'Store the return XML into DOM Document
  ReturnXML.async = False
  ReturnXML.validateOnParse = False
  ReturnXML.LoadXML (.ResponseText)

  'Terminate connection
  Call oWinhttp.abort
End With

'Extract nodes we are going to need
Set ItemList = ReturnXML.SelectNodes("//DSRSRREGAwardHourly")

1 个答案:

答案 0 :(得分:0)

使用名称空间的简单XML解析

尝试以下代码行

  • [1]通过以下方式设置名称空间定义

    ReturnXML.setProperty“ SelectionNamespaces”,xmlNameSpaces

其中xmlNameSpaces只是一个字符串变量,用于复制xmlns节点内的先前命名空间(<QueryResponse>)属性。

  • [2]通过节点结构执行非常基本的循环。由于显然每个节点中只有带有文本条目的子节点,因此此代码示例不检查空节点(考虑使用更详细的XPath解析和/或使用特殊的-平台独立的查询语言{{1 }} )。

相关代码段

XSLT

相关链接

C.f。 Obtain attribute names from XML using VBA

由于评论而产生的补遗

  

“我很好奇,这个问题是字符串定义了2个不同的名称空间,因此忽略了第二个吗?”

基本上;层次结构中的后一个声明取代xml数据示例中的前一个声明(明确前缀的元素名称除外)

  • a)具体示例中的整个XML结构仅显示“ normal” =无前缀的元素名称,例如' ... '[1] Store the return XML into DOM Document using name spaces defining a leading "d:" prefix ReturnXML.async = False ReturnXML.validateOnParse = False Dim xmlNameSpaces$ xmlNameSpaces = "xmlns:d=""http://emkt.pjm.com/emkt/xml""" ' define namespaces ReturnXML.setProperty "SelectionNamespaces", xmlNameSpaces ' set namespace prop ReturnXML.LoadXML (.ResponseText) ' get content '[2] Loop through node lists (attention to the chosen namespace prefix) Dim ItemList As MSXML2.IXMLDOMNodeList, ItemList2 As MSXML2.IXMLDOMNodeList Dim item As MSXML2.IXMLDOMNode, item2 As MSXML2.IXMLDOMNode Set ItemList = ReturnXML.SelectNodes("//d:DSRSRREGAwardHourly") ' <~~ leading "d:" :-) For Each item In ItemList Debug.Print "Day: " & item.SelectSingleNode("../@day").Text, _ "Hour: " & item.SelectSingleNode("./@hour").Text Set ItemList2 = item.SelectNodes("d:*") For Each item2 In ItemList2 Debug.Print vbTab & item2.nodeName, item2.Text Next item2 Next item (而不是可能基于的<SynchOfferMW>在先前的名称空间声明<extra:SynchOfferMW>中的其他显式前缀分配上)。对于无前缀的名称空间,您要声明两个默认名称空间,一个用于xmlns:extra="http://..."元素,第二个用于<Envelope>元素。
  • b)由于w3.org definition of namespaces/6.2 “,默认名称空间声明的范围从出现它的开始标签的开始一直延伸到相应结束标签的结尾,但不包括任何内部默认名称空间声明的范围。...默认名称空间声明适用于其范围内的所有未前缀元素的名称。“ 因此,本示例中的<QueryResponse>元素及其所有(未前缀)后代都属于第二个默认命名空间