XML解析器默认将CDATA视为普通文本,仅minidom和lxml可保留其节点结构;需禁用自动合并并检查nodeType,生成时应使用etree.CDATA()而非手动拼接。

XML解析器默认会把CDATA当成普通文本处理
很多XML解析库(比如Python的xml.etree.ElementTree、Java的DocumentBuilder)在读取含的节点时,不会报错,但也不会特殊标记——它只是把CDATA块里的内容原样塞进text属性,和普通文本完全一样。这意味着你无法靠节点类型或标志位区分“这是CDATA还是普通转义文本”,除非自己手动扫描原始XML字符串。
用minidom或lxml才能保留CDATA节点结构
xml.etree.ElementTree不暴露CDATA节点,而minidom和lxml可以。关键在于:必须禁用自动文本合并,并显式检查node.nodeType。
-
minidom中,CDATA节是Node.CDATA_SECTION_NODE类型,其data属性即原始内容 -
lxml中需用parser = etree.XMLParser(strip_cdata=False),否则默认丢弃CDATA包装、只留内容 - 若用
lxml.objectify,它根本无视CDATA——直接映射成字符串,别指望结构保留
from xml.dom import minidom
doc = minidom.parseString('Hello]]> ')
body = doc.getElementsByTagName('body')[0]
for child in body.childNodes:
if child.nodeType == child.CDATA_SECTION_NODE:
print('CDATA content:', repr(child.data)) # 输出: 'Hello
'反序列化到对象时,CDATA内容通常不需要特殊处理
绝大多数XML-to-POJO/DTO映射框架(如Jackson XML、JAXB、xmltodict)根本不关心CDATA——它们只取最终文本值。所以只要你的字段类型是字符串,映射结果和普通文本一致。真正要注意的是:
- 如果CDATA里含非法XML字符(如未转义的
&、),而你又用了不支持CDATA的解析器,会直接抛XMLSyntaxError - 若业务逻辑依赖“此处本应是HTML片段”,得靠约定字段名(如
htmlContent)或额外元数据,不能靠XML结构推断 - 生成XML时,不要手动拼接
——用库的API(如lxml.etree.CDATA(...))确保合法嵌套
用lxml.etree.CDATA安全生成含HTML的XML字段
手动拼字符串写CDATA极易出错:标签没闭合、嵌套CDATA非法、编码混乱。正确做法是让库处理。
from lxml import etree
root = etree.Element('item')
desc = etree.SubElement(root, 'description')
desc.text = etree.CDATA('Updated & live')
print(etree.tostring(root, encoding='unicode', pretty_print=True))
# 输出含标准CDATA包裹,且内部HTML不被二次转义注意:etree.CDATA()返回的是一个特殊对象,不是字符串;赋给.text后,tostring()才会渲染为。直接str(CDATA(...))会失败。
最常被忽略的一点:CDATA只影响解析器对内容的**解析行为**,不影响语义。它不提供安全性,也不改变数据类型——存进数据库或传给前端前,该转义还得转义,该校验还得校验。










