奇怪的SimpleXML问题 - 无法按名称引用节点?

时间:2015-09-28 15:31:31

标签: php xml simplexml

我试图解析一个有效的远程XML文件:

$xml = simplexml_load_file('http://feeds.feedburner.com/HammersInTheHeart?format=xml');

根元素为feed,我试图通过以下方式获取它:

$nodes = $xml->xpath('/feed'); //also tried 'feed', without slash

除非它找不到任何节点。

print_r($nodes); //empty array

或任何类型的任何节点,只要我按标签名称搜索它们,实际上是:

$nodes = $xml->xpath('//entry');
print_r($nodes); //empty array

但是,如果我使用通配符,它​​会找到节点,例如

$nodes = $xml->xpath('/*/*[4]');
print_r($nodes); //node found

发生了什么?

1 个答案:

答案 0 :(得分:3)

与DOM不同,SimpleXML没有文档对象的概念,只有元素。因此,如果您加载XML,则始终会获得文档元素。

$feed = simplexml_load_file($xmlFile);
var_dump($feed->getName());

输出:

string(4) "feed"

这意味着所有Xpath表达式必须相对于此元素或绝对值。简单feed将无效,因为上下文已经是feed元素。

但这是另一个原因。该URL是Atom订阅源。所以命名空间http://www.w3.org/2005/Atom中的XML元素。 SimpleXMLs魔术语法识别某些调用的默认命名空间 - 但Xpath不能。这里不是Xpath中的默认命名空间。您必须使用前缀注册它们并在Xpath表达式中使用该前缀。

$feed = simplexml_load_file($xmlFile);
$feed->registerXpathNamespace('a', 'http://www.w3.org/2005/Atom');
foreach ($feed->xpath('/a:feed/a:entry[position() < 3]') as $entry) {
  var_dump((string)$entry->title);
}

输出:

string(24) "Sharing the goals around"
string(34) "Kouyate inspires Hammers' comeback"

但是在SimpleXML中,必须为您调用xpath()方法的每个对象进行注册。

在DOM中使用Xpath略有不同,但功能更强大。

$document = new DOMDocument();
$document->load($xmlFile);
$xpath = new DOMXpath($document);
$xpath->registerNamespace('a', 'http://www.w3.org/2005/Atom');

foreach ($xpath->evaluate('/a:feed/a:entry[position() < 3]') as $entry) {
  var_dump($xpath->evaluate('string(a:title)', $entry));
}

输出:

string(24) "Sharing the goals around"
string(34) "Kouyate inspires Hammers' comeback"

使用with DOMXpath::evaluate()的Xpath表达式可以返回标量值。