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

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

например:

ירושלים

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

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

Хорошо, здесь вы идете:

 $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 в документ, который не указывает кодировку, вы потеряете все, что вы заявили в конструкторе, а это означает:

 $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(); 

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

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

Если вы хотите вывести 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!

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

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

Ну, правда, это не противоречит нахождению в вопросе. Не всегда .

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

 $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, применяются разные правила .
  • Вы не можете указать, хотите ли вы использовать сущности или нет для вывода, загружая XML-документ в виде кодированной строки UTF-8 в PHP DOMDocument per-se. Даже с флагами libxml и предоставлением спецификации. [1]
  • Вы можете указать, что вы не хотите использовать сущности, установив кодировку документов в UTF-8.
  • Если возможно, вы можете манипулировать входной строкой, содержащей XML-декларацию, определяющую кодировку документов, как указано в ответе Гордона .

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

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


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

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

например

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

скорее, чем:

 $dom->saveXML(); 

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

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

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

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

 $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 

К точному ответу:

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

  $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); 

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