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

Я возвращаю некоторые html-строки из моей базы данных, и я хотел бы проанализировать эти строки в моем DOMDocument. Проблема в том, что DOMDocument дает предупреждения по специальным символам.

Предупреждение: DOMDocumentFragment :: appendXML () [domdocumentfragment.appendxml]: Entity: строка 2: ошибка парсера: Entity 'nbsp' не определен в page.php в строке 189

Интересно, почему и мне интересно, как это решить. Это некоторые фрагменты кода моей страницы. Как я могу исправить эти предупреждения?

$doc = new DOMDocument(); // .. create some elements first, like some divs and a h1 .. while($row = mysql_fetch_array($result)) { $messageEl = $doc->createDocumentFragment(); $messageEl->appendXML($row['message']); // gives it's warnings here! $otherElement->appendChild($messageEl); } echo $doc->saveHTML(); 

Я также нашел что-то о проверке, но, применяя это, моя страница больше не загружается. Код, который я пробовал для этого, был примерно таким.

 $implementation = new DOMImplementation(); $dtd = $implementation->createDocumentType('html','-//W3C//DTD XHTML 1.0 Transitional//EN','http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'); $doc = $implementation->createDocument('','',$dtd); $doc->validateOnParse = true; $doc->formatOutput = true; // in the same whileloop, I used the following: $messageEl = $doc->createDocumentFragment(); $doc->validate(); // which stopped my code, but error- and warningless. $messageEl->appendXml($row['message']); 

Заранее спасибо!

Существует нет   в XML. Единственными символьными сущностями, которые имеют фактическое имя, определенное (вместо использования числовой ссылки), являются & , < , > , " и " ,

Это означает, что вам нужно использовать числовой эквивалент неразрывного пробела, который равен? или (в гексагоне)   ,

Если вы пытаетесь сохранить HTML в контейнер XML, сохраните его как текст. HTML и XML могут выглядеть схожими, но они очень разные. appendXML() ожидает корректно сформированного XML в качестве аргумента. nodeValue этого nodeValue свойство nodeValue , оно будет кодировать HTML-строку HTML без каких-либо предупреждений.

 // document fragment is completely unnecessary $otherElement->nodeValue = $row['message']; 

Это сложно, потому что на самом деле это несколько проблем.

Как указывает Томалак, нет   в XML. Итак, вы сделали правильную вещь, указав DOMImplementation, потому что в XHTML есть   , Но для DOM знать, что документ XHTML, у вас есть загрузка и проверка на DTD. DTD находится по адресу

 http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd 

но из-за того, что на эту страницу ежедневно поступает миллионы запросов, W3C решил заблокировать доступ к этой странице , если в запросе нет UserAgent. Для предоставления UserAgent вам необходимо создать настраиваемый контекст потока.

В коде:

 // make sure DOM passes a User Agent when it fetches the DTD libxml_set_streams_context( stream_context_create( array( 'http' => array( 'user_agent' => 'PHP libxml agent', ) ) ) ); // specify the implementation $imp = new DOMImplementation; // create a DTD (here: for XHTML) $dtd = $imp->createDocumentType( 'html', '-//W3C//DTD XHTML 1.0 Transitional//EN', 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd' ); // then create a DOMDocument with the configured DTD $dom = $imp->createDocument(NULL, "html", $dtd); $dom->encoding = 'UTF-8'; $dom->validate(); $fragment = $dom->createDocumentFragment(); $fragment->appendXML(' <head><title>XHTML test</title></head> <body><p>Some text with a &nbsp; entity</p></body> ' ); $dom->documentElement->appendChild($fragment); $dom->formatOutput = TRUE; echo $dom->saveXml(); 

Это все еще занимает некоторое время, чтобы закончить (не спрашивайте меня почему), но в конце вы получите ( переформатированный для SO )

 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>XHTML test</title> </head> <body> <p>Some text with a &nbsp; entity</p> </body> </html> 

Также см. Проблему DOMDocument :: validate ()

Я вижу проблему, о которой идет речь, а также о том, что на вопрос был дан ответ, но если я могу предложить мысль из моего прошлого, касающуюся подобных проблем.

Это может быть так, что ваша задача требует включения помеченных данных из базы данных в результирующий XML, но может или не требует синтаксического анализа. Если это всего лишь данные для включения, а не структурированные части вашего XML, вы можете поместить строки из базы данных в секции (разделы) CDATA , эффективно минуя все ошибки проверки на этом этапе.

Хотя smarty может быть хорошей ставкой (зачем изобретать колесо в 14-й раз?), У этрангера может быть точка. Есть ситуации, когда вы не хотите использовать что-то слишком, как полный новый (и неизученный) пакет, но скорее похожи на то, что вы хотите опубликовать некоторые данные из базы данных, которая только что содержит html-файлы, с которыми столкнулся XML-парсер.

Предупреждение. Следующее – простое решение, но не делайте этого, если вы НЕ УВЕРЕНЫ, что можете с ним справиться! (Я сделал это, когда у меня было около 2 часов до крайнего срока и у меня не было времени учиться, оставляйте одинокое орудие чем-то вроде умного …)

Прежде чем вставить строку в функцию appendXML, запустите ее через preg_replace. Например, замените all & nbsp; символов с [some_prefix] _nbsp. Затем, на странице, где вы показываете html, сделайте это наоборот.

И Престо! знак равно

Пример кода: код, который помещает текст в фрагмент документа:

 // add text tag to p tag. // print("CCMSSelTextBody::getDOMObject: strText: ".$this->m_strText."<br>\n"); $this->m_strText = preg_replace("/&nbsp;/", "__nbsp__", $this->m_strText); $domTextFragment = $domDoc->createDocumentFragment(); $domTextFragment->appendXML(utf8_encode($this->m_strText)); $p->appendChild($domTextFragment); // $p->appendChild(new DOMText(utf8_encode($this->m_strText))); 

Код, который анализировал строку и записывал html:

 // Instantiate template. $pTemplate = new CTemplate($env, $pageID, $pUser, $strState); // Parse tag-sets. $pTemplate->parseTXTTags(); $pTemplate->parseCMSTags(); // present the html code. $html = $pTemplate->getPageHTML(); $html = preg_replace("/__nbsp__/", "&nbsp;", $html); print($html); 

Вероятно, неплохо придумать более сильную замену. (Если вы настаиваете на том, чтобы быть тщательным: сделайте md5 по времени (), а hardcode – результатом этого в качестве префикса. Так что в первом фрагменте:

 $this->m_strText = preg_replace("/&nbsp;/", "4597ee308cd90d78aa4655e76bf46ee0_nbsp", $this->m_strText); 

А во втором:

 $html = preg_replace("/4597ee308cd90d78aa4655e76bf46ee0_nbsp/", "&nbsp;", $html); 

Сделайте то же самое для любых других тегов и вещей, которые вам нужно обойти.

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

Используйте вышеуказанное на свой страх и риск.