PHP DOMDocument为何将HTML引号实体转换为实际引号?
DOMDocument保留原有实体与UTF-8字符的问题解析与解决
问题场景
给定如下HTML内容:
$html = '<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> </head> <body> <p>' " & < © 庭</p> </body> </html>';
使用DOMDocument加载并输出:
$dom = new DOMDocument(); $dom->loadHTML($html, LIBXML_NOERROR); echo $dom->saveHTML();
得到的输出与输入差异如下:
输入: ' " & < © 庭 输出: ' " & < © 庭
原因分析
- 实体转换逻辑:
- HTML规范中,文本内容里的单引号(
')和双引号(")不属于必须转义的特殊字符,因此DOMDocument会将'和"解析为实际字符,输出时不会自动转回实体。 &和<是HTML的核心特殊字符(用于标记实体和标签边界),必须转义:输入的&会被转成&,而<本身就是转义后的合法形式,因此输出时保留。
- HTML规范中,文本内容里的单引号(
- UTF-8编码识别问题:
- libxml(DOMDocument依赖的底层库)默认以
ISO-8859-1编码解析文档,即使HTML中包含<meta charset="utf-8">也无效——因为meta标签是在DOM结构构建完成后才被解析的,无法影响初始的编码识别逻辑,导致UTF-8字符(如©、庭)被转成十进制实体。
- libxml(DOMDocument依赖的底层库)默认以
解决方案
1. 修复UTF-8字符转义问题
通过mb_convert_encoding将HTML转换为HTML-ENTITIES编码后再加载,让libxml正确识别UTF-8字符:
$html = '<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> </head> <body> <p>' " & < © 庭</p> </body> </html>'; $dom = new DOMDocument(); // 转换编码并加载,确保libxml识别UTF-8 $dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'), LIBXML_NOERROR); echo $dom->saveHTML();
此时©和庭会以原UTF-8字符输出,不会被转成实体。
2. 强制保留'和"实体
由于DOMDocument不会自动保留文本中的引号实体,需要通过自定义标记替换的方式实现:
$html = '<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> </head> <body> <p>' " & < © 庭</p> </body> </html>'; // 提前将目标实体替换为自定义标记,避免被DOM解析 $html = str_replace( [''', '"'], ['__ENTITY_SINGLE_QUOTE__', '__ENTITY_DOUBLE_QUOTE__'], $html ); $dom = new DOMDocument(); $dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'), LIBXML_NOERROR); // 输出前将自定义标记替换回原实体 $output = str_replace( ['__ENTITY_SINGLE_QUOTE__', '__ENTITY_DOUBLE_QUOTE__'], [''', '"'], $dom->saveHTML() ); echo $output;
该方案可确保'和"实体被完整保留,同时解决UTF-8编码问题。
内容的提问来源于stack exchange,提问作者Jeff
相关产品推荐
相关产品推荐

