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 表达式。

/ 开头的位置路径始终相对于文档,而不是上下文节点。使用 . 对当前节点的显式引用可避免该触发器。 .//imgcurrent()/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() 的第二个参数是上下文节点。