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