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('<root><body><![CDATA[<p>Hello</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/ai/2410" title="遨虾"><img
src="https://img.php.cn/upload/ai_manual/001/246/273/176421356013932.png" alt="遨虾" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/ai/2410" title="遨虾">遨虾</a>
<p>1688推出的跨境电商AI智能体</p>
</div>
<a href="/ai/2410" title="遨虾" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div>]]></body></root>')
body = doc.getElementsByTagName('body')[0]
for child in body.childNodes:
if child.nodeType == child.CDATA_SECTION_NODE:
print('CDATA content:', repr(child.data)) # 输出: '<p>Hello</p>'反序列化到对象时,CDATA内容通常不需要特殊处理
绝大多数XML-to-POJO/DTO映射框架(如Jackson XML、JAXB、xmltodict)根本不关心CDATA——它们只取最终文本值。所以只要你的字段类型是字符串,映射结果和普通文本一致。真正要注意的是:
- 如果CDATA里含非法XML字符(如未转义的
&、),而你又用了不支持CDATA的解析器,会直接抛<code>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('<div class="note">Updated & live</div>')
print(etree.tostring(root, encoding='unicode', pretty_print=True))
# 输出含标准CDATA包裹,且内部HTML不被二次转义注意:etree.CDATA()返回的是一个特殊对象,不是字符串;赋给.text后,tostring()才会渲染为。直接str(CDATA(...))会失败。
最常被忽略的一点:CDATA只影响解析器对内容的**解析行为**,不影响语义。它不提供安全性,也不改变数据类型——存进数据库或传给前端前,该转义还得转义,该校验还得校验。









