广告位 · 页头(后台-模块管理-新建模块后替换此区域)

XML中的CDATA是什么?CDATA区段如何正确使用?

XML解析器的核心工作之一是识别标签和实体。当一段文本中出现小于号时,解析器会默认其后是一个元素名称的开始;出现与符号时,会尝试读取一个实体引用。这种机制保证了XML的结构化,但也给包含大量特殊符号的文本内容带来麻烦。CDATA区段就是用来告诉解析器:这一段内容请按原样处理,不要尝试解析其中的任何标记。接下来从它解决的问题、具体语法、与实体转义的差异以及常见注意事项几个方面展开。

XML中的CDATA是什么?CDATA区段如何正确使用?

一、CDATA区段解决什么问题

XML中有五类预定义实体经常被误解析,分别是小于号<、大于号>、与符号&、双引号"和单引号'。如果在上层文本节点中直接写a < b && b > c,解析器会在第一个小于号处尝试读取标签名,发现后面跟着空格时就会报错;与符号后如果不是合法实体名,同样会导致解析失败。

传统做法是使用字符实体引用逐个替换,例如把小于号写成&lt;,把与符号写成&amp;。这种方式可以解决问题,但当嵌入的内容是整段JavaScript、SQL或HTML片段时,可读性会变得很差,维护时也容易漏掉某个符号。CDATA区段提供了一种整体豁免机制,让一整块内容都不参与XML标记解析。

CDATA全称为Character Data,也就是字符数据。它并不是一种元素,而是XML规范中定义的文本区域。解析器遇到这个区域后,会跳过内部的标签识别和实体替换过程,只把内容当作纯文本处理。因此,它非常适合承载那些本身含有大量XML保留字符的内容。

<message>
  <text>a < b && b > c</text>
</message>

上面的代码在真实XML中是非法写法,因为<text>元素内部的<会被解析器当作新的标签起点。解决它要么进行完整转义,要么使用接下来的CDATA区段。

二、CDATA区段的基本语法

CDATA区段以<![CDATA[开始,以]]>结束。开始标记和结束标记之间就是被保护的内容,这些内容可以包含小于号、大于号、与符号、引号等字符,且无需转义。需要注意,标记本身不能被拆开,也不能插入空格。

<![CDATA[
这里的内容不会被 XML 解析器当作标签
]]>

下面是一个完整的消息示例,<text>元素内部包含了一段比较表达式。由于该表达式位于CDATA区段中,解析器不会把<和&&识别为XML语法。

<message>
  <text><![CDATA[
    a < b && b > c
  ]]></text>
</message>

解析上述XML后,<text>元素的内容就是字符串a < b && b > c,而不是一个带有子元素的复杂结构。CDATA区段一旦开始,内部的所有内容都按字面处理,例如写&amp;也不会被还原成&,而是保持原样输出。

CDATA区段只能出现在元素字符数据可以出现的位置,不能用在属性值中。如果把<![CDATA[放进属性值里,它只会被当作普通字符串,不会开启任何特殊解析模式。

三、CDATA与字符实体转义的区别

字符实体转义和CDATA区段都能解决特殊字符问题,但工作方式完全不同。字符实体是在字符层面做替换,例如&lt;表示一个小于号,&gt;表示一个大于号。它的优点是精确,任何位置都可以使用,包括属性值;缺点是当文本中符号密集时,替换后几乎不可读,而且容易漏掉某个字符。

CDATA区段则是整段处理,一次性告诉解析器不要解析内部内容。它更适合大段代码、脚本或格式化文本,可读性更好,维护成本更低。但它也有两个主要限制:一是内部不能出现结束标记]]>,二是不能嵌套使用,也不能用在属性值中。

属性值中的特殊字符仍然只能通过实体来表达。例如下面示例中,title属性需要表示Tom & Jerry,就必须写成Tom &amp; Jerry。

<note title="Tom & Jerry">
  <body>Tom & Jerry</body>
</note>

从实际使用角度看,短文本字段优先用字符实体,大段内容优先用CDATA。两者也可以混合使用,例如大部分内容放在CDATA区段中,少量动态部分通过实体或文本拼接完成。

对比项CDATA区段字符实体转义
可读性大段内容更直观符号多时较差
使用位置元素字符数据中文本和属性值均可
限制不能出现]]>,不能嵌套需要逐个替换

四、在真实场景中的用法

嵌入脚本是CDATA区段最典型的应用场景之一。例如在SVG或XHTML文档中,JavaScript代码经常包含小于号、与符号和大于号。如果不用CDATA,就需要把每一个运算符都转义,代码会变得非常难以维护。

<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
  <script type="text/javascript"><![CDATA[
    function isSmall(a, b) {
      return a < b;
    }
    var valid = a < b && b > c;
  ]]></script>
</svg>

配置文件中也是常见场景。许多框架使用XML保存SQL语句或正则表达式,这些内容里会出现>、<等符号。通过CDATA区段可以避免在XML配置里写出大量&gt;、&lt;,让配置文件更接近原始语句。

<query><![CDATA[
  SELECT * FROM users WHERE age > 18 AND name LIKE 'A%'
]]></query>

此外,在RSS或Atom订阅源中嵌入HTML摘要时,也经常使用CDATA。不过要明确一点:CDATA只是让解析器不把内容当作XML标签,它不负责数据内容的合法性校验。接收方是否能够正确处理这些文本,取决于后续的业务逻辑,而不是XML解析层。

五、常见误区与注意事项

第一个常见误区是认为CDATA内部可以继续书写XML元素。实际上,解析器对CDATA内部完全不做结构解析,即使写入<strong>这是文本,不是元素</strong>,它也不会成为子元素,而只是一个字符串。

<content><![CDATA[
  <strong>这是文本,不是元素</strong>
]]></content>

第二个误区是在CDATA内部使用实体引用。由于CDATA区段会关闭实体解析,写&lt;只会得到字面量&lt;,不会转换成小于号。如果内容中确实需要表达实体引用本身,恰恰适合放在CDATA中;如果希望实体被解析,则应放在普通文本节点中。

第三个注意事项是结束标记的冲突。CDATA内容里不能出现]]>,否则解析器会提前结束区段。如果真实数据中必须包含这个字符串,可以将内容拆成多个CDATA区段进行拼接。例如要表示abc]]>def,可以写成下面这样。

<text><![CDATA[abc]]]]><![CDATA[>def]]></text>

上述XML解析后,<text>元素的内容是abc]]>def。这个技巧虽然不常用,但在处理某些特殊数据格式时非常有用。理解了CDATA区段的工作原理后,就可以根据内容形态灵活选择转义策略,写出更清晰、更稳定的XML文档。

广告位 · 文章底部(后台-模块管理替换此区域)