PHP DOMNode保留InnerHTML格式:提取BODY内容格式异常求助
解决DOMDocument提取BODY内容时的格式问题
我明白你遇到的困扰:提取HEAD属性一切正常,但处理BODY里的列表内容时,C14N()和saveXML()会改变原始的空格格式,saveHTML()的输出也和预期有差异。这本质上是DOMDocument对HTML和XML的空白处理规则不同导致的,给你几个实用的解决方案:
1. 调整DOMDocument核心参数,保留原始空白
DOMDocument默认会忽略节点间的空白文本节点,这就是你看到<ul>后面空格消失的原因。我们可以通过设置参数改变这个行为:
$originalHtml = '<ul> <li>test1</li> <li>test2</li> </ul>'; $dom = new DOMDocument(); // 关键:开启空白保留,避免DOM自动压缩空格 $dom->preserveWhiteSpace = true; // 加载HTML时,禁止自动添加默认的DOCTYPE、html/body标签(只保留你需要的内容) $dom->loadHTML($originalHtml, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); // 提取BODY内的内容 $bodyContent = $dom->getElementsByTagName('body')->item(0); // 使用saveHTML()输出,贴近原始HTML格式 echo $dom->saveHTML($bodyContent);
这段代码会输出和你原始HTML几乎一致的格式:<ul> <li>test1</li> <li>test2</li> </ul>
2. 理解三种序列化方法的差异
saveXML()和C14N()遵循XML规范,会严格处理空白字符、自动压缩冗余空格,更适合XML文档,而非HTML内容提取。saveHTML()是专门为HTML设计的序列化方法,贴近浏览器对HTML的解析逻辑,能保留更多原始格式,是提取HTML内容的优先选择。
3. 极端场景:手动保留空白节点
如果对格式要求极高,上面的方法还不够,可以手动遍历DOM节点,强制保留所有空白文本节点:
function preserveWhitespaceNodes(DOMNode $node) { foreach ($node->childNodes as $child) { if ($child instanceof DOMText && trim($child->nodeValue) === '') { // 保留空白文本节点,不被DOM自动忽略 $child->nodeValue = $child->nodeValue; } if ($child->hasChildNodes()) { preserveWhitespaceNodes($child); } } } // 加载HTML后调用函数处理节点 preserveWhitespaceNodes($dom);
内容的提问来源于stack exchange,提问作者Charly
相关产品推荐
相关产品推荐

