2

I'm expecting an array of Amount, but for some reason it refused to be found. I tried many combinations of setting the name space, but it gives the error SimpleXMLElement::xpath(): Undefined namespace prefix.

Code
      // $xml->registerXPathNamespace("amazon", "http://webservices.amazon.com/AWSECommerceService/2011-08-01");
      // $item->registerXPathNamespace("amazon", "http://webservices.amazon.com/AWSECommerceService/2011-08-01");
      // $possiblePrices = $item->OfferSummary->xpath('//amazon:Amount');
      $possiblePrices = $item->OfferSummary->xpath('//Amount');
      Yii::error(print_r($item->OfferSummary->asXML(), true));
      Yii::error(print_r($possiblePrices, true));
Log
2015-04-15 21:46:06 [::1][-][-][error][application] <OfferSummary><LowestNewPrice><Amount>1</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$0.01</FormattedPrice></LowestNewPrice><TotalNew>15</TotalNew><TotalUsed>0</TotalUsed><TotalCollectible>0</TotalCollectible><TotalRefurbished>0</TotalRefurbished></OfferSummary>
    in /cygdrive/c/Users/Chloe/workspace/xxx/controllers/ShoppingController.php:208
    in /cygdrive/c/Users/Chloe/workspace/xxx/controllers/ShoppingController.php:106
2015-04-15 21:46:06 [::1][-][-][error][application] Array
(
)
Top of XML
<?xml version="1.0" ?>
<ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2011-08-01">
8
  • Can you post a more complete sample of the original XML, prior to calling asXML() Commented Apr 16, 2015 at 2:01
  • Here is the complete XML pastebin.com/U5ar3UQh Commented Apr 16, 2015 at 2:05
  • This seems to address the default namespace (without element prefixes) issue you're dealing with: stackoverflow.com/questions/21143846/… Commented Apr 16, 2015 at 2:14
  • @MichaelBerkowski Well I did try to use namespaces. See line 1,2,3 of the code. However they give an error. Commented Apr 16, 2015 at 2:19
  • 2
    Not familiar with PHP, but since you registered the namespace to $item, maybe this way will do : $item->xpath('//amazon:OfferSummary//amazon:Amount'); ? Commented Apr 16, 2015 at 2:23

1 Answer 1

3

The Amount element is in the namespace <http://webservices.amazon.com/AWSECommerceService/2011-08-01>. But in your xpath query you put it in no namespace at all. So the example will return 0 elements:

$xml = simplexml_load_string($buffer);

$result = $xml->xpath('//Amount');
printf("Result (%d):\n", count($result));
foreach ($result as $node) {
    echo $node->asXML(), "\n";
}

The output is rather short:

Result (0):

Instead you need to tell that you want the Amount element in that specific namespace. You do that by registering a namespace-prefix and use it in your xpath query:

$xml->registerXPathNamespace("amazon", "http://webservices.amazon.com/AWSECommerceService/2011-08-01");
$result = $xml->xpath('//amazon:Amount');
printf("Result (%d):\n", count($result));
foreach ($result as $node) {
    echo $node->asXML(), "\n";
}

Now the output is with all those elements:

Result (24):
<Amount>217</Amount>
<Amount>1</Amount>
<Amount>800</Amount>
<Amount>1</Amount>
<Amount>498</Amount>
...

Take care that if you've got more than one element-name to check for in your xpath query, that you need to tell the correct namespace for each of them. Example:

$result = $xml->xpath('/*/amazon:Items/amazon:Item//amazon:Amount');

You can find the example code also online here: https://eval.in/314347 (backup)- otherwise the examples from my answer minus the XML at a glance:

$xml = simplexml_load_string($buffer);

$result = $xml->xpath('//Amount');
printf("Result (%d):\n", count($result));
foreach ($result as $node) {
    echo $node->asXML(), "\n";
}

$xml->registerXPathNamespace("amazon", "http://webservices.amazon.com/AWSECommerceService/2011-08-01");
$result = $xml->xpath('//amazon:Amount');
printf("Result (%d):\n", count($result));
foreach ($result as $node) {
    echo $node->asXML(), "\n";
}

$result = $xml->xpath('/*/amazon:Items/amazon:Item//amazon:Amount');
printf("Result (%d):\n", count($result));
foreach ($result as $node) {
    echo $node->asXML(), "\n";
}

Further Readings


If you don't want to register the namespace prefixes over and over again, you can extend from SimpleXMLElement and manage that registration list your own:

/**
 * Class MyXml
 *
 * Example on how to register xpath namespace prefixes within the document
 */
class MyXml extends SimpleXMLElement
{
    public function registerXPathNamespace($prefix, $ns)
    {
        $doc        = dom_import_simplexml($this)->ownerDocument;
        $doc->__sr  = $doc;
        $doc->__d[] = [$prefix, $ns];
    }

    public function xpath($path)
    {
        $doc = dom_import_simplexml($this)->ownerDocument;
        if (isset($doc->__d)) {
            foreach ($doc->__d as $v) {
                parent::registerXPathNamespace($v[0], $v[1]);
            }
        }

        return parent::xpath($path);
    }
}

With this MyXml class you can load the document and then you would only need to register the namespace once:

$namespace = "http://webservices.amazon.com/AWSECommerceService/2011-08-01";

$xml = simplexml_load_file('so-29664051.xml', 'MyXMl');
$xml->registerXPathNamespace("amazon", $namespace);

$item = $xml->Items->Item[0];

$result = $item->xpath('.//amazon:Amount');
printf("Result (%d):\n", count($result));
foreach ($result as $node) {
    echo $node->asXML(), "\n";
}
Sign up to request clarification or add additional context in comments.

2 Comments

That wasn't really the problem. I tried using namespaces. See line 1,2,3 of the code. The problem was pointed out by @har07. I thought setting the namespace on an element would propagate/inherit to the children, but it doesn't, so I have to set the namespace on the exact child object that I use xpath() with.
Ah! Yes you have to or you let SimpleXML do that for you by extending from it. I'll add an example on how you can to that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.