У меня проблемы с синтаксическим анализом XML, возвращенного из API. Моя основная задача - получить свойства «использовано» и «ограничение» одного из узлов (с помощью xPath).

На данный момент мне даже не удается изучить все XML-дерево, поэтому я прошу помощи

Возвращенный XML выглядит так:

 <?xml version="1.0" encoding="UTF-8"?>
<QueryResultRecords xmlns="http://www.xmlns.loc/sub" type="application/some.app.query+xml" href="https://my.api.call.com/query?has_cheezburger" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xmlns.loc/sub http://my.api.address.com/schema/master.xsd">
    <OnlyNodeType Name="name1" link="hhttp://my.api.address.com/a5d11b73dffe" Used="240640"  Limit="0"  />
    <OnlyNodeType Name="name2" link="http://my.api.address.com/03b11042ccd4"  Used="10240"  Limit="409600" />
    <OnlyNodeType Name="name3" link="http://my.api.address.com/1cf43be18e2e"  Used="11934947"  Limit="20971520" />
</QueryResultRecords>

Я примерно понимаю, как XMLDom работает в VBA, но поискав в Интернете, мне удалось написать это, что, очевидно, не работает ...

Dim XMLDOC As MSXML2.DOMDocument60
Dim nodelist As IXMLDOMNodeList
Set XMLDOC = New MSXML2.DOMDocument60
XMLDOC.async = False
XMLDOC.validateOnParse = False
XMLDOC.Load (myhttpresponse)

Namespace = "xmlns: 'http://www.xmlns.loc/sub' "
Call XMLDOC.setProperty("SelectionNamespaces", Namespace)
Call XMLDOC.setProperty("SelectionLanguage", "XPath")

XPath = "/"

Set nodelist = XMLDOC.SelectNodes(XPath)
For i = 0 To nodelist.Length - 1
    Set Node = nodelist.NextNode
    Debug.Print Node.Text
Next i

Я думаю, что это проблема xml-treeing (я чего-то не понял в XMLDom?) Или проблема xmlns / xsi, и здесь я застрял полностью.

Может ли кто-нибудь помочь мне в этом?

0
Ariel 19 Дек 2016 в 15:42

1 ответ

Лучший ответ

Вы должны выбрать префикс пространства имен для каждого пространства имен, которое хотите использовать, даже если в XML нет префикса.

Здесь я использую sub для обозначения пространства имен http://www.xmlns.loc/sub.

Option Explicit

Sub Test()
    Dim XmlDoc As MSXML2.DOMDocument60
    Dim OnlyNodeType As MSXML2.IXMLDOMElement

    Set XmlDoc = GetXml("https://my.api.call.com/query?has_cheezburger")
    XmlDoc.setProperty "SelectionNamespaces", "xmlns:sub='http://www.xmlns.loc/sub'"

    For Each OnlyNodeType In XmlDoc.SelectNodes("//sub:OnlyNodeType")
        Debug.Print OnlyNodeType.GetAttribute("link")
    Next OnlyNodeType
End Sub

Function GetXml(url As String) As MSXML2.DOMDocument60
    With New MSXML2.XMLHTTP60
        .Open url
        .Send
        Set GetXml = .responseXML
        GetXml.setProperty "SelectionLanguage", "XPath"
    End With
End Function

XML имеет удобные возможности пространств имен по умолчанию (объявления пространств имен без явного префикса, например xmlns="http://foo" в отличие от xmlns:foo="http://foo"). Этого удобного средства для XPath нет. Здесь каждая ссылка на пространство имен должна быть явной.

Пока URI пространства имен совпадает, вы можете выбрать любой префикс, который вам нравится.

0
Tomalak 19 Дек 2016 в 19:53
Думаю, вы мне очень помогли, спасибо :) Небольшая проблема: Dim OnlyNodeType Поскольку MSXML2.DOMElement, похоже, не распознается VBA. Я загрузил MS XML v6.0, но все равно не упоминал об этом. Держу пари на твоей ошибке, но все же?
 – 
Ariel
19 Дек 2016 в 19:52
Конечно, я имел в виду IXMLDOMElement. Вы также можете использовать IXMLDOMNode. Узел является базовым типом элемента DOM - он предлагает меньше методов и свойств, но взамен работает для всех возможных типов результатов запроса XPath. Используйте обозреватель объектов (F2 в среде разработки VBA), чтобы изучить различия между различными объектами.
 – 
Tomalak
19 Дек 2016 в 19:56
Спасибо большое. Мне все еще нужно исправить указанный вами способ xPath, который на самом деле /sub:QueryResultRecords/sub:OnlyNodeType
 – 
Ariel
20 Дек 2016 в 11:58
/sub:QueryResultRecords/sub:OnlyNodeType и //sub:OnlyNodeType эквивалентны, по крайней мере, для показанного вами образца XML.
 – 
Tomalak
20 Дек 2016 в 13:22