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

可紊 提交于 2019-11-28 12:48:41

问题


How can I extract the values from the Amazon MWS XML file shown below?

Sadly I'm not very good with PHP (or XML). I have been reading/trying everything I can find on all sites I can find but I think I'm just not up to the job.

I've tried DOM, simpleXML, namespaces etc etc but must have simply got it all wrong.

I've tried this snippet of code:

    $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>";
    }

However it only returns this data from the outermost nodes, shown here:

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

What I'm simply trying to get are the currency and prices that are the children under the [Offers] node.

<?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>

Update

The link provided by Nigel doesn't help - it is basically a compendium of information.


回答1:


XML in general is fairly easy to work with, but you've stumbled over one of the things that makes it much tricker: XML namespaces. This is given away by the presence of the xmlns attribute in the outer element.

My first thought upon looking at your document was, and since I am not familiar with this API, "offers" sounds like it could be plural. I therefore modified the test document to allow for that, since <Offers> is probably designed to contain zero, one, or more than one <Offer>.

So, for testing purposes, that would look like this (I've just duplicated the single <Offer> for convenience):

<?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>

The PHP code I used is as follows. I've used SimpleXML here, as I am familiar with it, but I expect there would be a DOMDocument solution as well.

<?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);
}

My first print_r will show you the namespaces you have in your document, and the only one you have is the null namespace. Since this is empty, your tags are not prefixed with a string (e.g. Amazon:Product) but the namespace nevertheless still exists. That looks like this:

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

I then get a namespaced version of the document ($doc->children($namespaces[''])) to work with. I have also declared the name of the namespace to be p (using registerXPathNamespace) which is an arbitrary name - you can use anything here that makes sense to you. (I did try registering a null name ('') but this did not work).

Finally, I use XPath as suggested in the comments, but since the namespace applies to the parent and all its children, I have added my namespace alias in front of every tag. (XPath is basically a query language for XML, and an explanation of it requires a book or a manual, so I will refrain from digging in too deeply here. If you are going to be doing more than a cursory bit of XML, I recommend finding an XML test application on the web and trying out some queries).

The output produces the two (identical) <Offer> nodes, which are thus:

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
)

You will want to dereference items within each node too. To do that, you can use object references and then casting to the type you want. For example:

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

In the loop, this will produce the values we expect:

AMAZON
AMAZON


来源:https://stackoverflow.com/questions/51989129/how-can-i-get-data-from-this-amazon-xml-response-file-using-php

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!