Intereting Posts
Изменение размера изображений на PHP без использования сторонних библиотек? Zend_Config_Xml странное поведение PHP – функция раскрывающегося списка, которая удерживает текущую страницу в фокусе Доктрина: изменение формата даты при получении и установке значений полей Является ли синхронизация в Amazon S3 PHP SDK / API действительно синхронизацией? Пусть браузеры кэшируют мою динамическую таблицу стилей PHP PHP-тиснение с цветом Symfony on Heroku: 403 Forbidden У вас нет прав доступа / доступа на этом сервере Проверка формы Codeigniter Память memory_get_peak_usage () возвращает память всего php или только текущего исполнения? Проверьте статус пользователя, а затем, если все в порядке, проверьте, есть ли admin; с PHP (база данных mysql) PHP: Предупреждение mcrypt_generic_init (): размер Iv неверен; длина: 12, необходимо: 8 Как чистить изображение с помощью PHP с моего сайта? Форма, не отправляющая при попытке использования jQuery's submitHandler php – изменить размер и сохранить изображение?

PHP не имеет функции для XML-безопасного сущностного декодирования? У вас нет xml_entity_decode?

ПРОБЛЕМА : Мне нужен XML-файл, полный кодированный UTF8; то есть без сущности, представляющей символы, все символы, подпадающие под UTF8, за исключением только трех, которые зарезервированы для XML, «&» (amp), «<» (lt) и «>» (gt). И мне нужна встроенная функция, которая делает это быстро : преобразовывать сущности в реальные символы UTF8 (без развращения моего XML).
PS: это «проблема реального мира» (!); в PMC / журналах , например, есть 2,8 млн. научных статей, связанных с специальным XML DTD (также известным как формат JATS ) … Для обработки как «обычного XML-UTF8-текста» нам нужно перейти от числового объекта к UTF8 голец.

ПОПЫТНОЕ РЕШЕНИЕ : естественной функцией для этой задачи является html_entity_decode , но она разрушает XML-код (!), Преобразуя зарезервированные 3 зарезервированных символа XML.

Иллюстрируя проблему

предполагать

$xmlFrag ='<p>Hello world!    Let A&lt;B and A=∬dxdy</p>'; 

Если объекты 160 (nbsp) и x222C (двойной интеграл) должны быть преобразованы в UTF8, а XML-зарезервировано lt not. Текст XML будет (после преобразования),

$ xmlFrag = ' <p> Привет, мир! Пусть A &lt; B и A = ∬dxdy </p> ';

Текст «A <B» нуждается в символе с сохранением XML, поэтому ДОЛЖЕН оставаться как A&lt;B


Разочарованные решения

Я пытаюсь использовать html_entity_decode для решения (напрямую!) Проблемы … Итак, я обновил свой PHP до версии 5.5, чтобы попытаться использовать параметр ENT_XML1 ,

  $s = html_entity_decode($xmlFrag, ENT_XML1, 'UTF-8'); // not working // as I expected 

Возможно, еще один вопрос: «ПОЧЕМУ нет другого способа делать то, что я ожидал?» – это важно для многих других приложений XML (!), причем не только для меня.


Мне не нужен обходной путь в качестве ответа … Хорошо, я показываю свою уродливую функцию, возможно, это помогает понять проблему,

  function xml_entity_decode($s) { // here an illustration (by user-defined function) // about how the hypothetical PHP-build-in-function MUST work static $XENTITIES = array('&amp;','&gt;','&lt;'); static $XSAFENTITIES = array('#_x_amp#;','#_x_gt#;','#_x_lt#;'); $s = str_replace($XENTITIES,$XSAFENTITIES,$s); //$s = html_entity_decode($s, ENT_NOQUOTES, 'UTF-8'); // any php version $s = html_entity_decode($s, ENT_HTML5|ENT_NOQUOTES, 'UTF-8'); // PHP 5.3+ $s = str_replace($XSAFENTITIES,$XENTITIES,$s); return $s; } // you see? not need a benchmark: // it is not so fast as direct use of html_entity_decode; if there // was an XML-safe option was ideal. 

PS: исправлено после этого ответа . Должен быть флаг ENT_HTML5 , для конвертирования действительно всех названных объектов .

Solutions Collecting From Web of "PHP не имеет функции для XML-безопасного сущностного декодирования? У вас нет xml_entity_decode?"

Используйте DTD при загрузке XML-документа JATS, так как он определит любое сопоставление от именованных объектов к символам Unicode, а затем установите кодировку в UTF-8 при сохранении:

 $doc = new DOMDocument; $doc->load($inputFile, LIBXML_DTDLOAD | LIBXML_NOENT); $doc->encoding = 'UTF-8'; $doc->save($outputFile); 

Этот вопрос создает время от времени «ложный ответ» (см. Ответы). Возможно, это связано с тем, что люди не обращают внимания, и потому что нет НИКАКОГО ОТВЕТА : есть недостаток встроенного в PHP решения .

… Итак, повторите мое обходное решение (это НЕ ответ !), Чтобы не создавать больше путаницы:

Лучшее обходное решение

Обращать внимание:

  1. Функция xml_entity_decode() ниже – лучший (по сравнению с любым другим) способом обхода .
  2. Функция ниже не является ответом на данный вопрос , это только работа.
  function xml_entity_decode($s) { // illustrating how a (hypothetical) PHP-build-in-function MUST work static $XENTITIES = array('&amp;','&gt;','&lt;'); static $XSAFENTITIES = array('#_x_amp#;','#_x_gt#;','#_x_lt#;'); $s = str_replace($XENTITIES,$XSAFENTITIES,$s); $s = html_entity_decode($s, ENT_HTML5|ENT_NOQUOTES, 'UTF-8'); // PHP 5.3+ $s = str_replace($XSAFENTITIES,$XENTITIES,$s); return $s; } 

Чтобы протестировать и продемонстрировать, что у вас есть лучшее решение, сначала проверьте этот простой benckmark:

  $countBchMk_MAX=1000; $xml = file_get_contents('sample1.xml'); // BIG and complex XML string $start_time = microtime(TRUE); for($countBchMk=0; $countBchMk<$countBchMk_MAX; $countBchMk++){ $A = xml_entity_decode($xml); // 0.0002 /* 0.0014 $doc = new DOMDocument; $doc->loadXML($xml, LIBXML_DTDLOAD | LIBXML_NOENT); $doc->encoding = 'UTF-8'; $A = $doc->saveXML(); */ } $end_time = microtime(TRUE); echo "\n<h1>END $countBchMk_MAX BENCKMARKs WITH ", ($end_time - $start_time)/$countBchMk_MAX, " seconds</h1>"; 
  public function entity_decode($str, $charset = NULL) { if (strpos($str, '&') === FALSE) { return $str; } static $_entities; isset($charset) OR $charset = $this->charset; $flag = is_php('5.4') ? ENT_COMPAT | ENT_HTML5 : ENT_COMPAT; do { $str_compare = $str; // Decode standard entities, avoiding false positives if ($c = preg_match_all('/&[az]{2,}(?![az;])/i', $str, $matches)) { if ( ! isset($_entities)) { $_entities = array_map('strtolower', get_html_translation_table(HTML_ENTITIES, $flag, $charset)); // If we're not on PHP 5.4+, add the possibly dangerous HTML 5 // entities to the array manually if ($flag === ENT_COMPAT) { $_entities[':'] = '&colon;'; $_entities['('] = '&lpar;'; $_entities[')'] = '&rpar'; $_entities["\n"] = '&newline;'; $_entities["\t"] = '&tab;'; } } $replace = array(); $matches = array_unique(array_map('strtolower', $matches[0])); for ($i = 0; $i < $c; $i++) { if (($char = array_search($matches[$i].';', $_entities, TRUE)) !== FALSE) { $replace[$matches[$i]] = $char; } } $str = str_ireplace(array_keys($replace), array_values($replace), $str); } // Decode numeric & UTF16 two byte entities $str = html_entity_decode( preg_replace('/(&#(?:x0*[0-9a-f]{2,5}(?![0-9a-f;]))|(?:0*\d{2,4}(?![0-9;])))/iS', '$1;', $str), $flag, $charset ); } while ($str_compare !== $str); return $str; } 

У меня была та же проблема, потому что кто-то использовал HTML-шаблоны для создания XML вместо использования SimpleXML. вздох … Во всяком случае, я придумал следующее. Это не так быстро, как ваш, но это не на порядок медленнее, и он менее взломан. Ваш будет непреднамеренно конвертировать #_x_amp#; до $amp; , однако маловероятно его присутствие в исходном XML.

Примечание. Я предполагаю, что кодировка по умолчанию – UTF-8

 // Search for named entities (strings like "&abc1;"). echo preg_replace_callback('#&[A-Z0-9]+;#i', function ($matches) { // Decode the entity and re-encode as XML entities. This means "&amp;" // will remain "&amp;" whereas "&euro;" becomes "€". return htmlentities(html_entity_decode($matches[0]), ENT_XML1); }, "<Foo>&euro;&amp;foo &Ccedil;</Foo>") . "\n"; /* <Foo>€&amp;foo Ç</Foo> */ 

Кроме того, если вы хотите заменить специальные символы нумерованными объектами (если вы не хотите XML UTF-8), вы можете легко добавить функцию к вышеуказанному коду:

 // Search for named entities (strings like "&abc1;"). $xml_utf8 = preg_replace_callback('#&[A-Z0-9]+;#i', function ($matches) { // Decode the entity and re-encode as XML entities. This means "&amp;" // will remain "&amp;" whereas "&euro;" becomes "€". return htmlentities(html_entity_decode($matches[0]), ENT_XML1); }, "<Foo>&euro;&amp;foo &Ccedil;</Foo>") . "\n"; echo mb_encode_numericentity($xml_utf8, [0x80, 0xffff, 0, 0xffff]); /* <Foo>&#8364;&amp;foo &#199;</Foo> */ 

В вашем случае вы хотите, чтобы все было наоборот. Кодировать нумерованные объекты как UTF-8:

 // Search for named entities (strings like "&abc1;"). $xml_utf8 = preg_replace_callback('#&[A-Z0-9]+;#i', function ($matches) { // Decode the entity and re-encode as XML entities. This means "&amp;" // will remain "&amp;" whereas "&euro;" becomes "€". return htmlentities(html_entity_decode($matches[0]), ENT_XML1); }, "<Foo>&euro;&amp;foo &Ccedil;</Foo>") . "\n"; // Encodes (uncaught) numbered entities to UTF-8. echo mb_decode_numericentity($xml_utf8, [0x80, 0xffff, 0, 0xffff]); /* <Foo>€&amp;foo Ç</Foo> */ 

эталонный тест

Я добавил контрольный показатель для хорошей оценки. Это также демонстрирует недостаток вашего решения для ясности. Ниже приведена введенная строка.

 <Foo>&euro;&amp;foo &Ccedil; &eacute; #_x_amp#; &#8748;</Foo> 

Ваш метод

 php -r '$q=["&amp;","&gt;","&lt;"];$y=["#_x_amp#;","#_x_gt#;","#_x_lt#;"]; $s=microtime(1); for(;++$i<1000000;)$r=str_replace($y,$q,html_entity_decode(str_replace($q,$y,"<Foo>&euro;&amp;foo &Ccedil; &eacute; #_x_amp#; &#8748;</Foo>"),ENT_HTML5|ENT_NOQUOTES)); $t=microtime(1)-$s; echo"$r\n=====\nTime taken: $t\n";' <Foo>€&amp;foo Ç é &amp; ∬</Foo> ===== Time taken: 2.0397531986237 

Мой метод

 php -r '$s=microtime(1); for(;++$i<1000000;)$r=preg_replace_callback("#&[A-Z0-9]+;#i",function($m){return htmlentities(html_entity_decode($m[0]),ENT_XML1);},"<Foo>&euro;&amp;foo &Ccedil; &eacute; #_x_amp#; &#8748;</Foo>"); $t=microtime(1)-$s; echo"$r\n=====\nTime taken: $t\n";' <Foo>€&amp;foo Ç é #_x_amp#; &#8748;</Foo> ===== Time taken: 4.045273065567 

Мой метод (с юникодом для нумерованного объекта):

 php -r '$s=microtime(1); for(;++$i<1000000;)$r=mb_encode_numericentity(preg_replace_callback("#&[A-Z0-9]+;#i",function($m){return htmlentities(html_entity_decode($m[0]),ENT_XML1);},"<Foo>&euro;&amp;foo &Ccedil; &eacute; #_x_amp#; &#8748;</Foo>"),[0x80,0xffff,0,0xffff]); $t=microtime(1)-$s; echo"$r\n=====\nTime taken: $t\n";' <Foo>&#8364;&amp;foo &#199; &#233; #_x_amp#; &#8748;</Foo> ===== Time taken: 5.4407880306244 

Мой метод (с нумерованным объектом для юникода):

 php -r '$s=microtime(1); for(;++$i<1000000;)$r=mb_decode_numericentity(preg_replace_callback("#&[A-Z0-9]+;#i",function($m){return htmlentities(html_entity_decode($m[0]),ENT_XML1);},"<Foo>&euro;&amp;foo &Ccedil; &eacute; #_x_amp#;</Foo>"),[0x80,0xffff,0,0xffff]); $t=microtime(1)-$s; echo"$r\n=====\nTime taken: $t\n";' <Foo>€&amp;foo Ç é #_x_amp#; ∬</Foo> ===== Time taken: 5.5400078296661 

Попробуйте эту функцию:

 function xmlsafe($s,$intoQuotes=1) { if ($intoQuotes) return str_replace(array('&','>','<','"'), array('&amp;','&gt;','&lt;','&quot;'), $s); else return str_replace(array('&','>','<'), array('&amp;','&gt;','&lt;'), html_entity_decode($s)); } 

пример использования:

 echo '<k nid="'.$node->nid.'" description="'.xmlsafe($description).'"/>'; 

также: https://stackoverflow.com/a/9446666/2312709

этот код, используемый в производстве, кажется, что никаких проблем с UTF-8