有没有办法在XML中转义CDATA结束标记?

我想知道是否有任何方法可以在xml文档中的CDATA节中转义CDATA结束标记( ]]> )。 或者更一般地说,如果在CDATA中使用了一些转义序列(但是如果它存在的话,我想它可能只有在开始或结束标记时才有意义)。

基本上,您可以在CDATA中embedded一个开始或结束标记,并告诉parsing器不要解释它,而只是将它视为另一个字符序列。

也许你应该重构你的xml结构或者你的代码,如果你发现自己试图做到这一点,但即使我在过去3年左右一直在使用xml,而且我从来没有遇到过这个问题,我想知道这是否可能。 只是出于好奇。

编辑:

除了使用html编码…

显然,这个问题纯粹是学术问题。 幸运的是,它有一个非常确定的答案。

你不能逃避一个CDATA结束序列。 XML 规范的生成规则20非常明确:

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

编辑:这个产品规则字面意思是“一个CData部分可能包含任何你想要的,但序列']]>'没有例外。

编辑2: 同一节也读取:

在CDATA部分中,只有CDEndstring被识别为标记,所以左尖括号和&符号可能以它们的字面forms出现; 他们不需要(也不能)使用“ < ”和“ & ”来转义。 CDATA部分不能嵌套。

换句话说,不可能使用实体引用,标记或任何其他forms的解释语法。 CDATA节中唯一parsing的文本是]]> ,并终止该节。

因此,在CDATA部分内不可能转义]]>

编辑3: 同一节也读取:

2.7 CDATA部分

[定义:CDATA部分可能出现在可能出现字符数据的地方; 它们被用来转义包含字符的文本块,否则这些字符会被识别为标记。 CDATA部分以string“<![CDATA [”结尾并以string“]]>”结尾::]

那么可能会出现任何字符数据的CDATA部分,包括单个CDATA部分的多个相邻的CDATA部分。 这样就可以分割]]>令牌,并把它的两部分放在相邻的CDATA节中。

例如:

 <![CDATA[Certain tokens like ]]> can be difficult and <invalid>]]> 

应该写成

 <![CDATA[Certain tokens like ]]]]><![CDATA[> can be difficult and <valid>]]> 

你必须将你的数据分解成几部分来隐藏]]>

这是整个事情:

<![CDATA[]]]]><![CDATA[>]]>

第一个<![CDATA[]]]]>]] 。 第二个<![CDATA[>]]>具有>

你不要逃避]]>但是你通过插入]]><![CDATA[之前的> ,在C / Java / PHP / Perlstring中想到这个\ a >和a ]]

顺便说一句,

S.Lott的答案与此相同,只是措词不同而已。

S. Lott的回答是正确的:你不编码结束标签,你把它分成多个CDATA部分。

如何在现实世界中解决这个问题:使用一个XML编辑器来创build一个XML文档,这个XML文档将被input到一个内容pipe理系统中,尝试写一篇关于CDATA部分的文章。 将代码示例embeddedCDATA部分的一般技巧在这里将会失败。 你可以想像我是如何学到这一点的。

但是在大多数情况下,您不会遇到这种情况,原因如下:如果您想将XML文档的文本存储为XML元素的内容,那么您可能会使用DOM方法,例如:

 XmlElement elm = doc.CreateElement("foo"); elm.InnerText = "<[CDATA[[Is this a problem?]]>"; 

而DOM相当合理地逃避了<和>,这意味着你没有在你的文档中无意中embedded了CDATA部分。

哦,这很有趣:

 XmlDocument doc = new XmlDocument(); XmlElement elm = doc.CreateElement("doc"); doc.AppendChild(elm); string data = "<![[CDATA[This is an embedded CDATA section]]>"; XmlCDataSection cdata = doc.CreateCDataSection(data); elm.AppendChild(cdata); 

这可能是.NET DOM的ideosyncrasy,但是不会抛出exception。 这里抛出exception:

 Console.Write(doc.OuterXml); 

我猜测底下发生了什么是XmlDocument正在使用XmlWriter产生它的输出,而XmlWriter在写入时检查格式良好。

只需replace]]>]]]]><![CDATA[>

这是另一个需要逃避的情况。 假设我们需要将完全有效的HTML文档保存在XML文档的CDATA块中,并且HTML源代码恰好具有它自己的CDATA块。 例如:

 <htmlSource><![CDATA[ ... html ... <script type="text/javascript"> /* <![CDATA[ */ -- some working javascript -- /* ]]> */ </script> ... html ... ]]></htmlSource> 

评论的CDATA后缀需要被改为:

  /* ]]]]><![CDATA[> *// 

因为XMLparsing器不会知道如何处理javascript注释块

在PHP中: '<![CDATA['.implode(explode(']]>', $string), ']]]]><![CDATA[>').']]>'

一个更清洁的方式在PHP中:

  function safeCData($string) { return '<![CDATA[' . str_replace(']]>', ']]]]><![CDATA[>', $string) . ']]>'; } 

如果需要,不要忘记使用多字节安全的str_replace(非latin1 $string ):

  function mb_str_replace($search, $replace, $subject, &$count = 0) { if (!is_array($subject)) { $searches = is_array($search) ? array_values($search) : array ($search); $replacements = is_array($replace) ? array_values($replace) : array ($replace); $replacements = array_pad($replacements, count($searches), ''); foreach ($searches as $key => $search) { $parts = mb_split(preg_quote($search), $subject); $count += count($parts) - 1; $subject = implode($replacements[$key], $parts); } } else { foreach ($subject as $key => $value) { $subject[$key] = mb_str_replace($search, $replace, $value, $count); } } return $subject; } 

另一个解决scheme是replace]]>通过]]]><![CDATA[]>