Вывод переменных данных в виде CDATA XML с XMLWriter

Я пытаюсь создать веб-сервис на PHP для приложения, с которым он будет взаимодействовать, который получит данные из базы данных и переведет их в формат XML для приложения. Один из столбцов, однако, содержит HTML и должен быть выведен (я думаю) как CDATA. У меня проблемы с выполнением этого, хотя пожалуйста, порекомендуйте

<?php
mysql_connect(DB_HOST, DB_USER, DB_PASSWORD);
mysql_select_db(DB_NAME);

$sql = "SELECT post_date_gmt, post_content, post_title FROM [schema].wp_posts WHERE post_status = \"publish\" && post_type = \"post\" ORDER BY post_date_gmt DESC;";
$res = mysql_query($sql);

$xml = new XMLWriter();

$xml->openURI("php://output");
$xml->startDocument();
$xml->setIndent(true);

$xml->startElement('BlogPosts');

while ($row = mysql_fetch_assoc($res)) {

$xml->startElement("Post");

$xml->startElement("PostDate");
$xml->writeRaw($row['post_date_gmt']);
$xml->endElement();

$xml->startElement("PostTitle");
$xml->$writeRaw($row['post_title']);
$xml->endElement();

$xml->startCData("PostContent");
$xml->writeCData($row['post_content']);
$xml->endCData();

$xml->endElement();

}

$xml->endElement();

header('Content-type: text/xml');
$xml->flush();

?>

Заранее большое спасибо за любую помощь, которую вы можете предложить!

3

Решение

Не использовать XMLWriter::writeRaw()За исключением случаев, когда вы действительно хотите писать XML-фрагменты напрямую. «Сырой» означает, что здесь не будет выхода из библиотеки.

Правильный способ записи текста в документ XML XMLWriter::text(),

$xml->startElement('PostTitle');
$xml->text('foo & bar');
$xml->endElement();

Выход:

<?xml version="1.0"?>
<PostTitle>foo &amp; bar</PostTitle>

Если вы используете XMLWriter::writeRaw() в этом примере результат будет содержать неэкранированный & и быть недействительным XML.

Разделы CDATA являются символьными узлами, не похожими на текстовые узлы, но допускают использование специальных символов без экранирования и оставляют пробелы. Вы всегда должны создавать узел элемента отдельно. Узел элемента может содержать несколько других узлов, даже несколько разделов CDATA.

XmlReader имеет два способа создания разделов CDATA:

Единственный метод:

$xml->startElement("PostContent");
$xml->writeCData('<b>post</b> content');
$xml->endElement();

Выход:

<?xml version="1.0"?>
<PostContent><![CDATA[<b>post</b> content]]></PostContent>

Или методы начала / окончания:

$xml->startElement("PostContent");
$xml->startCData();
$xml->text('<b>post</b> content');
$xml->text(' more content');
$xml->endCData();
$xml->endElement();

Выход:

<?xml version="1.0"?>
<PostContent><![CDATA[<b>post</b> content more content]]></PostContent>
5

Другие решения

Вы можете просто добавить его к нужным элементам, завернутым в CDATA, вот так:

 $xml->writeRaw('<![CDATA['.$row['post_date_gmt'].']]>');
0

ответ от ThW в целом вдумчивый и путь. Это хорошо объясняет, как интерфейс XMLWriter в PHP предназначен для использования.

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

Есть некоторые ограничения с CDATA в XML, однако, это также относится к намеченным двум способам использования XMLWriter для CDATA:

Строка ‘]]>’ не может быть помещена в секцию CDATA, поэтому вложенные секции CDATA недопустимы (ограничение правильности формы).

От: Раздел CDATA — сравнить 2.7 Разделы CDATA

Обычно XMLWriter принимает строковые данные, которые не закодированы для использования. Например. если вы передадите какой-нибудь текст, он будет написан в правильном кодировании (если XMLWriter::writeRaw).

Но если вы начнете раздел CDATA, а затем напишите текст или же вы пишете CDATA напрямую, передаваемая строка не должна заканчиваться или содержать другой раздел CDATA. Это означает, что он не может содержать последовательность символов]]>msgstr «так как это преждевременно завершит раздел CDATA.

Таким образом, ответственность за передачу действительных данных в XMLWriter остается за пользователем этих методов.

Обычно это тривиально (одиночные октеты, двоичные кодировки набора символов на основе US-ASCII и Unicode UTF-8), вот пример кода:

/**
* prepare text for CDATA section to prevent invalid or nested CDATA
*
* @param $string
*
* @return string
* @link http://www.w3.org/TR/REC-xml/#sec-cdata-sect
*/
function xmlwriter_prepare_cdata_text($string) {
return str_replace(']]>', ']]]]><![CDATA[>', (string) $string);
}

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

$xml = new XMLWriter();
$xml->openURI("php://output");
$xml->startDocument();

$xml->startElement("PostContent");
$xml->writeCDATA(xmlwriter_prepare_cdata_text('<![CDATA[Foo & Bar]]>'));
$xml->endElement();

$xml->endElement();

Примерный вывод:

<?xml version="1.0"?>
<PostContent><![CDATA[<![CDATA[Foo & Bar]]]]><![CDATA[>]]></PostContent>

DOMDocument Кстати. делает что-то очень похожее под капотом уже:

$dom = new DOMDocument();
$dom->appendChild(
$dom->createElement('PostContent')
);
$dom->documentElement->appendChild(
$dom->createCdataSection('<![CDATA[Foo & Bar]]>')
);
$dom->save("php://output");

Выход:

<?xml version="1.0"?>
<PostContent><![CDATA[<![CDATA[Foo & Bar]]]]><![CDATA[>]]></PostContent>

Технически понять почему XMLWriter в PHP ведет себя так, вы должны знать, что XMLWriter основан на библиотека libxml2. Расширение в PHP для большей части проделанной работы передает вызовы libxml:

РНР xmlwriter_write_cdata делегаты в libxml xmlTextWriterWriteCDATA который делает подозреваемая последовательность из xmlTextWriterStartCDATA, xmlTextWriterWriteString а также xmlTextWriterEndCDATA,

xmlTextWriterWriteString используется во многих подпрограммах (например, написание PI), но только для некоторых случаев написания текста строка параметра содержимого является кодируются:

  • Название,
  • Текст и
  • Атрибут.

Для всех остальных это передается как есть. Это включает в себя CDATA, поэтому данные передаются XMLWriter::writeCData должен соответствовать требованиям для XML CData (потому что это написано этим методом):

  • [20] CData ::= (Char* - (Char* ']]>' Char*))

Что технически говорит: любая строка не содержит]]>».

Это может быть легко упущено, я сам подозревал, что это могло быть ошибкой вчера. И я не единственный, связанный отчет об ошибках на PHP.net: https://bugs.php.net/bug.php?id=44619 с лет назад.

Смотри также Что значит <! [CDATA []]> в XML значит?

0