生成XML文档时CDATA段中含有]]>怎么办?

这是个有意思的问题,包含在CDATA标签<![CDATA[ ... ]]>之间的内容会被XML解析器忽略,这样就不需要对内容中出现的 <>&等字符进行转义(&lt;&gt;&amp;)。

但是内容中一旦出现]]>,就会导致XML解析失败,因为CDATA不允许嵌套。
解决的办法不止一个,我采用把 ]]>拆开放入两个CDATA中的简单办法,下面是PHP的实现:

function XmlCDATAStr($s)
{
  $a = explode(']]>',$s);
  return XmlSafeStr(implode(']]]]><![CDATA[>',$a));
}

上面用到了前文提到的XmlSafeStr()函数来过滤非法的XML字符。

有更好的办法请一定告诉我 :)

15 条评论 »

  1. suozixie said,

    2007/1/11 @ 17:54

    博客部落解决了谢谢
    $strTitle = str_replace(']]>', ']]>', $strTitle);

  2. Nukq said,

    2007/1/11 @ 18:00

    嗯?你的代码是不是贴错了? :P

  3. suozixie said,

    2007/1/11 @ 20:14

    如果]]>是用来显示的话,可以这样做
    $strTitle = str_replace(']]>', ']]&gt;', $strTitle);

    本来打开http://www.blogblo.com/blogblo.php?id=26会报错,原因是你blog的rss中的文章标题中的“>”没有被转义(一般的rss的文章标题和内容是htmlentities过的,不会出现]]>),所以抓取的时候就导致CDATA中的出现了]]>, 现在我加了$strTitle = str_replace(']]>', ']]&>;', $strTitle);,问题就解决了。
    抓你这篇文章时候暴露了blogblo的一个潜在bug,要说一声谢谢。

    不过在你blog上发回复好麻饭啊为了显示]]&gt;要输入]]&amp;gt;

    我想应该把回复htmlentities转义一下吧~_~,我不知道回复可不可一插入js,否者...

  4. Nukq said,

    2007/1/11 @ 20:25

    如果对CDATA内的内容再做转义,那就不符合CDATA的本意了,所以我拆开放入两个CDATA中。

    wordpress的内部字符处理很乱,看不明白 呵呵,
    所以帖代码上来往往显示的面目全非 :(

    昨天在blogblo添加了这个种子,结果加载了半天没反应,原来是这个bug 啊

  5. suozixie said,

    2007/1/11 @ 20:42

    在CDATA里的字符是不用,我刚意识到我说错了
    但是如果CDATA中是html code 而且 ]]>是用来显示而不是之类的标签,是不是应该转为]]&gt;的吧(html tag中应该不会用到的吧,我想是一般用来显示的)
    但是你的title没用CDATA也没转义,且恰好又是关于]]>的,太巧了和,所以blogblo的xajax出错了。

    用你方法改进xajax那应该是最根本的解决办法了,说到底是毕竟是xajax

  6. Nukq said,

    2007/1/11 @ 20:47

    嗯,作为html显示的时候肯定要转义的

    另外: 我看了我的rss输出。其中 titile虽没有包含在CDATA中, 但是已经转义了啊。

    <title>生成XML文档时CDATA段中含有]]&gt;怎么办?</title>

  7. Nukq said,

    2007/1/11 @ 20:52

    我想:不管是转义还是 原样放入CDATA中,你用xml库得到后的数据都是未转义的。

    所以显示的时候还是要htmlentities处理的。

  8. Anonymous said,

    2007/1/11 @ 20:53

    用你方法(很通用)改进xajax那应该是最根本的解决办法了,说到底是毕竟是xajax bug。

    你们做的东东很精致
    很想和你交个朋友,我的QQ:95210236。有机会能见个面最好了

  9. suozixie said,

    2007/1/11 @ 20:57

    htmlentities处理后文章中的图片和段落就没了连也没了。
    现在的做法是 $strDescription = strip_tags($strDescription, "");

  10. Nukq said,

    2007/1/11 @ 21:05

    对标题用 htmlspecialchars()处理就够了

    对文章内容,因为是html格式,所以可以直接输出,但是这样有隐含的安全问题,建议对内容进行必要的修正和过滤,比较理想的是使用Tidy模块来处理

    看我的文章:
    PHP+Tidy-完美的XHTML纠错+过滤
    http://nukq.malmam.com/?p=14

  11. Nukq said,

    2007/1/11 @ 21:11

    加你QQ了 :P

  12. suozixie said,

    2007/1/11 @ 22:33

    如果标题带引号什么的一般blog rss都已经进行了htmlentities了(sohu sina 等),我再加就两次htmlentities了,显示不正确了。你这个除外~_~

  13. Nukq said,

    2007/1/11 @ 22:40

    输出XML的时候:如果没有CDATA,那么需要转义;如果有CDATA,那么不需要转义。

    按照这个原则,那么你解析XML得到的标题数据肯定是 原始数据(未转义的)

    如果不是,那么要么XML解析库有问题,要么对方输出的时候胡乱转义。

    因此输出的做一次htmlspecialchars(),也就只做了一次而已。
    如果页面显示的时候出现&xxx啥的,肯定是对方输出不标准导致的。

  14. suozixie said,

    2007/1/11 @ 23:51

    如果不是,那么要么XML解析库有问题,要么对方输出的时候胡乱转义。
    ~~~~~~~~~~~~~~~~~~~~~~
    问题就出在这,很多大的网站的rss的文章title
    同时用了CDATA和&转义,而你的只用了&转义。
    有点不好办~_~!

  15. Nukq said,

    2007/1/11 @ 23:54

    汗~ 不按照标准,

    那就无语了 -.-

RSS feed for comments on this post · TrackBack URI

发表看法

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word