3

因此,我正在开展一个项目,该项目根据每个来源的特征使用多种不同的方法从互联网上的许多不同来源抓取和收集数据。

最近添加的是一个 WebAPI调用,它返回以下内容XML作为响应:

<?xml version="1.0"?>
<Publication_MarketDocument xmlns="urn:iec62325.351:tc57wg16:451-3:publicationdocument:7:0">
    <mRID>29b526a69b9445a7bb507ba446e3e8f9</mRID>
    <revisionNumber>1</revisionNumber>
    <type>A44</type>
    <sender_MarketParticipant.mRID codingScheme="A01">10X1001A1001A450</sender_MarketParticipant.mRID>
    <sender_MarketParticipant.marketRole.type>A32</sender_MarketParticipant.marketRole.type>
    <receiver_MarketParticipant.mRID codingScheme="A01">10X1001A1001A450</receiver_MarketParticipant.mRID>
    <receiver_MarketParticipant.marketRole.type>A33</receiver_MarketParticipant.marketRole.type>
    <createdDateTime>2019-09-19T11:28:51Z</createdDateTime>
    <period.timeInterval>
        <start>2019-09-18T22:00Z</start>
        <end>2019-09-19T22:00Z</end>
    </period.timeInterval>
    <TimeSeries>
        <mRID>1</mRID>
        <businessType>A62</businessType>
        <in_Domain.mRID codingScheme="A01">10YCS-SERBIATSOV</in_Domain.mRID>
        <out_Domain.mRID codingScheme="A01">10YCS-SERBIATSOV</out_Domain.mRID>
        <currency_Unit.name>EUR</currency_Unit.name>
        <price_Measure_Unit.name>MWH</price_Measure_Unit.name>
        <curveType>A01</curveType>
        <Period>
            <timeInterval>
                <start>2019-09-18T22:00Z</start>
                <end>2019-09-19T22:00Z</end>
            </timeInterval>
            <resolution>PT60M</resolution>
            <Point>
                <position>1</position>
                <price.amount>44.08</price.amount>
            </Point>
            <Point>
                <position>2</position>
                <price.amount>37.14</price.amount>
            </Point>
            <Point>
                <position>3</position>
                <price.amount>32.21</price.amount>
            </Point>
            <Point>
                <position>4</position>
                <price.amount>31.44</price.amount>
            </Point>
            <Point>
                <position>5</position>
                <price.amount>32.48</price.amount>
            </Point>
            <Point>
                <position>6</position>
                <price.amount>45.52</price.amount>
            </Point>
            <Point>
                <position>7</position>
                <price.amount>56.05</price.amount>
            </Point>
            <Point>
                <position>8</position>
                <price.amount>74.96</price.amount>
            </Point>
            <Point>
                <position>9</position>
                <price.amount>74.08</price.amount>
            </Point>
            <Point>
                <position>10</position>
                <price.amount>69.03</price.amount>
            </Point>
            <Point>
                <position>11</position>
                <price.amount>72.89</price.amount>
            </Point>
            <Point>
                <position>12</position>
                <price.amount>68.91</price.amount>
            </Point>
            <Point>
                <position>13</position>
                <price.amount>74.95</price.amount>
            </Point>
            <Point>
                <position>14</position>
                <price.amount>72.91</price.amount>
            </Point>
            <Point>
                <position>15</position>
                <price.amount>75.97</price.amount>
            </Point>
            <Point>
                <position>16</position>
                <price.amount>76.49</price.amount>
            </Point>
            <Point>
                <position>17</position>
                <price.amount>59.08</price.amount>
            </Point>
            <Point>
                <position>18</position>
                <price.amount>60.19</price.amount>
            </Point>
            <Point>
                <position>19</position>
                <price.amount>64.69</price.amount>
            </Point>
            <Point>
                <position>20</position>
                <price.amount>69.18</price.amount>
            </Point>
            <Point>
                <position>21</position>
                <price.amount>64.97</price.amount>
            </Point>
            <Point>
                <position>22</position>
                <price.amount>63.38</price.amount>
            </Point>
            <Point>
                <position>23</position>
                <price.amount>52.92</price.amount>
            </Point>
            <Point>
                <position>24</position>
                <price.amount>48.08</price.amount>
            </Point>
        </Period>
    </TimeSeries>
</Publication_MarketDocument> 

使用成功处理此类情况后,Microsoft XML, v6.0我尝试了以下方法:

Dim respXML As New MSXML2.DOMDocument60
respXML.LoadXML (ThisWorkbook.Worksheets("Sheet2").Range("A1")) 'for the sake of the post's simplicity I'm loading the xml from excel
Debug.Print respXML.getElementsByTagName("price.amount").Length

这应该返回24,但它返回0。确实如下:

Debug.Print respXML.getElementsByTagName("price.amount")(1) Is Nothing

返回True,这意味着<price.amount></price.amount>没有找到元素。但是,Debug.Print respXML.XML会产生预期的结果。

我在某处读到早期绑定可能会导致问题,所以我也尝试了以下方法:

Dim respXML As Object
Set respXML = CreateObject("MSXML2.DOMDocument.6.0")
respXML.LoadXML (ThisWorkbook.Worksheets("Sheet2").Range("A1"))
Debug.Print respXML.getElementsByTagName("price.amount").Length
Debug.Print respXML.getElementsByTagName("price.amount")(1) Is Nothing

结果还是一样的。

切换到Microsoft XML, v3.0完全解决问题。

但是,我更愿意坚持使用 v6.0,因为它是得到更积极维护和支持的版本。

为什么会这样?它与 XML 本身有关吗?它与我的代码有关吗?我错过了什么吗?有没有办法让它工作Microsoft XML, v6.0

任何输入将不胜感激。

4

2 回答 2

4

为了扩展@CindyMeister 的答案,问题似乎是使用getElementsByTagName(). 具体来说,您的 XML 维护一个xmlns没有冒号标识前缀的属性,这需要 DOM 库在解析内容时分配前缀:

<Publication_MarketDocument xmlns="urn:iec62325.351:tc57wg16:451-3:publicationdocument:7:0" ...

但是,使用SelectionNamespaces+SelectNodes将临时别名(例如doc)定义为默认命名空间前缀,这两个库都会打印出预期的结果。MS docs甚至建议使用后一种方法(强调):

getElementsByTagName方法模拟提供的参数与 的tagName属性 结果的匹配IXMLDOMElement。执行时,它不识别或不支持命名空间。相反,您应该使用selectNodes方法,该方法 在某些情况下速度更快,并且可以支持更复杂的搜索。

MXSML v3.0 (打印意外getElementsByTagName结果)

Sub ParseXMLv3()
    Dim respXML As New MSXML2.DOMDocument30

    respXML.Load "C:\Path\To\Input.xml"
    respXML.setProperty "SelectionLanguage", "XPath"
    respXML.setProperty "SelectionNamespaces", "xmlns:doc='urn:iec62325.351:tc57wg16:451-3:publicationdocument:7:0'"

    Debug.Print respXML.SelectNodes("//doc:price.amount").Length       ' PRINTS 24
    Debug.Print respXML.SelectNodes("//price.amount").Length           ' PRINTS 0
    Debug.Print respXML.getElementsByTagName("price.amount").Length    ' PRINTS 24

    Set respXML = Nothing
End Sub

MSXML v6.0

Sub ParseXMLv6()
    Dim respXML As New MSXML2.DOMDocument60

    respXML.Load "C:\Path\To\Input.xml"
    respXML.setProperty "SelectionLanguage", "XPath"
    respXML.setProperty "SelectionNamespaces", "xmlns:doc='urn:iec62325.351:tc57wg16:451-3:publicationdocument:7:0'"

    Debug.Print respXML.SelectNodes("//doc:price.amount").Length       ' PRINTS 24
    Debug.Print respXML.SelectNodes("//price.amount").Length           ' PRINTS 0
    Debug.Print respXML.getElementsByTagName("price.amount").Length    ' PRINTS 0

    Set respXML = Nothing
End Sub
于 2019-09-20T16:32:44.287 回答
3

此处的快速测试表明,没有使用DOMDocument60.

我成功使用DOMDocument30,仍在使用 MSXML6 解析器。因此,这可能是您的解决方法:

'Using the MSXML6 parser, it's still possible to use what worked in older versions
Dim respXML As Msxml2.DOMDocument30
Set respXML = CreateObject("MSXML2.DOMDocument.3.0")

互联网上的研究发现了两个有用的链接,一个在MSDN上,另一个在 VB 论坛上。

第一个基本上说安全属性是在 MSXML6 中添加的,这意味着在 MSXML2 中有效的一些东西在新版本中不再适用。这些都记录在 Microsoft^s 网站上。

我不知道它是哪一个(如果有的话,但最接近的似乎是SelectionNamespace属性),但另一个变化似乎是解析器如何处理“匿名”命名空间(VB 论坛链接)。如果命名空间是在顶级元素中声明的,没有前缀,那么它不会应用于任何子元素 - 所以它们不会“看到”。

由于问题中的 XML 代码包含没有前缀的命名空间,这似乎是问题所在。如果声明DOMDocument30对您不起作用,并且 SelectionNamespace 没有帮助,那么我认为唯一的办法是更改/转换 XML 为命名空间所有元素添加前缀。

于 2019-09-20T15:11:11.370 回答