SimpleXml::xpath() 在 simplexml_import_dom() 操作整个 DomDocument 而不仅仅是节点
SimpleXml::xpath() after simplexml_import_dom() operates on the whole DomDocument and not just the Node
我不确定这是预期的行为还是我做错了什么:
<?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() returns 只是那部分,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"
}
}
}
这是预期的行为。您正在将 DOM 元素节点导入到 SimpleXMLElement 中。这不会在后台修改 XML 文档 - 节点保留其上下文。
这里是向上 (parent::
、ancestor::
) 或兄弟 (preceding-sibling::
、following-sibling::
) 的 Xpath 表达式。
以 /
开头的位置路径始终相对于文档,而不是上下文节点。使用 .
对当前节点的显式引用可避免该触发器。 .//img
是 current()/descendant-or-self::img
的缩写 - 另一种选择是 descendant::img
。
然而,您无需将 DOM 节点转换为简单XML元素即可使用 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
元素节点。如果文档中没有匹配的元素,它将 return 一个空列表。使用 foreach
可以避免这种情况下的错误。它将被迭代一次或永远不会。
string(.//img/@src)
获取后代 img
元素的 src
属性并将第一个元素转换为字符串。如果此处没有匹配节点,则 return 值将为空字符串。 DOMXpath::evaluate()
的第二个参数是上下文节点。
我不确定这是预期的行为还是我做错了什么:
<?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() returns 只是那部分,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"
}
}
}
这是预期的行为。您正在将 DOM 元素节点导入到 SimpleXMLElement 中。这不会在后台修改 XML 文档 - 节点保留其上下文。
这里是向上 (parent::
、ancestor::
) 或兄弟 (preceding-sibling::
、following-sibling::
) 的 Xpath 表达式。
以 /
开头的位置路径始终相对于文档,而不是上下文节点。使用 .
对当前节点的显式引用可避免该触发器。 .//img
是 current()/descendant-or-self::img
的缩写 - 另一种选择是 descendant::img
。
然而,您无需将 DOM 节点转换为简单XML元素即可使用 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
元素节点。如果文档中没有匹配的元素,它将 return 一个空列表。使用 foreach
可以避免这种情况下的错误。它将被迭代一次或永远不会。
string(.//img/@src)
获取后代 img
元素的 src
属性并将第一个元素转换为字符串。如果此处没有匹配节点,则 return 值将为空字符串。 DOMXpath::evaluate()
的第二个参数是上下文节点。