php: используя DomDocument всякий раз, когда я пытаюсь написать UTF-8, он записывает шестнадцатеричную запись этого - PullRequest
11 голосов
/ 26 августа 2010

Когда я пытаюсь записать строки UTF-8 в файл XML с использованием DomDocument, он фактически записывает шестнадцатеричное представление строки вместо самой строки.

, например:

ירושלים

вместо: ירושלים

есть идеи, как решить проблему?

Ответы [ 6 ]

16 голосов
/ 26 августа 2010

Хорошо, вот и все:

$dom = new DOMDocument('1.0', 'utf-8');
$dom->appendChild($dom->createElement('root'));
$dom->documentElement->appendChild(new DOMText('ירושלים'));
echo $dom->saveXml();

будет работать нормально, потому что в этом случае созданный вами документ сохранит кодировку, указанную в качестве второго аргумента:

<?xml version="1.0" encoding="utf-8"?>
<root>ירושלים</root>

Однако, как только вы загрузите XML в Document, в котором не указана кодировка, вы потеряете все, что вы объявили в конструкторе, что означает:

$dom = new DOMDocument('1.0', 'utf-8');
$dom->loadXml('<root/>'); // missing prolog
$dom->documentElement->appendChild(new DOMText('ירושלים'));
echo $dom->saveXml();

не будет иметь кодировку utf-8:

<?xml version="1.0"?>
<root>&#x5D9;&#x5E8;&#x5D5;&#x5E9;&#x5DC;&#x5D9;&#x5DD;</root>

Так что, если вы загрузите что-то в формате XML, убедитесь, что это

$dom = new DOMDocument();
$dom->loadXml('<?xml version="1.0" encoding="utf-8"?><root/>');
$dom->documentElement->appendChild(new DOMText('ירושלים'));
echo $dom->saveXml();

, и оно будет работать как положено.

В качестве альтернативы вы также можете указатькодировка после загрузки документа.

6 голосов
/ 03 мая 2013

Если вы хотите вывести UTF-8 с DOMDocument, вам нужно указать это.Просто, не правда ли?Если вы уже поняли хитрый вопрос, вы не слишком далеки от этого, но на первый взгляд, это действительно просто.

Рассмотрим следующий (кодированный в UTF-8) пример кода, который выводит шестнадцатеричные сущности:

$dom = new DOMDocument();
$dom->loadXml('<root>ירושלים</root>');
$dom->save('php://output');

Вывод:

<?xml version="1.0"?>
<root>&#x5D9;&#x5E8;&#x5D5;&#x5E9;&#x5DC;&#x5D9;&#x5DD;</root>

Как написано, если вы хотите вывести это как UTF-8, вам нужно указать его, и это просто:

...
$dom->encoding = 'UTF-8';
$dom->save('php://output');

Выходные данные в явном виде в UTF-8 :

<?xml version="1.0" encoding="UTF-8"?>
<root>ירושלים</root>

Так много для прямой части.Если вас интересуют грязные мелочи, вы можете читать дальше - если нет, пожалуйста, не спрашивайте «почему?» :).

Я только что написал "в UTF-8 явно", поскольку и в первом примере выходные данные кодируются в UTF-8, XML просто содержит шестнадцатеричные сущности, что совершенно правильно - даже в UTF-8!

Вы уже заметили, что я начинаю с придирки, но помните: UTF-8 - это кодировка по умолчанию XML .

И если вы сейчас начнете говорить: эй, подождите, если кодировка по умолчанию UTF-8 в любом случае, почему PHP DOMDocument использует сущности в первую очередь?

Ну, правда, это не вопреки выводу в вопросе.Не всегда .

См. Следующий пример, в котором вместо значения узла, содержащего буквы Ivrit, используется XML-комментарий:

$dom = new DOMDocument();
$dom->loadXml('<root><!-- ירושלים --></root>');
$dom->save('php://output');

Вывод:

<?xml version="1.0"?>
<root><!-- ירושלים --></root>

Хорошо, всеЧисто?Итак, маленький грязный секрет здесь: есть ли у вас эти сущности XML или нет - для документа это не имеет значения, это просто другая форма записи одних и тех же символьных данных XML.И вы уже чувствуете себя приглашенным: давайте попробуем CDATA вместо первого примера:

$dom = new DOMDocument();
$dom->loadXML("<root><![CDATA[ירושלים]]></root>");
$dom->save('php://output');

Вывод:

<?xml version="1.0"?>
<root><![CDATA[ירושלים]]></root>

Как это видно из XML-комментарияНапример, здесь нет никаких сущностей XML, используемых здесь.Ну, они все равно не будут действительными, как в примере с XML-комментариями.

Для обзора давайте создадим пример, который содержит все это:

$dom = new DOMDocument();
$dom->loadXML("<!-- ירושלים --><root>&#x5D9;רושלים <![CDATA[ירושלים]]></root>");
$dom->save('php://output');

Вывод:

<?xml version="1.0"?>
<!-- ירושלים -->
<root>&#x5D9;&#x5E8;&#x5D5;&#x5E9;&#x5DC;&#x5D9;&#x5DD; <![CDATA[ירושלים]]></root>

Извлеченные уроки:

  • UTF-8 всегда используется.Только некоторые объекты используются в PCDATA, если не указана кодировка UTF-8. Если указано другое кодирование UTF-8, применяются другие правила .
  • Вы не можете указать, хотите ли вы использовать сущности или нет для вывода, загружая anXML-документ в виде строки в кодировке UTF-8 в PHP DOMDocument per se.Даже с libxml flags и без предоставления спецификации. [1]
  • Вы можете указать, что не хотите использовать объекты, установив кодировку документов в UTF-8.
  • Если вы можете, вы можете манипулироватьвходная строка, имеющая XML-декларацию с указанием документов, кодирующих , как указано в ответе Гордона .

Совет: Есливаша строка имеет XML-декларацию, которая не соответствует кодировке строк, или вы хотите изменить либо до загрузки строки в DOMDocument вам нужно изменить XML-декларацию и / или повторно-кодировать строку.Это было рассмотрено в ответе на вопрос PHP XMLReader, получите версию и кодировку , продемонстрировав, как работает XMLRecoder класс .

И это все, надеюсь.


[1] Возможно, если вы загружаете из HTTP-запроса и предоставляете контекст потока и помечаете кодировку символов через метаданные- но это надо сначала проверить, я не знаю.То, что спецификация не работает, является признаком того, что все эти вещи не работают.

3 голосов
/ 26 августа 2010

Очевидно, что передача documentElement в качестве $ node для saveXML работает в обход этого, хотя я не могу сказать, что понимаю, почему.

, например

$dom->saveXML($dom->documentElement);

вместо:

$dom->saveXML();

Источник: http://www.php.net/manual/en/domdocument.savexml.php#88525

1 голос
/ 17 декабря 2015

Ответ на этот вопрос таков:

Когда ваша функция запускается, сразу после получения содержимого сделайте следующее:

$content = mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8');

А затем запустите новый документ и т. Д.пример:

if ( empty( $content ) ) {
    return false;
}
$doc = new DOMDocument('1.0', 'utf-8');
libxml_use_internal_errors(true);
$doc->LoadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

Затем делайте то, что вы собирались сделать со своим кодом.

0 голосов
/ 25 марта 2013
$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
$doc->encoding = 'UTF-8'; // insert proper
0 голосов
/ 26 августа 2010

Когда я создал DomDocument для записи, я добавил следующие параметры:

dom = new DOMDocument('1.0','utf-8');

эти параметры вызвали запись строки UTF-8 как есть.

...