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

时间:2008-10-21 21:54:59

标签: xml escaping cdata

我想知道是否有办法在xml文档的CDATA部分中转义CDATA结束标记(]]>)。或者,更一般地说,如果在CDATA中使用某些转义序列(但如果它存在,我想它可能只有在逃避开始或结束令牌时才有意义)。

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

如果你发现自己试图这样做,你应该重构你的xml结构或你的代码,但即使我在过去3年左右的时间里每天都在使用xml而且我从未有过这个问题,我想知道是否有可能。只是出于好奇。

编辑:

除了使用html编码...

11 个答案:

答案 0 :(得分:166)

您必须将数据分成几部分才能隐藏]]>

以下是整个事情:

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

第一个<![CDATA[]]]]>]]。第二个<![CDATA[>]]>包含>

答案 1 :(得分:133)

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

您无法转义CDATA结束序列。 XML specification的生产规则20非常明确:

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

编辑:此产品规则的字面意思是“CData部分可能包含您想要的任何内容但序列']]&gt;'。没有例外。”。

EDIT2:same section也读取:

  

在CDATA部分中,只有CDEnd字符串被识别为标记,因此左尖括号和&符号可能以其字面形式出现;他们不需要(也不能)使用“&lt;”和“&amp;”进行转义。 CDATA部分无法嵌套。

换句话说,不可能使用实体引用,标记或任何其他形式的解释语法。 CDATA部分中唯一解析的文本是]]>,它会终止该部分。

因此,无法在CDATA部分中转义]]>

EDIT3:same section也读取:

  

2.7 CDATA章节

     

[定义:CDATA部分可能出现在任何可能出现字符数据的地方;它们用于转义包含字符的文本块,否则这些字符将被识别为标记。 CDATA部分以字符串“&lt;![CDATA [”开头,以字符串“]]&gt;”:]结束

然后可能存在CDATA部分,可能出现任何字符数据,包括单个CDATA部分的多个相邻CDATA部分。这样就可以分割]]>标记,并将它的两部分放在相邻的CDATA部分中。

例如:

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

应该写成

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

答案 2 :(得分:15)

你没有逃脱]]>,但是在>之后]]移出]]><![CDATA[>之前插入\,就像>一样{1}}在C / Java / PHP / Perl字符串中,但仅在]]之前和{{1}}之后需要。

BTW,

S.Lott的回答与此相同,措辞不同。

答案 3 :(得分:7)

S上。 Lott的答案是正确的:你没有对结束标记进行编码,而是将其分成多个CDATA部分。

如何在现实世界中遇到这个问题:使用XML编辑器创建一个将被送入内容管理系统的XML文档,尝试写一篇关于CDATA部分的文章。你在CDATA部分嵌入代码示例的普通技巧将在这里失败。你可以想象我是如何学到这一点的。

但是在大​​多数情况下,你不会遇到这个,这就是原因:如果你想存储(比方说)XML文档的文本作为XML元素的内容,你可能会使用DOM方法,例如:

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

并且DOM非常合理地逃脱了&lt;和&gt ;,这意味着你没有无意中在文档中嵌入了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的一种特殊情况,但这不会引发异常。抛出异常:

Console.Write(doc.OuterXml);

我猜在幕后发生的事情是XmlDocument正在使用XmlWriter产生其输出,并且XmlWriter在写入时检查格式良好。

答案 4 :(得分:5)

只需将]]>替换为]]]]><![CDATA[>

即可

答案 5 :(得分:3)

这是另一个需要转义]]>的案例。假设我们需要在XML文档的CDATA块中保存一个完全有效的HTML文档,并且HTML源恰好拥有它自己的CDATA块。例如:

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

注释的CDATA后缀需要更改为:

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

因为XML解析器不知道如何处理javascript注释块

答案 6 :(得分:1)

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

答案 7 :(得分:1)

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;
   }

答案 8 :(得分:0)

另一种解决方案是将]]>替换为]]]><![CDATA[]>

答案 9 :(得分:0)

见这个结构:

<![CDATA[
   <![CDATA[
      <div>Hello World</div>
   ]]]]><![CDATA[>
]]>

对于内部CDATA标记,您必须使用]]]]><![CDATA[>而非]]>关闭。就这么简单。

答案 10 :(得分:-1)

我不认为中断CDATA是个好方法。这是我的选择...

]用于转义序列,后跟字符的十六进制值。就像在&#xhhhh; => ]<unicode value>;

中一样

这样,如果您尝试记录]]>,则编码fn将产生]005D;]005D;]003E;,这在CDATA中是可以的。

这比按实体名称进行转义更好,因为它们不会在您的应用程序中每次都解码,并且您可能对使用&符号转义实体与对某些其他字符/序列转义可能具有不同的优先级。因此,您可以更好地控制CDATA的内容。