使用XMLWriter将变量数据输出为CDATAXML


Output variable data as CDATA XML with XMLWriter

我正在尝试用PHP为应用程序制作一个web服务,以便与之通信,该服务将从数据库中获取数据,并将其转换为应用程序的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();
?>

提前非常感谢您提供的任何帮助!

不要使用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>

您可以将它添加到需要用CDATA包装的元素中,如下所示:

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

ThW的回答是全面周到的,也是可行的。它很好地解释了如何使用PHP中的XMLWriter接口。

当我们昨天在聊天中讨论这个问题时,他为这个差异化的答案所做的大部分工作也得到了赞扬。

XML中的CDATA有一些限制,但这也适用于为CDATA:使用XMLWriter的两种方法

字符串']]>'不能放在CDATA节中,因此不允许嵌套的CDATA节(格式良好的约束)。

来自:CDATA部分-比较2.7个CDATA部分

通常,XMLWriter接受未编码的字符串数据。例如,如果您传递一些文本,它将被正确地编码(除非使用bespoken XMLWriter::writeRaw)。

但是,如果您开始一个CDATA部分,然后直接写入文本,则传递的字符串不能结束,也不能与另一个CDATA部分重叠。这意味着,它不能包含字符序列";CCD_ 7";因为这会过早地结束CDATA部分。

因此,将有效数据传递给XMLWriter的责任仍然由这些方法的用户承担。

这样做通常很简单(单八位字节、基于US-ASCII的字符集二进制编码和UTF-8 Unicode),下面是一些示例代码:

/**
 * 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>

DOMDocumentbtw.已经在幕后做了一些非常类似的事情:

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

要从技术上理解PHP中的XMLWriter为什么会这样,您需要知道XML Writeribxml2库的。PHP中完成的大部分工作的扩展将调用传递到libxml:

PHP的xmlwriter_write_cdata委托给libxml xmlTextWriterWriteCDATA,后者执行xmlTextWriterStartCDATAxmlTextWriterWriteStringxmlTextWriterEndCDATA的可疑序列。

xmlTextWriterWriteString用于许多例程(例如写入PI),但仅在某些文本写入情况下,内容参数字符串编码:

  • 姓名
  • 文本和
  • 属性

对于所有其他人来说,它是按原样通过的。这包括CDATA,因此传递给XMLWriter::writeCData的数据必须与XMLCData的要求相匹配(因为这是用该方法编写的):

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

这在技术上是说:任何不包含";CCD_ 16";。

这很容易被忽略,我自己昨天也怀疑这可能是一个bug。我不是唯一一个,PHP.net上的一份相关错误报告是:https://bugs.php.net/bug.php?id=44619从几年前。

也可以查看What dos<![CDATA[>在XML中是什么意思?