【问题标题】:Replace Tag in HTML with DOMDocument用 DOMDocument 替换 HTML 中的标签
【发布时间】:2017-08-31 00:49:01
【问题描述】:

我正在尝试在 php 中使用 DOMDocument::loadHTML 编辑 html 标签。 html 数据是 html 的一部分,而不是整个页面。我按照此页面 (PHP - DOMDocument - need to change/replace an existing HTML tag w/ a new one) 的说明进行操作。

这应该将 pre 标记转换为 div 标记,但它会给出“致命错误:未捕获的异常 'DOMException' 和消息'未找到错误'。”

<?php
$contents = <<<STR
<pre>hi</pre>
<pre>hello</pre>
<pre>bye</pre>
STR;

$dom = new DOMDocument;
@$dom->loadHTML($contents);

foreach( $dom->getElementsByTagName("pre") as $nodePre ) {
    $nodeDiv = $dom->createElement("div", $nodePre->nodeValue);
    $dom->replaceChild($nodeDiv, $nodePre);
}

echo $dom->saveHTML();
?>

[编辑] 当我尝试向后迭代节点对象时,我收到此错误,“注意:尝试获取非对象的属性...”

<?php
$contents = <<<STR
<pre>hi</pre>
<pre>hello</pre>
<pre>bye</pre>
STR;

$dom = new DOMDocument;
@$dom->loadHTML($contents);
$domPre = $dom->getElementsByTagName('pre');
$length = $domPre->length;

    For ($i = $length; $i > -1 ; $i--) {
        $nodePre = $domPre->item($i);
        echo $nodePre->nodeValue . '<br />';
//      $nodeDiv = $dom->createElement("div", $nodePre->nodeValue);
//      $dom->replaceChild($nodeDiv, $nodePre);
    }

    // echo $dom->saveHTML();
?>

[编辑] 好的,解决了。由于回答的代码有一些错误,我在这里发布了解决方案。谢谢大家。

解决办法:

<?php
$contents = <<<STR
<pre>hi</pre>
<pre>hello</pre>
<pre>bye</pre>
STR;

$dom = new DOMDocument;
@$dom->loadHTML($contents);
$domPre = $dom->getElementsByTagName('pre');
$length = $domPre->length;

For ($i = $length - 1; $i > -1 ; $i--) {
    $nodePre = $domPre->item($i);
    $nodeDiv = $dom->createElement("div", $nodePre->nodeValue);
    $nodePre->parentNode->replaceChild($nodeDiv, $nodePre);
}

echo $dom->saveHTML();
?>

【问题讨论】:

  • 见this answer。
  • 我知道这是 PHP 的问题。关闭节点并编辑克隆的节点怎么样?与正则表达式解决方案相比,这慢吗?
  • 不是PHP的问题。如果您向后迭代 NodeList,您应该能够替换所有 pre 标记。如果这不起作用,将逻辑更改为效率较低的版本,替换第一个匹配,再次调用getElementsByTagName,替换第一个匹配...
  • 迭代 backwars 是个好主意。我试试看。
  • 我更新了最初的帖子。我在尝试执行您的建议时遇到了另一个错误。

标签: php dom


【解决方案1】:

问题在于对replaceChild() 的调用。而不是

$dom->replaceChild($nodeDiv, $nodePre);

使用

$nodePre->parentNode->replaceChild($nodeDiv, $nodePre);

更新

这是一个工作代码。替换多个节点似乎存在一些问题(更多信息:http://php.net/manual/en/domnode.replacechild.php),因此您必须使用回归循环来替换元素。

$contents = <<<STR
<pre>hi</pre>
<pre>hello</pre>
<pre>bye</pre>
STR;

$dom = new DOMDocument;
@$dom->loadHTML($contents);

$elements = $dom->getElementsByTagName("pre");
for ($i = $elements->length - 1; $i >= 0; $i --) {
    $nodePre = $elements->item($i);
    $nodeDiv = $dom->createElement("div", $nodePre->nodeValue);
    $nodePre->parentNode->replaceChild($nodeDiv, $nodePre);
}

【讨论】:

  • &lt;html&gt;&lt;body&gt;&lt;div&gt;hi&lt;/div&gt; &lt;pre&gt;hello&lt;/pre&gt; &lt;div&gt;bye&lt;/div&gt;&lt;/body&gt;&lt;/html&gt; 这是我通过尝试你的建议得到的。第二个标签仍然存在。
  • @Teno 这个问题似乎是由于尝试替换多个节点而引起的。 PHP手册中有一个关于如何解决这个问题的好建议。检查我上面的更新答案。
  • $nodePre = $elements-&gt;item($i); 行导致错误“注意:未定义变量:i”。尽管通过定义 $i 修复了简单的错误,但它开始说“注意:尝试获取非对象的属性。”
  • @Teno 请再次检查。这应该是一个for循环。一个善意的编辑改变了它,但没有彻底做到。
【解决方案2】:

paquettg/php-html-parser 的另一种方式(没有找到更改名称的方法,所以不得不使用 hack 重新绑定$this):

use PHPHtmlParser\Dom;
use PHPHtmlParser\Dom\HtmlNode;

$dom = new Dom;
$dom->load($text);
/** @var HtmlNode[] $tags */
foreach($dom->find('pre') as $tag) {
    $changeTag = function() {
        $this->name = 'div';
    };
    $changeTag->call($tag->tag);
};
echo (string)$dom;

【讨论】:

  • 你拯救了我的一天!谢谢
猜你喜欢
  • 2011-06-17
  • 2013-04-24
  • 1970-01-01
  • 1970-01-01
  • 2023-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多