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

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

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

编辑:

除了使用 html 编码...

有帮助吗?

解决方案

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

您无法转义CDATA结束序列。 XML 规范的制定规则20非常明确:

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

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

EDIT2:同一部分也写着:

  

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

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

因此,无法在CDATA部分中逃避<=>。

EDIT3:同一部分也写着:

  

2.7 CDATA章节

     

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

结束

然后可能存在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 / Perl中的<=>字符串,但仅在<=>之前和<=>之后才需要。

BTW,

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

S。洛特的回答是正确的:您不对结束标记进行编码,而是将其分解为多个 CDATA 部分。

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

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

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

并且 DOM 相当合理地转义了 < 和 >,这意味着您没有无意中在文档中嵌入了 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 在写入时检查格式是否良好。

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

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

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

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

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

因为XML解析器不会知道如何处理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;
   }

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

见这个结构:

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top