DomDocument和特殊字符

36

这是我的代码:

$oDom = new DOMDocument();
$oDom->loadHTML("èàéìòù");
echo $oDom->saveHTML();

这是输出结果:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><p>&Atilde;&uml;&Atilde;&nbsp;&Atilde;&copy;&Atilde;&not;&Atilde;&sup2;&Atilde;&sup1;</p></body></html>

我想要这个输出:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><p>èàéìòù</p></body></html>

我已经尝试过....

$oDom = new DomDocument('4.0', 'UTF-8');

或者使用1.0和其他的东西但什么都没有。

另一件事... 有没有一种方法可以获得完全相同未更改的HTML? 例如,使用此输入中的html <p>hello!</p> 仅使用DOMDocument解析DOM并在标记内进行一些替换,以获得相同的输出<p>hello!</p>


如果你的输出中出现了&Atilde;,那么说明你的UTF-8编码出现了问题,可能被转换成了iso-8859或其他编码格式。 - Marc B
可能是PHP DOMDocument loadHTML不正确地编码UTF-8的重复问题。 - cmbuckley
10个回答

65
解决方案:
$oDom = new DOMDocument();
$oDom->encoding = 'utf-8';
$oDom->loadHTML( utf8_decode( $sString ) ); // important!

$sHtml = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
$sHtml .= $oDom->saveHTML( $oDom->documentElement ); // important!

saveHTML()方法在指定节点时有所不同。您可以使用主节点($oDom->documentElement)手动添加所需的!DOCTYPE。另一个重要的事情是使用utf8_decode()。在我的情况下,DOMDocument类的所有属性和其他方法都不能产生所需的结果。


18
为了使此方法适用于ISO-8859-1字符集之外的其他字符,您需要使用多字节解码。这样,像中文或欧元符号之类的字符也将被正确编码。$oDom->loadHTML(mb_convert_encoding($sString, 'HTML-ENTITIES', 'UTF-8'));点击此处查看更多信息 - Andrew Killen
我差点为解决这个问题而疯掉了!非常感谢你! - George Henrique

7
请在加载HTML后再设置编码类型。
尽量在之后设置编码类型。
$dom = new DOMDocument();
$dom->loadHTML($data);
$dom->encoding = 'utf-8';
echo $dom->saveHTML();

Other way


7
$dom = new DomDocument();
$str = htmlentities($str);
$dom->loadHTML(utf8_decode($str));
$dom->encoding = 'utf-8';
.
.
.
$str = $dom->saveHTML();
$str = html_entity_decode($str);

上述代码对我很有用。

6

我不知道为什么标记的答案对我的问题没有用。但这个可以解决。

参考:https://www.php.net/manual/zh/class.domdocument.php

<?php

            // checks if the content we're receiving isn't empty, to avoid the warning
            if ( empty( $content ) ) {
                return false;
            }

            // converts all special characters to utf-8
            $content = mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8');

            // creating new document
            $doc = new DOMDocument('1.0', 'utf-8');

            //turning off some errors
            libxml_use_internal_errors(true);

            // it loads the content without adding enclosing html/body tags and also the doctype declaration
            $doc->LoadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

            // do whatever you want to do with this code now

?>

5
问题似乎是已知的,根据php.net上手册页面的用户评论。那里提出的解决方案包括放置。
<meta http-equiv="content-type" content="text/html; charset=utf-8">

在您放置任何包含非ASCII字符的字符串之前,请参考文档。
另一个技巧建议在其中放置


<?xml encoding="UTF-8">

作为文档中的第一个文本,然后在最后删除它。
讨厌的东西。对我来说像是个漏洞。

4
这样做:
/**
 * @param string $text
 * @return DOMDocument
 */
private function buildDocument($text)
{
    $dom = new DOMDocument();

    libxml_use_internal_errors(true);
    $dom->loadHTML('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">' . $text);
    libxml_use_internal_errors(false);

    return $dom;
}

1
我需要它用于移动应用程序使用的API端点。只有这个解决方案适合我。谢谢 :) - Waqas

3

What worked for me was:

$doc->loadHTML(mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8'));

来源: https://davidwalsh.name/domdocument-utf8-problem

在PHP的DOMDocument类中处理UTF-8文档时,可能会遇到问题并导致返回的结果被截断。解决这个问题的方法是将DOMDocument对象的encoding属性设置为UTF-8,并使用iconv将传入DOMDocument的HTML代码转换为UTF-8编码。这样做可以确保文档正确解析且不会因为编码问题而出现错误或截断。

这解决了我的问题,关于土耳其字符。 - TCS

1

以上方法均不适用于我,但这个方法解决了我的问题:

$fileContent = file_get_contents('my_file.html');
$dom = new DOMDocument();
@$dom->loadHTML(mb_convert_encoding($fileContent, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$dom->encoding = 'utf-8';
$html = $dom->saveHTML();
$html = html_entity_decode($html, ENT_COMPAT, 'UTF-8');
echo $html;

0

0

这对我有用:

<?php

$doc = new DOMDocument();
$doc->loadHTML('<?xml encoding="UTF-8">' . $html);

// dirty fix
foreach ($doc->childNodes as $item) {
    if ($item->nodeType == XML_PI_NODE) {
        $doc->removeChild($item); // remove hack
    }
}

?>

致谢:https://www.php.net/manual/en/domdocument.loadhtml.php#95251


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