Почему синтаксический анализ XML-документа с использованием MSXML v3.0 работает, а MSXML v6.0 - нет - PullRequest
3 голосов
/ 20 сентября 2019

Итак, я работаю над проектом, который собирает и собирает данные из разных источников в Интернете, используя множество различных методов в зависимости от характеристик каждого источника.

Самое последнее добавление - это веб-вызов APIкоторый возвращает следующее 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 полностью решает проблему.

Однако я бы предпочел придерживаться версии 6.0, поскольку она более активно поддерживается и поддерживается.

Почему это происходит?Это связано с самим XML?Это связано с моим кодом?Я что-то пропустил?Есть ли способ заставить его работать с Microsoft XML, v6.0?

Любой вклад будет оценен.

Ответы [ 2 ]

4 голосов
/ 20 сентября 2019

Чтобы расширить @ 1001 * ответ @ CindyMeister , проблема заключается в обработке пространства имен между версиями MSXML с использованием getElementsByTagName().В частности, ваш XML поддерживает атрибут xmlns без префикса, идентифицированного двоеточием, который требует от библиотек DOM назначать префикс при разборе содержимого:

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

Однако, используя SelectionNamespaces + SelectNodes для определения временного псевдонимаНапример, doc , к префиксу пространства имен по умолчанию обе библиотеки выводят ожидаемые результаты.И MS docs даже рекомендует последний метод (выделение добавлено):

Метод getElementsByTagName имитирует сопоставление предоставленного аргумента с результатом свойства tagNameIXMLDOMElement.При выполнении он не распознает и не поддерживает пространства имен .Вместо этого вам следует использовать метод 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
3 голосов
/ 20 сентября 2019

Быстрый тест здесь показывает, что нет узлов / элементов, выбранных с помощью 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, чтобы добавить префикс для пространства имен и ко всемэлементы.

...