我正在尝试使用 DOMDocument 解析一些 HTML,但是当我这样做时,我突然失去了我的编码(至少在我看来是这样)。
$profile = "<div><p>various japanese characters</p></div>";
$dom = new DOMDocument();
$dom->loadHTML($profile);
$divs = $dom->getElementsByTagName('div');
foreach ($divs as $div) {
echo $dom->saveHTML($div);
}
这段代码的结果是我得到了一堆不是日语的字符。但是,如果我这样做:
echo $profile;
它显示正确。我试过 saveHTML 和 saveXML,都没有正确显示。我正在使用 PHP 5.3。
我所看到的:
ã¤ãªãã¤å·ã·ã«ã´ã«ã¦ãã¢ã¤ã«ã©ã³ãç³»ã®å®¶åºã«ã9人åå¼ã®5çªç®ã¨ãã¦çã¾ãããå½¼ãå«ãã¦4人ã俳åªã«ãªã£ããç¶è¦ªã¯æ¨æã®ã»ã¼ã«ã¹ãã³ã§ãæ¯è¦ªã¯éµä¾¿å±ã®å®¢å®¤ä¿ã ã£ããé«æ ¡æ代ã¯ãã£ãã£ã®ã¢ã«ãã¤ãã«å¤ãã¿ãæè²è³éãåããªããã«ããªãã¯ç³»ã®é«æ ¡ã¸é²å¦ã
应该显示的内容:
イリノイ州シカゴにて、アイルランド系の家庭に、9人兄弟の5番目として生まれる。彼を含めて4人が俳優になった。父親は木材のセールスマンで、母親は郵便局の客室係だった。高校時代はキャディのアルバイトに勤しみ、教育資金を受けながらカトリック系の高校へ進学
编辑:我已将代码简化为五行,以便您自己测试。
$profile = "<div lang=ja><p>イリノイ州シカゴにて、アイルランド系の家庭に、</p></div>";
$dom = new DOMDocument();
$dom->loadHTML($profile);
echo $dom->saveHTML();
echo $profile;
这是返回的 html:
<div lang="ja"><p>イリノイ州シカゴã«ã¦ã€ã‚¢ã‚¤ãƒ«ãƒ©ãƒ³ãƒ‰ç³»ã®å®¶åºã«ã€</p></div>
<div lang="ja"><p>イリノイ州シカゴにて、アイルランド系の家庭に、</p></div>
DOMDocument::loadHTML
会将您的字符串视为 ISO-8859-1(HTTP/1.1 默认字符集),除非您另有说明。这会导致 UTF-8 字符串被错误地解释。
如果您的字符串不包含 XML 编码声明,您可以在前面添加一个以使字符串被视为 UTF-8:
$profile = '<p>イリノイ州シカゴにて、アイルランド系の家庭に、9</p>';
$dom = new DOMDocument();
$dom->loadHTML('<?xml encoding="utf-8" ?>' . $profile);
echo $dom->saveHTML();
如果您不知道字符串是否已经包含这样的声明,那么 SmartDOMDocument 中有一个解决方法可以帮助您:
$profile = '<p>イリノイ州シカゴにて、アイルランド系の家庭に、9</p>';
$dom = new DOMDocument();
$dom->loadHTML(mb_convert_encoding($profile, 'HTML-ENTITIES', 'UTF-8'));
echo $dom->saveHTML();
这不是一个很好的解决方法,但由于并非所有字符都可以在 ISO-8859-1 中表示(如这些武士刀),因此它是最安全的选择。
问题在于 saveHTML()
和 saveXML()
,它们在 Unix 中都不能正常工作。在 Unix 中使用时,它们不能正确保存 UTF-8 字符,但它们在 Windows 中工作。
解决方法非常简单:
如果您尝试使用默认值,您将收到您描述的错误
$str = $dom->saveHTML(); // saves incorrectly
您所要做的就是保存如下:
$str = $dom->saveHTML($dom->documentElement); // saves correctly
这行代码将正确保存您的 UTF-8 字符。如果您使用 saveXML()
,请使用相同的解决方法。
更新
正如下面评论部分中的“Jack M”所建议的,并由“Pamela”和“Marco Aurélio Deleu”验证,以下变体可能适用于您的情况:
$str = utf8_decode($dom->saveHTML($dom->documentElement));
笔记
不带参数使用saveHTML()时英文字符不会有任何问题(因为在UTF-8中英文字符被保存为单字节字符)当您有多字节字符时会出现问题(例如中文、俄文、阿拉伯文、希伯来文) , ...ETC。)
我推荐阅读这篇文章:http://coding.smashingmagazine.com/2012/06/06/all-about-unicode-utf8-character-sets/。您将了解 UTF-8 的工作原理以及为什么会出现此问题。这将花费您大约 30 分钟,但这是值得花的时间。
$str = utf8_decode($dom->saveHTML($dom->documentElement));
utf8_decode($dom->saveHTML($dom->documentElement));
为我做得很好。
确保真正的源文件保存为 UTF-8(您甚至可能想尝试使用 UTF-8 来确保不推荐的 BOM 字符)。
同样对于 HTML,请确保您已使用 meta
标记声明了正确的编码:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
如果它是 CMS(因为您已使用 Joomla 标记了您的问题),您可能需要为编码配置适当的设置。
<meta charset="UTF-8">
标记不适用于 DOMDocument。
<meta charset="UTF-8">
完全没有问题:见 3v4l.org/AATjh
这花了我一段时间才弄清楚,但这是我的答案。
在使用 DomDocument 之前,我会使用 file_get_contents 来检索 URL,然后使用字符串函数处理它们。也许不是最好的方法,但很快。在确信 Dom 的速度一样快后,我首先尝试了以下方法:
$dom = new DomDocument('1.0', 'UTF-8');
if ($dom->loadHTMLFile($url) == false) { // read the url
// error message
}
else {
// process
}
尽管有适当的元标记、PHP 设置以及此处和其他地方提供的所有其他补救措施,但在保留 UTF-8 编码方面却失败了。这是有效的:
$dom = new DomDocument('1.0', 'UTF-8');
$str = file_get_contents($url);
if ($dom->loadHTML(mb_convert_encoding($str, 'HTML-ENTITIES', 'UTF-8')) == false) {
}
等等。现在世界上一切都很好。
DomDocument('1.0', 'UTF-8')
中的参数,也适用于我。但在我的情况下,只加载了部分 html。
您可以为强制 utf-8
编码的行添加前缀,如下所示:
@$doc->loadHTML('<?xml version="1.0" encoding="UTF-8"?>' . "\n" . $profile);
然后您可以继续使用已有的代码,例如:
$doc->saveXML()
为 UTF-8 使用正确的标头
不要满足于“它有效”。
@cmbuckley 在他接受的答案中建议将 <?xml encoding="utf-8" ?>
设置为文档。然而,在 HTML 文档中使用 XML 声明有点奇怪。 HTML 不是 XML(除非它是 XHTML),它可能会在通往客户端的过程中混淆浏览器和其他软件(可能是其他人报告的故障的根源)。
我成功使用了 HTML5 声明:
$profile = '<p>イリノイ州シカゴにて、アイルランド系の家庭に、9</p>';
$dom = new DOMDocument();
$dom->loadHTML('<!DOCTYPE html><meta charset="UTF-8">' . $profile);
echo $dom->saveHTML();
如果您使用其他标准,请使用正确的标头,DOMDocument 非常迂腐地遵循标准并且似乎也支持 HTML5(如果不是您的情况,请尝试更新 libxml 扩展名)。
<!DOCTYPE alsfjaswrtoiufn>
您会得到相同的结果,即它只会输出您输入的任何内容。
您必须为 DOMDocument 提供一个带有有意义的标头的 HTML 版本。就像 HTML5 一样。
$profile ='<?xml version="1.0" encoding="'.$_encoding.'"?>'. $html;
让您的 html 尽可能有效可能是一个好主意,这样您就不会在开始查询时遇到问题... :-) 并远离 htmlentities
!!!!那是一种必要的来回浪费资源。保持你的代码疯狂!!!!
使用它以获得正确的结果
$dom = new DOMDocument();
$dom->loadHTML('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">' . $profile);
echo $dom->saveHTML();
echo $profile;
这个操作
mb_convert_encoding($profile, 'HTML-ENTITIES', 'UTF-8');
这是不好的方法,因为像 < ; 这样的特殊符号, >可以在 $profile 中,并且在 mb_convert_encoding 之后它们不会转换两次。这是 XSS 和不正确 HTML 的漏洞。
为我找到工作:
$dom = new \DOMDocument;
$dom->loadHTML(utf8_decode($html));
...
return utf8_encode( $dom->saveHTML());
?
)
唯一对我有用的是接受的答案
$profile = '<p>イリノイ州シカゴにて、アイルランド系の家庭に、9</p>';
$dom = new DOMDocument();
$dom->loadHTML('<?xml encoding="utf-8" ?>' . $profile);
echo $dom->saveHTML();
然而
这带来了新的问题,即在文档的输出中包含 <?xml encoding="utf-8" ?>
。
我的解决方案是做
foreach ($doc->childNodes as $xx) {
if ($xx instanceof \DOMProcessingInstruction) {
$xx->parentNode->removeChild($xx);
}
}
一些解决方案告诉我要删除 xml
标头,我必须执行
$dom->saveXML($dom->documentElement);
对于部分文档(例如,带有两个 <p>
标签的文档),这对我不起作用,只有一个 <p>
标签被返回。
问题是当您向 DOMDocument::saveHTML()
函数添加参数时,您会丢失编码。在少数情况下,您需要避免使用参数并使用旧的字符串函数来查找您要查找的内容。
我认为先前的答案对您有用,但是由于此解决方法对我不起作用,因此我添加了该答案以帮助可能与我有关的人。
不定期副业成功案例分享
$dom->loadHTML('<?xml encoding="utf-8" ?>' . $content);
在 PHP7 中为我修复了它(所以它仍然是一个问题) - 这是一个非常烦人的问题,因为我在 HTML 文档中定义了 utf8(使用<meta charset="UTF-8" />
)但是没有效果,它似乎需要<?xml 部分,这完全不直观。$dom->loadHTML(mb_convert_encoding($profile, 'HTML-ENTITIES', 'UTF-8'));
效果很好!谢谢,