如何使用ElementTree编辑并保留XML中的CDATA段?
编辑XML中CDATA内容并保留CDATA标记的方案
问题场景
处理包含CDATA的XML文件时,使用Python标准库xml.etree.ElementTree解析并修改CDATA内容后,输出的XML会丢失CDATA标记,导致原有的HTML格式被转义成普通文本。需要修改目标标签内的CDATA内容,同时保留CDATA格式输出。
示例输入XML片段:
<question type="multichoice"> <name> <text>decimal to binary 1</text> </name> <questiontext format="html"> <text><![CDATA[<p dir="ltr" style="text-align: left;">Convert the following number from decimal to binary:</p><p dir="ltr" style="text-align: left;">248<sub>10</sub></p>]]></text> </questiontext> <generalfeedback format="html"> <text></text> </generalfeedback> <defaultgrade>1.0000000</defaultgrade> ... </question>
解决方案
方案一:基于Python标准库实现
通过自定义序列化函数,让ElementTree在输出时保留CDATA标记:
import xml.etree.ElementTree as ET # 重写XML序列化逻辑,保留CDATA格式 def serialize_with_cdata(write, elem, encoding, qnames, namespaces): # 针对目标text标签处理CDATA if elem.tag == 'text' and elem.text and elem.text.startswith('<![CDATA[') and elem.text.endswith(']]>'): # 提取CDATA内容并按原格式输出 cdata_content = elem.text[9:-3] write(f"<{elem.tag}><![CDATA[{cdata_content}]]></{elem.tag}>".encode(encoding)) else: # 其他标签使用默认序列化逻辑 ET._serialize_xml(write, elem, encoding, qnames, namespaces) # 替换ElementTree的默认序列化方法 ET._serialize['xml'] = serialize_with_cdata # 解析输入XML tree = ET.parse('input.xml') root = tree.getroot() # 定位到questiontext下的text标签 target_text = root.find('.//questiontext/text') # 修改CDATA内容:提取内部内容,修改后重新包裹CDATA标记 original_content = target_text.text[9:-3] modified_content = original_content.replace('248<sub>10</sub>', '255<sub>10</sub>') target_text.text = f'<![CDATA[{modified_content}]]>' # 写入输出XML tree.write('output.xml', encoding='utf-8', xml_declaration=True)
方案二:使用lxml库(更简洁)
lxml原生支持CDATA节点,处理起来更直观:
from lxml import etree # 解析XML文件 tree = etree.parse('input.xml') root = tree.getroot() # 找到目标text标签 target_text = root.find('.//questiontext/text') # lxml会自动将CDATA解析为CDATA对象,直接修改内容即可 new_content = target_text.text.replace('248<sub>10</sub>', '255<sub>10</sub>') target_text.text = etree.CDATA(new_content) # 保存修改后的XML tree.write('output.xml', encoding='utf-8', xml_declaration=True)
说明
- 方案一依赖Python标准库,无需额外安装包,适合环境受限的场景;
- 方案二需要先安装lxml库(
pip install lxml),代码更简洁,处理CDATA的逻辑更原生。
内容的提问来源于stack exchange,提问作者Amit Singh
相关产品推荐
相关产品推荐

