我不确定这是否是预期的行为,或者我做错了什么:
<?php
$xml = '<?xml version="1.0"?>
<foobar>
<foo>
<nested>
<img src="example1.png"/>
</nested>
</foo>
<foo>
<nested>
<img src="example2.png"/>
</nested>
</foo>
</foobar>';
$dom = new DOMDocument();
$dom->loadXML($xml);
$node = $dom->getElementsByTagName('foo')[0];
$simplexml = simplexml_import_dom($node);
echo $simplexml->asXML() . "\n";
echo " === With // ====\n";
var_dump($simplexml->xpath('//img'));
echo " === With .// ====\n";
var_dump($simplexml->xpath('.//img'));
即使我仅导入了特定的DomNode,并且asXml()仅返回该部分,但xpath()似乎仍然可以在整个文档上运行。
我可以通过使用.//img来防止这种情况,但这对我来说似乎很奇怪。
结果:
<foo>
<nested>
<img src="example1.png"/>
</nested>
</foo>
=== With // ====
array(2) {
[0] =>
class SimpleXMLElement#4 (1) {
public $@attributes =>
array(1) {
'src' =>
string(12) "example1.png"
}
}
[1] =>
class SimpleXMLElement#5 (1) {
public $@attributes =>
array(1) {
'src' =>
string(12) "example2.png"
}
}
}
=== With .// ====
array(1) {
[0] =>
class SimpleXMLElement#5 (1) {
public $@attributes =>
array(1) {
'src' =>
string(12) "example1.png"
}
}
}
答案 0 :(得分:2)
这是预期的行为。您正在将DOM元素节点导入到SimpleXMLElement中。这不会在后台修改XML文档-节点保留其上下文。
这里是Xpath表达式,它们向上(parent::
,ancestor::
)或兄弟姐妹(preceding-sibling::
,following-sibling::
)上升。
以/
开头的位置路径始终相对于文档,而不是上下文节点。使用.
显式引用当前节点可避免该触发。 .//img
是current()/descendant-or-self::img
的缩写-另一个选择是descendant::img
。
但是,您不需要将DOM节点转换为SimpleXMLElement即可使用Xpath。
$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMXpath($document);
foreach ($xpath->evaluate('//foo[1]') as $foo) {
var_dump(
$xpath->evaluate('string(.//img/@src)', $foo)
);
}
输出:
string(12) "example1.png"
//foo[1]
获取文档中的第一个foo
元素节点。如果文档中没有匹配的元素,它将返回一个空列表。使用foreach
可以避免这种情况下的错误。它将重复一次或永不重复。
string(.//img/@src)
获取后代src
元素的img
属性,并将第一个元素转换为字符串。如果此处没有匹配的节点,则返回值将为并且为空字符串。 DOMXpath::evaluate()
的第二个参数是上下文节点。