DOMDocument::load()加载非英文维基页面触发警告的原因排查
问题现象
1. 法语维基百科页面测试
测试代码:
$doc = new DOMDocument(); $doc->load("https://fr.wikipedia.org/wiki/Facebook"); echo $doc->saveHTML();
运行后返回警告:
Warning: DOMDocument::load(): Specification mandates value for attribute checked in https://fr.wikipedia.org/wiki/Facebook, line: 43 in C:\laragon\www\test.php on line 190 Warning: DOMDocument::load(): Opening and ending tag mismatch: img line 37 and span in https://fr.wikipedia.org/wiki/Facebook, line: 68 in C:\laragon\www\test.php on line 190 Warning: DOMDocument::load(): Opening and ending tag mismatch: img line 37 and a in https://fr.wikipedia.org/wiki/Facebook, line: 69 in C:\laragon\www\test.php on line 190 Warning: DOMDocument::load(): Opening and ending tag mismatch: span line 37 and div in https://fr.wikipedia.org/wiki/Facebook, line: 71 in C:\laragon\www\test.php on line 190 Warning: DOMDocument::load(): Opening and ending tag mismatch: img line 37 and header in https://fr.wikipedia.org/wiki/Facebook, line: 156 in C:\laragon\www\test.php on line 190 Warning: DOMDocument::load(): Opening and ending tag mismatch: a line 37 and div in https://fr.wikipedia.org/wiki/Facebook, line: 2971 in C:\laragon\www\test.php on line 190 Warning: DOMDocument::load(): Opening and ending tag mismatch: header line 37 and body in https://fr.wikipedia.org/wiki/Facebook, line: 2977 in C:\laragon\www\test.php on line 190 Warning: DOMDocument::load(): Opening and ending tag mismatch: input line 37 and html in https://fr.wikipedia.org/wiki/Facebook, line: 2978 in C:\laragon\www\test.php on line 190 Warning: DOMDocument::load(): EndTag: '</' not found in https://fr.wikipedia.org/wiki/Facebook, line: 2978 in C:\laragon\www\test.php on line 190
2. 中文维基百科页面测试
测试代码:
$doc->load(rawurldecode("https://zh.wikipedia.org/wiki/亞馬遜公司")); echo $doc->saveHTML();
即使使用rawurldecode处理URL适配亚洲语言编码,仍然返回警告:
Warning: DOMDocument::load(): Entity 'reg' not defined in https://zh.wikipedia.org/wiki/%E4%BA%9E%E9%A6%AC%E9%81%9C%E5%85%AC%E5%8F%B8, line: 1382 in C:\laragon\www\test.php on line 181 Warning: DOMDocument::load(): Entity 'trade' not defined in https://zh.wikipedia.org/wiki/%E4%BA%9E%E9%A6%AC%E9%81%9C%E5%85%AC%E5%8F%B8, line: 1382 in C:\laragon\www\test.php on line 181
核心疑问:调用DOMDocument的load方法加载法语、中文、日语等非英文维基页面时会触发不同类型的警告,加载英文页面却可以正常运行,原因是什么,如何解决?
原因说明
DOMDocument::load()默认按严格XML规范解析内容,但维基百科返回的是HTML5页面,本身就不满足严格XML语法要求:比如布尔属性不写值、自闭合标签不按XML规则闭合、自定义HTML实体这类写法在HTML里完全合法,放到XML解析器里就会直接报错。- 不同语言版本的维基页面返回的HTML结构、用到的语法特性有差异,所以报的错误类型不一样:法语版页面存在无值的
checked属性、未闭合的img标签这类写法,中文版页面用到了®(注册商标符号)、™(商标符号)这类HTML实体,而XML默认只识别&/</>/"/'5个基础实体,自然会报实体未定义的错误。 - 英文页面只是刚好返回的内容没有触发XML严格校验的雷点,不代表英文页面就完全兼容
load()的XML解析规则,只是概率问题。 - 额外提醒:用
rawurldecode处理多语言URL完全是多余操作,DOMDocument::load()和file_get_contents()原生支持标准百分号编码的URL,手动解码反而可能在部分环境下导致URL解析异常。
解决方案
不要直接用load()方法加载远程HTML内容,换成专门针对HTML解析的逻辑,同时临时关闭解析错误抛出,避免警告干扰:
// 1. 先手动获取页面内容,不要直接传URL给load,规避编码、实体解析的兼容问题 $html = file_get_contents("https://zh.wikipedia.org/wiki/亞馬遜公司"); $doc = new DOMDocument(); // 2. 临时关闭内部错误输出,忽略HTML不规范导致的警告 libxml_use_internal_errors(true); // 3. 用loadHTML()方法而非load(),该方法按HTML语法规则解析,不强制严格XML规范 // 前置加UTF-8编码声明,避免解析后出现乱码 $doc->loadHTML('<?xml encoding="UTF-8">' . $html); // 4. 不需要留存错误信息就清空错误缓存,恢复错误抛出规则 libxml_clear_errors(); libxml_use_internal_errors(false); echo $doc->saveHTML();
该写法适配所有语言版本的维基页面解析,不会再出现上述警告,最终生成的DOM结构可正常使用。
内容的提问来源于stack exchange,提问作者user7962781
相关产品推荐
相关产品推荐

