使用XPath选择/过滤XML元素

问题描述:

here is my amazon mws api responce

<?xml version="1.0"?>
<GetMyPriceForSKUResponse xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01">
<GetMyPriceForSKUResult SellerSKU="ds-tru-6sss" 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>Assssssss</MarketplaceId>
        <ASIN>sss</ASIN>
      </MarketplaceASIN>
      <SKUIdentifier>
        <MarketplaceId>Afasrfd</MarketplaceId>
        <SellerId>ssssss</SellerId>
        <SellerSKU>dssss</SellerSKU>
      </SKUIdentifier>
    </Identifiers>
    <Offers>
      <Offer>
        <BuyingPrice>
          <LandedPrice>
            <CurrencyCode>USD</CurrencyCode>
            <Amount>12.49</Amount>
          </LandedPrice>
          <ListingPrice>
            <CurrencyCode>USD</CurrencyCode>
            <Amount>12.49</Amount>
          </ListingPrice>
          <Shipping>
            <CurrencyCode>USD</CurrencyCode>
            <Amount>0.00</Amount>
          </Shipping>
        </BuyingPrice>
        <RegularPrice>
          <CurrencyCode>USD</CurrencyCode>
          <Amount>12.49</Amount>
        </RegularPrice>
        <FulfillmentChannel>MERCHANT</FulfillmentChannel>
        <ItemCondition>New</ItemCondition>
        <ItemSubCondition>New</ItemSubCondition>
        <SellerId>Aadada</SellerId>
        <SellerSKU>ssss</SellerSKU>
      </Offer>
      <Offer>
        <BuyingPrice>
          <LandedPrice>
            <CurrencyCode>USD</CurrencyCode>
            <Amount>1000.00</Amount>
          </LandedPrice>
          <ListingPrice>
            <CurrencyCode>USD</CurrencyCode>
            <Amount>1000.00</Amount>
          </ListingPrice>
          <Shipping>
            <CurrencyCode>USD</CurrencyCode>
            <Amount>0.00</Amount>
          </Shipping>
        </BuyingPrice>
        <RegularPrice>
          <CurrencyCode>USD</CurrencyCode>
          <Amount>1000.00</Amount>
        </RegularPrice>
        <FulfillmentChannel>MERCHANT</FulfillmentChannel>
        <ItemCondition>New</ItemCondition>
        <ItemSubCondition>New</ItemSubCondition>
        <SellerId>ssss</SellerId>
        <SellerSKU>sss</SellerSKU>
      </Offer>
    </Offers>
  </Product>
</GetMyPriceForSKUResult>
<ResponseMetadata>
  <RequestId>e0ef1c2c-4f35-4316-8629-faadadd</RequestId>
</ResponseMetadata>
</GetMyPriceForSKUResponse>

and to select amount (12.49) from

<ListingPrice>
    <CurrencyCode>USD</CurrencyCode>
    <Amount>12.49</Amount>
</ListingPrice>

I am trying ,

// from curl
$result = curl_exec ($ch);
$xmldoc = new DOMDocument();
$xmldoc->load($result);
$xpathvar = new Domxpath($xmldoc);

$queryResult = $xpathvar->query('/Amount');
foreach($queryResult as $result){
    echo $result;
}

I am expecting more then one value for this, but I am getting none at all.

Sorry, I am not good at XPath, can somebody guide me?

Currently I found errors in your code:


First: Use two // to select an element regardless of where it is located in the xml tree.

 $queryResult = $xpathvar->query('//Amount');

Second: thanks @Ranon. You'll take care of the documents xml namespace:

// Register Namespace mws
$xpathvar->registerNamespace("mws", 'http://mws.amazonservices.com/schema/Products/2011-10-01');

... and use it, means:

 $queryResult = $xpathvar->query('//mws:Amount');

Third: If you want to select the text node (between the <amount> nodes) you should use:

$queryResult = $xpathvar->query('//mws:Amount/text()');

Otherwise you can select the parent element <Amount> (as you already doing) and retrieve the value with PHP. Then you have to change your code to:

$queryResult = $xpathvar->query('//mws:Amount');
foreach($queryResult as $result){
   echo $result->nodeValue; // echo the node value, not the node 'itself'
}

Fourth: Also note another error in your code. When you create a DOMDocument from an xml string you'll have to use:

$document->loadXML($result);

Fifth: You told that you want to retrieve the <Amount> elements form inside <ListingPrice> elements. Note that there are also <Amount> elements inside <RegularPrice> elements. So it does matter where the <Amount> element is located in tree. Use the following query to obtain only listing price amounts:

$queryResult = $xpathvar->query('//mws:ListingPrice/mws:Amount');

The XPath expression is wrong. You need '//Amount' to select all the "Amount" elements

Amazon returns XML using a namespace which you have to declare and use.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// from curl
$result = curl_exec($ch);
$xmldoc = new DOMDocument();
$xmldoc->loadXML($result);
$xpathvar = new Domxpath($xmldoc);
// Register Namespace mws
$xpathvar->registerNamespace("mws", 'http://mws.amazonservices.com/schema/Products/2011-10-01');

// Query using namespace mws
$queryResult = $xpathvar->query('//mws:Amount');
foreach($queryResult as $result){
    echo $result->nodeValue;
}

I selected the namespace identifier mws arbitrarily from the subdomain, you can choose another if you want.

I corrected some other errors in the code found by @hek2mgl.