DomDocument и специальные символы

Это мой код:

$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> получить тот же вывод <p>hello!</p> используя DOMDocument только для синтаксического анализа DOM и выполнения некоторых подстановок внутри тегов.

Ответ 1

Решение:

$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, в моем случае, не дают желаемого результата.

Ответ 2

Попробуйте установить тип кодировки после загрузки HTML.

$dom = new DOMDocument();
$dom->loadHTML($data);
$dom->encoding = 'utf-8';
echo $dom->saveHTML();

Другой путь

Ответ 3

Проблема, как представляется, известна, согласно комментариям пользователя на странице руководства на 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;
}

Ответ 5

Похоже, вам просто нужно установить substituteEntities, когда вы создаете объект DOMDocument.

Ответ 6

Я не знаю, почему отмеченный ответ не сработал для моей проблемы. Но этот сделал.

ref: https://www.php.net/manual/en/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

?>