PHP DOMDocument nodeValue以字面UTF-8字符形式输出,而不是编码后的形式。

5
我遇到了类似于这个问题的问题: 在PHP中,从DomDocument返回的nodeValue返回奇怪的字符 我发现根本原因可以通过mb_convert_encoding()来模拟。
在我的单元测试中,最终捕捉到了这个问题。
$test = mb_convert_encoding('é', "UTF-8");
$this->assertTrue(mb_check_encoding($test,'UTF-8'),'data is UTF-8');
$this->assertTrue($this->rw->checkEncoding($test,'UTF-8'),'data is UTF-8');
$this->assertIdentical($test,html_entity_decode('é',ENT_QUOTES,'UTF-8'),'values match');

UTF-8 数据的原始值似乎正在传输,而 PHP 运行的系统的基本代码页很可能不是 UTF-8。
一直到解析(使用将数据转储到 DOMDocument 的 HTML5lib 实现),字符串保持清洁、友好的 UTF-8。只有在使用时提取数据时才会出现问题。
$span->nodeValue

我看到编码稳定性出现了失败。
我的猜测是,htmlentities在domdocument导出到nodeValue时使用了编码转换器,但忽略了内联编码值。
考虑到我的问题与HTML5有关,我认为它与实现的新颖性直接相关,但似乎是一个更广泛的问题。我没有找到任何关于这个问题特定于DOMDocument的信息,除了上面提到的问题。
更新:
为了向前迈进,我已经从HTML5lib和DOMDocument切换到Simple HTML DOM,它可以导出干净的转义HTML,然后我可以将其解析回正确的UTF-8实体。
另外,我没有尝试的一个函数是:
utf8_decode

这可能是其他遇到此问题的人的解决方案。它解决了我在AJAX/PHP方面遇到的一个相关问题,该解决方案可以在2009年的博客文章中找到:克服AJaX UTF-8编码限制(在PHP中)

欢迎来到SO!还有一些问题。您所说的“原始值”是什么意思?能给出一些示例吗?包含é的脚本文件使用的编码是什么?能展示正确和失败的值吗?您在页面上使用的输出编码是什么? - Pekka
“原始值”指的是渲染结果是通过这个函数调用获得的。 html_entity_decode('&Atilde;&copy;',ENT_QUOTES,'UTF-8') 所以,本质上,在源HTML中有一个包含字符é的单词的span标签。当我使用 $span->nodeValue提取该span标签的内容时,其中 $span是DOMDocument getElementsByTagName()的结果。 我正在尝试在所有地方都使用UTF-8,在这个HTML中,元数据设置为UTF-8,如下所示: `<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />` - Dave Espionage
所以,HTML页面显示é,而nodeValue的结果是渲染等效于&Atilde;&copy;的结果,根据我所读的内容,这相当于在没有默认编码为UTF-8的系统上运行mb_check_encoding('é', 'UTF-8')时发生的情况。 - Dave Espionage
2个回答

3

刚刚在一个nodeValue上使用了utf8_decode,它确实有点起作用了,解决了特殊字符无法正确显示的问题。

然而,一些字符仍然存在问题,例如单引号 ' 和一些其他字符(例如œ)

因此,使用$element->nodeValue将不起作用,但是utf8_decode($element->nodeValue)会 - 部分地解决问题。


啊,是的,在这种情况下,我正在处理法语重音符号,所以这就成为了一个主要问题,所有“标准”字母实体都没问题,但是任何涉及到UTF-8编码的字符都会被错误地转换。我在想是否有服务器设置相关的地方? - Dave Espionage

1

utf8_decodeutf8_encode函数的命名不太合适。它们分别从utf-8转换为iso-8859-1,以及从iso-8859-1转换为utf-8

当只使用utf-8作为参数调用mb_convert_encoding函数时,通常类似于使用utf8_encode函数。(“通常”是指除非您更改了内部代码页,您可能 - 希望 - 没有这样做)。

PHP的大多数函数都希望字符串编码为iso-8859-1。然而,libxml(这是php xml解析库的基础库)希望字符串编码为utf-8。因此,如果您不小心,很容易出现混乱的编码。

至于您的测试,第一行可能会产生误导。由于脚本中有一个字面上的é,测试结果将取决于您保存文件所使用的编码方式。请检查您的文本编辑器。

希望这能澄清一些问题。


我在最初的工作中学到了很多关于这些函数的作用 :) 我没有改变内部代码页(看到了有关它的警告)。值得注意的是,你在问题中看到的测试代码可能是第五个排列。我尝试了几种不同的保存文件方式(确保UTF-8、Windows本地)和触发该字符的方式(十六进制、ASCII、HTML实体),我发布的是最后一次尝试。这让我想再次测试那段代码!谢谢你的想法。 - Dave Espionage

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接