【问题标题】:'SelectSingleNode' XPath query from XML with multiple Namespaces来自具有多个命名空间的 XML 的“SelectSingleNode”XPath 查询
【发布时间】:2016-03-24 00:02:53
【问题描述】:

这是我试图解析的示例 XML 的一部分:

<GetCompetitivePricingForASINResponse xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01">
    <GetCompetitivePricingForASINResult ASIN="B014P3CM08" status="Success">
        <Product xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01" xmlns:ns2="http://mws.amazonservices.com/schema/Products/2011-10-01/default.xsd">
            <Identifiers>
                <MarketplaceASIN>
                    <MarketplaceId>A1F83G8C2ARO7P</MarketplaceId>
                    <ASIN>B014P3CM08</ASIN>
                </MarketplaceASIN>
            </Identifiers>
            <CompetitivePricing>
                <CompetitivePrices>
                    <CompetitivePrice belongsToRequester="false" condition="New" subcondition="New">
                        <CompetitivePriceId>1</CompetitivePriceId>
                            <Price>
                                <LandedPrice>
                                    <CurrencyCode>GBP</CurrencyCode>
                                    <Amount>24.00</Amount>
                                </LandedPrice>
                                <ListingPrice>
                                    <CurrencyCode>GBP</CurrencyCode>
                                    <Amount>24.00</Amount>
                                </ListingPrice>
                                <Shipping>
                                    <CurrencyCode>GBP</CurrencyCode>
                                    <Amount>0.00</Amount>
                                </Shipping>
                            </Price>
                        </CompetitivePrice>
                    </CompetitivePrices>
.... etc

我正在尝试从 /Price/LandedPrice/Amount/ 节点(在本例中为24.00)定位和检索文本。这是我到目前为止的 VBA 代码:

Dim strXMLSite As String
Dim objXMLHTTP As MSXML2.XMLHTTP60
Dim objXMLDoc As MSXML2.DOMDocument60
Dim objXMLNode1 As MSXML2.IXMLDOMNode

Set objXMLHTTP = New MSXML2.XMLHTTP60
Set objXMLDoc = New MSXML2.DOMDocument60

Call MWSProductAPI

strXMLSite = Worksheets("Settings").Range("B12").Value

objXMLHTTP.Open "GET", strXMLSite, False
objXMLHTTP.send
objXMLDoc.LoadXML (objXMLHTTP.responseText)

XmlNamespaces = "xmlns:ns2='http://mws.amazonservices.com/schema/Products/2011-10-01/default.xsd' xmlns:ns1='http://mws.amazonservices.com/schema/Products/2011-10-01'"

objXMLDoc.setProperty "SelectionNamespaces", XmlNamespaces

Set objXMLNode1 = objXMLDoc.SelectSingleNode("/ns2:GetCompetitivePricingForASINResponse/ns2:GetCompetitivePricingForASINResult/ns2:Product/ns2:CompetitivePricing/ns2:CompetitivePrices/ns2:CompetitivePrice/ns2:Price/ns2:LandedPrice/ns2:Amount")
Worksheets("Settings").Range("C8").Value = objXMLNode1.text

但是,当我在 Excel 中运行代码时,它会返回错误:

'对象变量或未设置块引用'。

调试代码显示 SelectSingleNode 没有返回任何内容。我对命名空间前缀以及它如何适应 XPath 的理解非常有限。我可以找到很多带有命名空间的 XML 示例,但是,有多个命名空间的示例非常有限。

【问题讨论】:

  • 您尝试获取的元素位于命名空间xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01" 中。在您的属性“SelectionNamespaces”中,这是ns1而不是ns2
  • 是的,就像 axel 说您缺少第一个命名空间一样,您可以通过以 // 开头来跳过产品上方的元素,例如//ns2:Product
  • 另外元素Product不在命名空间ns2中。在发布的XML 代码中,没有任何元素位于此命名空间中。
  • 啊,很好看,xmlns:ns2 应该是xsi:schemaLocation,不知道你为什么要使用架构的名称作为命名空间!

标签: xml vba excel xpath


【解决方案1】:

因为你在根标签中有一个默认的命名空间,你只需要声明一个命名空间,而不是多个。考虑在删除其他声明时进行以下调整:

XmlNamespaces = "xmlns:ns2='http://mws.amazonservices.com/schema/Products/2011-10-01'"

objXMLDoc.setProperty "SelectionNamespaces", XmlNamespaces

Set objXMLNode1 = objXMLDoc.SelectSingleNode("/ns2:GetCompetitivePricingForASINResponse" _
                            & "/ns2:GetCompetitivePricingForASINResult/ns2:Product" _
                            & "/ns2:CompetitivePricing/ns2:CompetitivePrices" _
                            & "/ns2:CompetitivePrice/ns2:Price/ns2:LandedPrice/ns2:Amount")

顺便说一句,您可以缩短 XPath 表达式:

Set objXMLNode1 = objXMLDoc.SelectSingleNode("//ns2:Price/ns2:LandedPrice/ns2:Amount")

即使使用列表也应该出现多个LandedPrice(但将声明更改为节点列表并使用索引表示法作为返回值):

...
Dim objXMLNode1 As MSXML2.IXMLDOMNodeList
...

Set objXMLNode1 = objXMLDoc.DocumentElement.SelectNodes(" _
                       & //ns2:Price/ns2:LandedPrice/ns2:Amount")

Worksheets("Settings").Range("C8").Value = objXMLNode1(0).Text

【讨论】:

  • 完美运行!感谢您的详细解释,这对我来说已经解释了很多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-13
相关资源
最近更新 更多