应使用lxml库并显式声明目标元素为CDATA类型,因其能可靠获取未转义原始内容;标准ElementTree忽略CDATA结构,正则仅适用于简单稳定场景,minidom和BeautifulSoup均无法满足原始内容提取需求。

Python解析XML时CDATA内容被忽略或转义了怎么办
标准xml.etree.ElementTree默认把CDATA当作普通文本处理,不会保留结构,更不会阻止实体转义(比如变成)。这不是bug,是设计使然——它只关心XML信息集,不保留标记语法细节。真要提取原始CDATA内容,得换思路。
用lxml配合parser.set_cdata_section_elements()
lxml是唯一在主流XML库中支持显式CDATA感知的方案。关键不是“读取CDATA标签”,而是告诉解析器:哪些元素的内容应被当作CDATA处理(即跳过实体解码、保留原始字符)。
- 必须提前知道哪些元素可能含CDATA(比如
description、script),无法全自动识别 - 需使用
lxml.etree.XMLParser,而非etree.parse()默认解析器 - 设置后,这些元素的
.text属性会返回未转义的原始字符串
from lxml import etreeparser = etree.XMLParser()
告诉解析器:所有
和 元素的内容按CDATA处理parser.set_cdata_section_elements(['content', 'code'])
立即学习“Python免费学习笔记(深入)”;
xml_str = '''
]]>''' root = etree.fromstring(xml_str, parser)Hello & world print(root.find('content').text) # 输出:
Hello & world
(未转义,原样保留)
ElementTree里手动提取CDATA字符串(不推荐但有时可行)
如果只能用标准库,且XML格式固定、CDATA位置明确,可退而求其次:用正则从原始XML字符串中提取内容。这绕过了XML解析,风险高,但对简单场景够用。
- 仅适用于XML结构稳定、无嵌套CDATA、且你控制输入源的情况
- 正则
r''会捕获最内层内容,注意re.DOTALL标志 - 无法处理CDATA跨行、或内容含
]]>的情况(XML本身禁止这样写,但坏数据可能有)
import rexml_raw = '''
- ''' match = re.search(r'', xml_raw, re.DOTALL) if match: cdata_content = match.group(1) # 'Line1
Line2]]>
Line2'
为什么不用minidom或BeautifulSoup
xml.dom.minidom虽能访问CDATASection节点,但其.data属性仍会做基础转义(如&→&),且API笨重;BeautifulSoup根本不是XML解析器,对CDATA无特殊处理,会直接丢弃标签或当普通文本。两者都不解决“获取未转义原始内容”这个核心诉求。
真正要可靠处理CDATA,lxml + 显式声明目标元素是目前最轻量也最可控的方式。别指望自动发现CDATA——XML标准本身不要求解析器暴露这种语法细节,所有方案都依赖你提前知道哪些字段该被当CDATA对待。










