我的 DOMDocument 中有鬼?

ghosts in my DOMDocument?

尝试使用以前 运行 的简单 xpath,现在只显示空节点。

来源:任何 XML 文件。假设

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" lang="pt-br" xml:lang="pt-br">
  <head> <meta charset="utf-8"/><title>test</title> </head>
  <body>
    <article id="etc"><p>Hello</p><p>Bye</p></article>
  </body>
</html>

全部重做,这里附上完整的测试:

$dom2 = new DOMDocument;
$dom2->Load($pathFile);
$xpath2 = new DOMXPath($dom2);
$entries = $xpath->query('//p');
// nothing here, all empty:
var_dump($entries);  // zero!
foreach ($entries as $entry) {
    echo "Found {$entry->nodeValue},";
}
// by all here!  
foreach($dom2->getElementsByTagName('*') as $e )
  print "\n name={$e->nodeName}";  // all tags!

有什么问题,为什么 xpath 不是 运行?

那是因为您的 xml 定义了默认命名空间:

xmlns="http://www.w3.org/1999/xhtml"

因此您需要注册一个命名空间,然后使用命名空间标签名称进行搜索:

$xpath->registerNamespace('x', 'http://www.w3.org/1999/xhtml');
$entries = $xpath->query('//x:p');

这是 W3C 的 DomDocument v1.0 标准的一个老问题。 an old site commented 关于 XPath 初学者的惊喜,

One of the commonly asked questions about (...) is:
"Why nothing matched for my XPath expression which seems right to me?"
Common cause of these problems is not properly defining a namespace for XPath.

但是初学者是对的,丑陋的行为 "default thing"...所以让我们保持初学者对什么是简单而好的直觉。

看到一个似乎不是您需要的 XPath 真是太可怕了(当它的标签没有前缀时 XML 看起来是什么)。标签是简单的标签,需要简单的 XPath。

可靠的解决方法

使用最佳解决方案修复丑陋的 XPath 查询行为。这不是微不足道的,因为 root 的 xmlns 属性 is read-only,所以我们需要通过新字符串 XML:

重新做 DOM 对象
$expTag = 'html';  // config expected tag-root
$expNs  = 'http://www.w3.org/1999/xhtml';  // config
// ...
$e = $dom->documentElement; // root node

// Validate input (as expecteds configs) and change tag root:
if ($e->nodeName==$expTag && $e->hasAttribute('xmlns') 
    && $e->getAttribute('xmlns')==$expNs) {
  // can't do $e->removeAttribute('xmlns') because is read-only!
  $xml = $dom->C14N(); // normalize quotes and remove repeateds
  $xml = preg_replace("#^<$expTag (.*?)xmlns=\"[^\"]+\"#", "<$expTag$1", $xml);
  $dom = DOMDocument::LoadXML($xml);
} else 
     die("\n ERROR: something not expected.\n");
//...
$xpath = new DOMXPath($dom);
$entries = $xpath->query('//p'); // perfect, now back simple to express XPath!

仅当您没有限制时才必须使用此解决方案,例如在 digital preservation 上下文中。

其他实际情况下的问题是 save/reload 完整 XML 作为字符串的高成本 (CPU),为了安全起见,成本更高 C14N 方法,为正则表达式准备安全 XML。

使用 C14N(对于 数字保存 上下文中的其他内容也有好处)对于确保正则表达式的正确行为是必要的——严格来说 getAttribute()方法可能会受到属性重复的影响,但是我们可以忽略这种"second order"影响,或者将检查转移到正则表达式。