在XML文档中,像小于号、大于号、与号这类符号如果直接出现在元素内容里,会被解析器误判为标签或实体起始,从而导致文档无法被正确读取。CDATA区块提供了一种将一段内容整体声明为纯字符数据的机制,解析器在遇到该区块时会停止解释其中的特殊字符,直到区块结束。理解它的语法与限制,是写出健壮XML配置和报文的基础。

什么是CDATA以及它的基本语法
CDATA是Character Data的缩写,在XML规范中用于指示一段文本不需要被解析器做标记处理。它的标准写法是<![CDATA[ 开头,以 ]]> 结尾,中间放置任意文本,只要文本内部不出现 ]]> 这个结束序列即可。
之所以需要这种结构,是因为XML默认的解析规则会把 < 当成标签起点,把 & 当成实体引用起点。当你要在元素里放一段JavaScript、SQL或者正则表达式时,这些文本往往充满上述符号,逐一转义既麻烦又影响可读性。CDATA让开发者可以原样粘贴代码,解析器会把它当作普通字符串交给上层程序。
<config>
<script><![CDATA[
if (a < b && b > 0) {
return true;
}
]]></script>
</config>
上面这段XML中,script 元素内部的比较和逻辑符号没有被转义,但因为包裹在CDATA里,解析器不会报错。程序读取到 script 节点的文本内容时,拿到的是完整的原始脚本,而不是被拆散的标签碎片。
CDATA适用的典型场景
最常见的使用场景是配置文件中的代码片段。例如MyBatis的映射文件允许在动态SQL里写判断逻辑,当SQL包含 < 或 > 时,用CDATA可以避免和XML标签冲突。另一个场景是WebService报文,某些字段需要传输HTML片段或JSON字符串,这些文本里的特殊字符极多,使用CDATA能降低拼装成本。
在日志或规则引擎的导出文件中,也经常看到CDATA。假设你要保存一条包含正则的过滤规则 a<b|c&d,如果不用CDATA,每个符号都要写成 <、&,维护人员很容易改错。用CDATA后,规则和代码编辑器里看到的一致,排查问题更直观。
<rule> <expression><![CDATA[ status < 200 && type = 'error' ]]></expression> </rule>
这段规则如果改成纯转义写法,会变成 status < 200 && type = 'error',可读性明显下降。因此在人机都要读写的XML里,CDATA是更友好的选择。
CDATA与实体转义方式的对比
处理特殊字符并非只有CDATA一条路。传统做法是用XML预定义实体:< 代表小于号,> 代表大于号,& 代表与号。这种方式兼容所有XML版本,且不依赖区块语法,适合短文本。
但实体转义在长文本中容易出错,尤其是嵌套多层时。CDATA的优势是零转义、原样保留,劣势是不能嵌套,且内部不能出现 ]]>。如果一段脚本里恰好包含结束序列,就需要拆分或改用转义。下面的表格列出了两者差异:
| 对比维度 | CDATA区块 | 实体转义 |
|---|---|---|
| 书写复杂度 | 低,原样粘贴 | 高,逐字符替换 |
| 可读性 | 好,接近源码 | 差,符号被替换 |
| 嵌套能力 | 不支持 | 支持 |
| 结束冲突 | 遇 ]]> 中断 | 无此问题 |
实际项目中,如果内容由程序自动生成且含大量符号,推荐CDATA;如果是手工编写的简短属性值,用实体转义更稳妥。两者也可以混用,例如外层用CDATA包裹大段SQL,SQL里极个别处需要输出 ]]> 时,再局部用转义拆开处理。
使用CDATA的注意事项与常见误区
第一个误区是认为CDATA可以写在标签属性里。XML规范只允许CDATA作为元素内容,属性值必须用引号包裹并做实体转义。例如 <input value="<![CDATA[...]]>"> 是错误写法,这里的 input() 是函数调用语境下的举例,实际属性中写CDATA字符串只会被当成普通文本,并不会生效。
第二个误区是试图嵌套CDATA。因为结束标识固定为 ]]>,内层再写同样的标识会直接让外层提前结束。如果业务必须传输包含该序列的文本,可以在生成XML时做分割,比如把内容按 ]] 和 > 拆成两段,分别用两个CDATA并通过程序拼接还原。
// Java中安全写入可能含 ]]> 的文本
String raw = "数据结束]]>标记";
String safe = raw.replace("]]>", "]]]]><![CDATA[>");
String xml = "<data><![CDATA[" + safe + "]]></data>";
上面的Java片段演示了如何把冲突序列拆开,使生成的XML既包含完整信息,又不会因为 ]]> 提前终止区块。掌握这类技巧,才能在复杂数据交换中放心使用CDATA。
总结与实践建议
CDATA是XML提供的特殊字符免解析通道,适合包裹脚本、SQL、HTML片段等富含符号的内容。它语法简单,但不能用于属性,也不能嵌套。面对短文本或必须嵌套的场景,实体转义仍是可靠补充。
建议在团队规范里明确:自动生成的报文默认用CDATA提升可读性,手工维护的配置短值用转义;同时封装一个XML写入工具函数,自动检测 ]]> 并做安全拆分。这样既能享受CDATA的便利,也能避开它的边界陷阱。