这有点棘手,但你可以这样做:
$html = <<< HTML
<div><p>The CEO of the Dexia bank <em>has</em> just decided to retire.</p></div>
HTML;
我添加了一个强调元素只是为了说明它也适用于内联元素。
设置
$dom = new DOMDocument;
$dom->formatOutput = TRUE;
$dom->loadXML($html);
$xpath = new DOMXPath($dom);
$nodes = $xpath->query('//text()[contains(., "Dexia")]');
上面有趣的当然是 XPath。它会在加载的 DOM 中查询所有包含针“Dexia”的DOMText 节点。结果是DOMNodeList(和往常一样)。
替换
foreach($nodes as $node) {
$link = '<a href="info.php?tag=dexia">Dexia</a>';
$replaced = str_replace('Dexia', $link, $node->wholeText);
$newNode = $dom->createDocumentFragment();
$newNode->appendXML($replaced);
$node->parentNode->replaceChild($newNode, $node);
}
echo $dom->saveXML($dom->documentElement);
找到的$node 将包含wholeText 的字符串Dexia 银行的CEO,尽管它位于P 元素内。这是因为$node 有一个兄弟DOMElement,重点放在bank 之后。我将链接创建为字符串而不是节点,并用它替换 wholeText 中所有出现的“Dexia”(无论单词边界如何 - 这对 Regex 来说都是一个很好的调用)。然后我从结果字符串创建一个DocumentFragment 并用它替换DOMText 节点。
W3C 与 PHP
使用DocumentFragement::applyXML() 是一种非标准方法,因为该方法不是 W3C DOM 规范的一部分。
如果您想使用标准 API 进行替换,您首先必须将 A 元素创建为新的 DOMElement。然后您必须在DOMText 的nodeValue 中找到“Dexia”的偏移量,并将DOMText 节点拆分为该位置的两个节点。从返回的兄弟中移除 Dexia 并在第二个之前插入链接元素。对兄弟节点重复此过程,直到在该节点中找不到更多的 Dexia 字符串。以下是发生一次 Dexia 的方法:
foreach($nodes as $node) {
$link = $dom->createElement('a', 'Dexia');
$link->setAttribute('href', 'info.php?tag=dexia');
$offset = strpos($node->nodeValue, 'Dexia');
$newNode = $node->splitText($offset);
$newNode->deleteData(0, strlen('Dexia'));
$node->parentNode->insertBefore($link, $newNode);
}
最后是输出
<div>
<p>The CEO of the <a href="info.php?tag=dexia">Dexia</a> bank <em>has</em> just decided to retire.</p>
</div>