将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)。任何建议表示赞赏。
答案 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
的参考问题