You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP DOMDocument解析HTML时ul被移出pre元素的原因及解决方法

问题原因

  1. 该现象是HTML解析器的标准纠错行为,完全符合HTML规范要求:<pre>标签的内容模型仅允许包含短语内容(行内级内容,例如文本、<span>、<code>等),禁止嵌套块级元素(例如<ul>、<div>、<p>等)。
  2. 你提供的原始HTML直接将<ul>作为<pre>的子元素,属于非法嵌套结构。PHP的DOMDocument底层依赖libxml的HTML解析器,解析过程中会自动修正不符合规范的结构:遇到<pre>内部出现非法块级元素时,会提前闭合<pre>标签,将非法块级元素移到<pre>标签外部,最终得到你看到的输出结果。

解决方法

根据你的使用场景,可以选择以下两种方案保留原始结构:

方案1:HTML标签严格闭合时使用

直接用loadXML方法替代loadHTML解析内容,XML解析器不会执行HTML规范特有的结构纠错逻辑,会严格按照输入的标签嵌套关系构建DOM树,输出即可保留原始结构:

$doc = new DOMDocument();
// 用XML模式解析,不执行HTML结构纠错
$doc->loadXML($html);
echo $doc->saveHTML();

方案2:兼容标签不严格闭合的HTML场景

可以先对HTML做预处理,把所有<pre>标签的内部内容转义为HTML实体,解析完成后再还原即可:

// 预处理:转义所有pre标签内的内容,避免被解析器修改
$html = preg_replace_callback('#(<pre[^>]*>)(.*?)(</pre>)#is', function($matches) {
    return $matches[1] . htmlspecialchars($matches[2]) . $matches[3];
}, $html);

$doc = new DOMDocument();
// 关闭自动添加html/body/doctype的逻辑
$doc->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

// 后处理:还原pre标签内的原始内容
foreach($doc->getElementsByTagName('pre') as $pre) {
    $pre->nodeValue = htmlspecialchars_decode($pre->nodeValue);
}

echo $doc->saveHTML();

注:从规范层面出发,更建议你调整HTML结构,不要把块级元素嵌套在<pre>标签内,从根源上避免该问题。

内容的提问来源于stack exchange,提问作者Chuoke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 20:24:03