对html片段的loadHTML LIBXML_HTML_NOIMPLIED会生成错误的标记

时间:2015-04-07 14:11:20

标签: php html domdocument

将LIBXML_HTML_NOIMPLIED标志与html片段一起使用会生成错误的标记:

$str = '<p>Lorem ipsum dolor sit amet.</p><p>Nunc vel vehicula ante.</p>';
$doc = new DOMDocument();
$doc->loadHTML($str, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
echo $doc->saveHTML();

输出:

<p>Lorem ipsum dolor sit amet.<p>Nunc vel vehicula ante.</p></p>

我发现黑客可以使用正则表达式来解决这个问题,但这会破坏使用DOM的目的。我用几个版本的libxml和php测试了这个,最新的libxml 2.9.2,php 5.6.7(Debian Jessy)。任何建议表示赞赏。

1 个答案:

答案 0 :(得分:21)

重新安排是由您正在使用的LIBXML_HTML_NOIMPLIED选项完成的。看起来它对你的情况不够稳定。

另外,您可能不希望因为可移植性原因而使用它,例如我手头有一个带有Libxml 2.7.8的PHP 5.4.36,支持LIBXML_HTML_NOIMPLIED( Libxml&gt; = 2.7.7)但以后 LIBXML_HTML_NODEFDTD(Libxml&gt; = 2.7.8)选项。

我知道这种处理方式。加载片段时,将其包装到<div>元素中:

$doc->loadHTML("<div>$str</div>");

这有助于在您想要的结构上指导 DOMDocument

然后,您可以从文档中提取此容器:

$container = $doc->getElementsByTagName('div')->item(0);
$container = $container->parentNode->removeChild($container);

然后从文档中删除所有孩子:

while ($doc->firstChild) {
    $doc->removeChild($doc->firstChild);
}

现在文档已经完全空了,您现在可以再次附加孩子了。幸运的是我们之前删除了<div>容器元素,因此我们可以从中添加:

while ($container->firstChild ) {
    $doc->appendChild($container->firstChild);
}

然后可以使用已知的 saveHTML 方法检索片段:

echo $doc->saveHTML();

在您的方案中给出了:

<p>Lorem ipsum dolor sit amet.</p><p>Nunc vel vehicula ante.</p>

这种方法与现场的现有材料略有不同(参见下面的参考资料),所以这个例子一下子:

$str = '<p>Lorem ipsum dolor sit amet.</p><p>Nunc vel vehicula ante.</p>';

$doc = new DOMDocument();
$doc->loadHTML("<div>$str</div>");

$container = $doc->getElementsByTagName('div')->item(0);
$container = $container->parentNode->removeChild($container);
while ($doc->firstChild) {
    $doc->removeChild($doc->firstChild);
}

while ($container->firstChild ) {
    $doc->appendChild($container->firstChild);
}

echo $doc->saveHTML();

我还真的推荐如何在不使用HTML包装器的情况下保存DOMDocument的HTML?以进一步阅读以及关于inner-html

的参考问题

参考