首页 文章

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

提问于
浏览
119

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

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

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

编辑:

除了使用html编码...

10 回答

  • 1

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

  • 5

    看到这个结构:

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

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

  • 164

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

    您无法转义CDATA结束序列 . XML specification的 生产环境 规则20非常清楚:

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

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

    EDIT2:same section还读取:

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

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

    因此,无法在CDATA部分内逃避 ]]> .

    编辑3:same section也读到:

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

    然后可能存在CDATA部分,可能出现任何字符数据,包括单个CDATA部分的多个相邻CDATA部分 . 这使得可以分割 ]]> 令牌并将其两部分放在相邻的CDATA部分中 .

    例如:

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

    应该写成

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

    你必须将你的数据分成碎片以隐藏 ]]> .

    这是整个事情:

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

    第一个 <![CDATA[]]]]>]] . 第二个 <![CDATA[>]]>> .

  • 3

    你没有逃避 ]]> ,但是在 ]] 之后通过在 > 之前插入 ]]><![CDATA[ 来逃避 > ,想想这就像C / Java / PHP / Perl字符串中的 \ ,但只需要在 > 之前和 ]] 之后 .

    顺便说一句,

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

  • 7

    S. Lott的答案是正确的:你没有对结束标记进行编码,而是在多个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在写入时检查格式良好 .

  • 1

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

  • 130

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

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

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

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

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

  • 0

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

  • 15

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

相关问题