当前位置: 首页 > 知识库问答 >
问题:

为什么使用MSXML v3.0解析XML文档可以工作,而MSXML v6.0却不能

苏坚成
2023-03-14

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

最近添加的是一个web调用,它返回以下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,这意味着

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

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一起工作?

如有任何意见,将不胜感激。

共有2个答案

狄阳华
2023-03-14

此处的快速测试表明,使用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的网站上。

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

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

夏弘义
2023-03-14

为了扩展@CindyMister的答案,问题似乎是使用getElementsByTagName()在MSXML版本之间处理命名空间。具体而言,XML维护一个不带冒号前缀的属性,该属性要求DOM库在解析内容时指定前缀:

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

但是,使用SelectionNamespaces将临时别名(如doc)定义为默认名称空间前缀,这两个库都会打印出预期的结果。而MS docs甚至建议采用后一种方法(重点补充):

getElementsByTagName方法模拟提供的参数与IXmlDomeElement的标记名属性结果的匹配。执行时,它不识别或不支持名称空间。相反,您应该使用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
 类似资料: