为什么';这个PHP SimpleXML XPath不能找到值吗?

为什么';这个PHP SimpleXML XPath不能找到值吗?,php,xml,xpath,simplexml,Php,Xml,Xpath,Simplexml,我期待着一个Amount数组,但由于某种原因,它拒绝被找到。我尝试了许多设置名称空间的组合,但它给出了错误simplexmlement::xpath():未定义的名称空间前缀 code // $xml->registerXPathNamespace("amazon", "http://webservices.amazon.com/AWSECommerceService/2011-08-01"); // $item->re

我期待着一个
Amount
数组,但由于某种原因,它拒绝被找到。我尝试了许多设置名称空间的组合,但它给出了错误
simplexmlement::xpath():未定义的名称空间前缀

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
(
)
Amount
元素位于命名空间
中。但在xpath查询中,您根本没有将其放在名称空间中。因此,该示例将返回0个元素:

$xml = simplexml_load_string($buffer);

$result = $xml->xpath('//Amount');
printf("Result (%d):\n", count($result));
foreach ($result as $node) {
    echo $node->asXML(), "\n";
}
Result (24):
<Amount>217</Amount>
<Amount>1</Amount>
<Amount>800</Amount>
<Amount>1</Amount>
<Amount>498</Amount>
...
输出相当短:

Result (0):
相反,您需要告知您希望在该特定名称空间中使用
Amount
元素。您可以通过注册名称空间前缀并在xpath查询中使用它来实现这一点:

$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";
}
现在,输出包含所有这些元素:

$xml = simplexml_load_string($buffer);

$result = $xml->xpath('//Amount');
printf("Result (%d):\n", count($result));
foreach ($result as $node) {
    echo $node->asXML(), "\n";
}
Result (24):
<Amount>217</Amount>
<Amount>1</Amount>
<Amount>800</Amount>
<Amount>1</Amount>
<Amount>498</Amount>
...
您也可以在这里在线找到示例代码:()-否则,我的答案中的示例会减去XML:

$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";
}
进一步阅读

如果不想反复注册名称空间前缀,可以从SimpleXMLElement扩展并管理自己的注册列表:

/**
 * 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);
    }
}
使用这个MyXml类,您可以加载文档,然后只需要注册一次名称空间:

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

在调用
asXML()
之前,您能发布一个更完整的原始XML示例吗?这是一个完整的XML,它似乎解决了您正在处理的默认名称空间(没有元素前缀)问题:@MichaelBerkowski我确实尝试过使用名称空间。见本规范第1、2、3行。但是他们给出了一个错误。不熟悉PHP,但是由于您将名称空间注册到了
$item
,可能这样做:
$item->xpath('//amazon:OfferSummary//amazon:Amount')?这不是真正的问题。我尝试使用名称空间。见本规范第1、2、3行。@har07指出了这个问题。我原以为在元素上设置名称空间会传播/继承到子对象,但事实并非如此,因此我必须在我与.Ah一起使用的
xpath()
子对象上设置名称空间!是的,您必须这样做,或者通过扩展SimpleXML让SimpleXML为您这样做。我将添加一个示例,说明如何实现这一点。