我如何使用 PHP 从这个 Amazon XML 响应文件中获取数据?

How can I get data from this Amazon XML response file using PHP?

如何从如下所示的亚马逊 MWS XML 文件中提取值?

遗憾的是我不太擅长 PHP(或 XML)。我已经 reading/trying 在我能找到的所有网站上找到了所有我能找到的东西,但我认为我只是不能胜任这份工作。

我试过DOM、简单XML、命名空间等等,但一定是完全搞错了。

我试过这段代码:

    $response = $service->GetMyPriceForASIN($request);

    $dom = new DOMDocument();
    $dom->loadXML($response->toXML());
    $dom->preserveWhiteSpace = false;
    $dom->formatOutput = true;
    $dom->saveXML();     

    $x = $dom->documentElement;
    foreach ($x->childNodes AS $item) {
    print $item->nodeName . " = " . $item->nodeValue . "<br>";
    }

然而,它仅 returns 来自最外层节点的数据,如下所示:

GetMyPriceForASINResult = xxxxxxxxxxxB07DNYLZP5USD9.97USD9.97USD0.00USD15.99AMAZONNewNewxxxxxxxxxxxxxDazzle Tattoos ResponseMetadata = xxxxxxxxxxxxxxxxxxxxxxxx

我只是想获取 [Offers] 节点下子节点的货币和价格。

<?xml version="1.0"?>
<GetMyPriceForASINResponse 
xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01">
  <GetMyPriceForASINResult ASIN="B07DNYLZP5" status="Success">
    <Product>
      <Identifiers>
        <MarketplaceASIN>
          <MarketplaceId>xxxxxxxxxxxxxxxxxx</MarketplaceId>
          <ASIN>B07DNYLZP5</ASIN>
        </MarketplaceASIN>
      </Identifiers>
      <Offers>
        <Offer>
          <BuyingPrice>
            <LandedPrice>
              <CurrencyCode>USD</CurrencyCode>
              <Amount>9.97</Amount>
            </LandedPrice>
            <ListingPrice>
              <CurrencyCode>USD</CurrencyCode>
              <Amount>9.97</Amount>
            </ListingPrice>
            <Shipping>
              <CurrencyCode>USD</CurrencyCode>
              <Amount>0.00</Amount>
            </Shipping>
          </BuyingPrice>
          <RegularPrice>
            <CurrencyCode>USD</CurrencyCode>
            <Amount>15.99</Amount>
          </RegularPrice>
          <FulfillmentChannel>AMAZON</FulfillmentChannel>
          <ItemCondition>New</ItemCondition>
          <ItemSubCondition>New</ItemSubCondition>
          <SellerId>xxxxxxxxxx</SellerId>
          <SellerSKU>Dazzle Tattoos</SellerSKU>
        </Offer>
      </Offers>
    </Product>
  </GetMyPriceForASINResult>
  <ResponseMetadata>
    <RequestId>xxxxxxxxxxxxxxxxxxxxx</RequestId>
  </ResponseMetadata>
</GetMyPriceForASINResponse>

更新

Nigel 提供的 link 没有帮助 - 它基本上是信息概要。

XML 一般来说, 相当容易使用,但是您偶然发现了使它变得更加棘手的事情之一:XML名称空间。这是由外部元素中 xmlns 属性的存在给出的。

我看到您的文档时的第一个想法是,由于我不熟悉这个 API,所以 "offers" 听起来可能是复数。因此,我修改了测试文档以允许这样做,因为 <Offers> 可能被设计为包含零个、一个或多个 <Offer>.

因此,出于测试目的,它看起来像这样(为了方便,我刚刚复制了单个 <Offer>):

<?xml version="1.0"?>
<GetMyPriceForASINResponse 
    xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01"
>
  <GetMyPriceForASINResult ASIN="B07DNYLZP5" status="Success">
    <Product>
      <Identifiers>
        <MarketplaceASIN>
          <MarketplaceId>xxxxxxxxxxxxxxxxxx</MarketplaceId>
          <ASIN>B07DNYLZP5</ASIN>
        </MarketplaceASIN>
      </Identifiers>
      <Offers>
        <Offer>
          <BuyingPrice>
            <LandedPrice>
              <CurrencyCode>USD</CurrencyCode>
              <Amount>9.97</Amount>
            </LandedPrice>
            <ListingPrice>
              <CurrencyCode>USD</CurrencyCode>
              <Amount>9.97</Amount>
            </ListingPrice>
            <Shipping>
              <CurrencyCode>USD</CurrencyCode>
              <Amount>0.00</Amount>
            </Shipping>
          </BuyingPrice>
          <RegularPrice>
            <CurrencyCode>USD</CurrencyCode>
            <Amount>15.99</Amount>
          </RegularPrice>
          <FulfillmentChannel>AMAZON</FulfillmentChannel>
          <ItemCondition>New</ItemCondition>
          <ItemSubCondition>New</ItemSubCondition>
          <SellerId>xxxxxxxxxx</SellerId>
          <SellerSKU>Dazzle Tattoos</SellerSKU>
        </Offer>
        <Offer>
          <BuyingPrice>
            <LandedPrice>
              <CurrencyCode>USD</CurrencyCode>
              <Amount>9.97</Amount>
            </LandedPrice>
            <ListingPrice>
              <CurrencyCode>USD</CurrencyCode>
              <Amount>9.97</Amount>
            </ListingPrice>
            <Shipping>
              <CurrencyCode>USD</CurrencyCode>
              <Amount>0.00</Amount>
            </Shipping>
          </BuyingPrice>
          <RegularPrice>
            <CurrencyCode>USD</CurrencyCode>
            <Amount>15.99</Amount>
          </RegularPrice>
          <FulfillmentChannel>AMAZON</FulfillmentChannel>
          <ItemCondition>New</ItemCondition>
          <ItemSubCondition>New</ItemSubCondition>
          <SellerId>xxxxxxxxxx</SellerId>
          <SellerSKU>Dazzle Tattoos</SellerSKU>
        </Offer>
      </Offers>
    </Product>
  </GetMyPriceForASINResult>
  <ResponseMetadata>
    <RequestId>xxxxxxxxxxxxxxxxxxxxx</RequestId>
  </ResponseMetadata>
</GetMyPriceForASINResponse>

我使用的PHP代码如下。我在这里使用了 SimpleXML,因为我很熟悉它,但我希望也会有一个 DOMDocument 解决方案。

<?php

$file = 'prices.xml';
$doc = simplexml_load_file($file);

// Examine the namespaces
$namespaces = $doc->getNamespaces(true);    
print_r($namespaces);

$nsDoc = $doc->children($namespaces['']);
$nsDoc->registerXPathNamespace('p', 'http://mws.amazonservices.com/schema/Products/2011-10-01');

$nodes = $nsDoc->xpath('//p:GetMyPriceForASINResult/p:Product/p:Offers/p:Offer');
foreach ($nodes as $node)
{
    print_r($node);
}

我的第一个 print_r 将向您展示文档中的命名空间,而您唯一拥有的是 null 命名空间。由于这是空的,您的标签没有前缀字符串(例如 Amazon:Product),但命名空间仍然存在。看起来像这样:

Array
(
    [] => http://mws.amazonservices.com/schema/Products/2011-10-01
)

然后我得到文档的命名空间版本 ($doc->children($namespaces[''])) 来使用。我还将命名空间的名称声明为 p(使用 registerXPathNamespace),这是一个任意名称 - 您可以在此处使用任何对您有意义的名称。 (我确实尝试注册一个空名称 (''),但这没有用)。

最后,我按照评论中的建议使用了 XPath,但由于命名空间适用于父项及其所有子项,因此我在每个标记前添加了我的命名空间别名。 (XPath 基本上是 XML 的一种查询语言,对它的解释需要一本书或一本手册,所以我不会在这里深入挖掘。如果你打算做的不仅仅是粗略的XML,我建议在网络上找到一个 XML 测试应用程序并尝试一些查询。

输出产生两个(相同的)<Offer> 节点,因此:

SimpleXMLElement Object
(
    [BuyingPrice] => SimpleXMLElement Object
        (
            [LandedPrice] => SimpleXMLElement Object
                (
                    [CurrencyCode] => USD
                    [Amount] => 9.97
                )

            [ListingPrice] => SimpleXMLElement Object
                (
                    [CurrencyCode] => USD
                    [Amount] => 9.97
                )

            [Shipping] => SimpleXMLElement Object
                (
                    [CurrencyCode] => USD
                    [Amount] => 0.00
                )

        )

    [RegularPrice] => SimpleXMLElement Object
        (
            [CurrencyCode] => USD
            [Amount] => 15.99
        )

    [FulfillmentChannel] => AMAZON
    [ItemCondition] => New
    [ItemSubCondition] => New
    [SellerId] => xxxxxxxxxx
    [SellerSKU] => Dazzle Tattoos
)
SimpleXMLElement Object
(
    [BuyingPrice] => SimpleXMLElement Object
        (
            [LandedPrice] => SimpleXMLElement Object
                (
                    [CurrencyCode] => USD
                    [Amount] => 9.97
                )

            [ListingPrice] => SimpleXMLElement Object
                (
                    [CurrencyCode] => USD
                    [Amount] => 9.97
                )

            [Shipping] => SimpleXMLElement Object
                (
                    [CurrencyCode] => USD
                    [Amount] => 0.00
                )

        )

    [RegularPrice] => SimpleXMLElement Object
        (
            [CurrencyCode] => USD
            [Amount] => 15.99
        )

    [FulfillmentChannel] => AMAZON
    [ItemCondition] => New
    [ItemSubCondition] => New
    [SellerId] => xxxxxxxxxx
    [SellerSKU] => Dazzle Tattoos
)

您也需要取消引用每个节点中的项目。为此,您可以使用对象引用,然后转换为您想要的类型。例如:

$fulfillment = (string) $node->FulfillmentChannel;
echo "$fulfillment\n";

在循环中,这将产生我们期望的值:

AMAZON
AMAZON