XML DOM – CDATASection 对象(CDATA 节点)
CDATASection 是 XML DOM 中专门用来表示 <![CDATA[ ... ]]> 区块的节点类型。
它继承自 Text 节点,所以拥有 Text 节点的所有属性和方法,但有一个关键区别:内容不进行任何转义。
1. 基本信息一览
| 项目 | 值 / 说明 |
|---|
| nodeType | 4(Node.CDATA_SECTION_NODE) |
| nodeName | 始终为 "#cdata-section" |
| nodeValue / data | CDATA 区块内的原始文本(可读写) |
| textContent | 与 nodeValue 完全相同 |
| length | 字符长度(UTF-16 代码单元) |
| 继承自 | Text → CharacterData → Node |
| 创建方法 | document.createCDATASection(data) |
| 是否转义 | 完全不转义(<、>、&、”、’ 都原样输出) |
2. 为什么需要 CDATASection?
| 场景 | 不用 CDATA(会出问题) | 使用 CDATA(完美解决) |
|---|
| 存放 JavaScript 代码 | <script>if (a < b && b > c) ...</script> 解析失败 | <![CDATA[if (a < b && b > c) ...]]> 完美 |
| 存放 HTML/XML 示例代码 | <example><div>hello</div></example> 被当成真实标签 | CDATA 内原样保留 |
| 包含大量 &、<、> 的数学公式、日志等 | 必须全部写成 < > & 极难维护 | 直接写原始文本 |
| 需要在 RSS/Atom 中嵌入 HTML | 必须转义所有 < > & | 用 <![CDATA[<p>欢迎</p>]]> 简单清晰 |
3. 创建与使用示例
const xmlDoc = new DOMParser().parseFromString(
`<root></root>`, "text/xml");
// 创建 CDATA 节点
const cdata = xmlDoc.createCDATASection(`
<script type="text/javascript">
if (user.age < 18 || user.vip == false) {
alert("未成年或非VIP用户!");
}
</script>
<p>价格 & 优惠:买一送一 & 满1000减200</p>
`);
xmlDoc.documentElement.appendChild(cdata);
// 序列化查看结果
console.log(new XMLSerializer().serializeToString(xmlDoc));
输出:
<?xml version="1.0"?>
<root><![CDATA[
<script type="text/javascript">
if (user.age < 18 || user.vip == false) {
alert("未成年或非VIP用户!");
}
</script>
<p>价格 & 优惠:买一送一 & 满1000减200</p>
]]></root>
4. 与 Text 节点的完整对比
| 特性 | Text 节点 | CDATASection 节点 |
|---|
| nodeType | 3 | 4 |
| nodeName | “#text” | “#cdata-section” |
| 内容是否转义 | 是(< → <) | 否(原样输出) |
可否包含 ]]> | 可以 | 禁止!会提前结束 CDATA(XML 语法错误) |
| 继承关系 | CharacterData → Node | 继承自 Text(所以拥有 splitText 等所有方法) |
| 在 HTML 中是否支持 | 支持 | 完全不支持(HTML 会忽略或解析错误) |
| 推荐使用场景 | 普通文本内容 | 包含大量 < > & ” ‘ 或脚本代码时 |
5. 关键限制(必须记住!)
- CDATA 内不能出现字符串
]]>
<![CDATA[错误:这里有 ]]> 会被提前结束]]>
解决办法:拆分成多个 CDATA(极少遇到):
<![CDATA[这里安全]]><!-- 空注释防止合并 -->><![CDATA[继续写]]>
- HTML 文档中完全不支持 CDATA
浏览器会把 <![CDATA[ 当成注释或未知标签,直接丢弃或错误解析。
- 只能出现在 XML 文档中(包括 XHTML 当作 XML 处理时)
6. 高级操作(因为继承自 Text,所有 Text 方法都可用)
const cdata = doc.querySelector("script").firstChild; // 假设是 CDATA
// 拆分 CDATA(和 Text 完全一样)
const part1 = cdata.splitText(100); // 前100字符留在原节点
const part2 = part1.splitText(200); // 中间200字符
// 获取完整内容
console.log(cdata.wholeText); // 所有连续 Text/CDATA 合并内容
// 修改内容
cdata.data += "\n// 新增一行注释";
// 替换内容(推荐)
cdata.replaceData(0, cdata.length, "全新的脚本内容");
7. 实战应用场景总结
| 应用场景 | 推荐做法 |
|---|
| 生成 RSS/Atom feed | 正文用 <![CDATA[...]]> 包裹 HTML |
| 输出前端模板代码 | 用 CDATA 避免转义 |
| 导出包含公式的 MathML | 公式部分用 CDATA |
| 构建 SVG 中的 |