【问题标题】:find and replace keywords by hyperlinks in an html fragment, via php dom通过 php dom 在 html 片段中通过超链接查找和替换关键字
【发布时间】:2011-03-10 05:27:14
【问题描述】:

我正在尝试使用simple_html_dom php 类创建一个查找和替换函数,该函数查找关键字并将它们替换为关键字定义的链接,关键字作为链接文本。

如何使用此类在<div><p>The CEO of the Dexia bank has just decided to retire.</p></div> 等字符串中查找并替换“Dexia”为<a href="info.php?tag=dexia">Dexia</a>

【问题讨论】:

  • 一定要使用simple_html_dom吗?这似乎可以通过使用 preg_replace 的正则表达式来完成。
  • @threendib HTML 不规则。

标签: php html replace


【解决方案1】:

这有点棘手,但你可以这样做:

$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。然后您必须在DOMTextnodeValue 中找到“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>

【讨论】:

  • @gordon:这很有趣。我简化了我的问题,因为我期望更简单的东西;实际上,我有大约 500 个关键字。这种方法是否正确扩展?我猜我必须有一个双 foreach 循环。
  • @pixeline 好吧,一开始很棘手,但这只是因为 DOM 非常冗长,您必须考虑节点而不是文本。我理解人们为什么想用 Regex 来做这件事,但是一旦你开始使用它,它就真的没那么难了。我的意思是,它只有 15 行代码。把它放到一个适当的服务类中,你就得到了一个很酷的可重用工具。不过我不知道它的性能如何,因此您必须自己对其进行基准测试,看看它是否适合您。
  • 它工作得很好(我必须更改为 loadHTML,因为我传递的 html 来自 CMS,可能格式不正确。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-25
  • 2013-08-04
  • 1970-01-01
  • 2012-01-30
  • 1970-01-01
  • 2013-05-19
  • 1970-01-01
相关资源
最近更新 更多