You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python修改XML中CDATA标签内容后保留CDATA格式的方法

问题描述

我在Python和XML使用方面经验不足,尝试用Python解析XML文件,修改CDATA标签内的名称并生成新XML文件。使用从Stack Overflow获取的代码可完成修改并生成新文件,但新文件丢失了<![CDATA[]]>格式。请问如何让Python写入新XML时保留该格式?

原XML文件:

<Programs Use="Context">
    <Program Use="Target" Name="MainProgram" TestEdits="false" MainRoutineName="MainRoutine"        Disabled="false" UseAsFolder="false">
        <Tags/>
            <Routines>
                <Routine Name="MainRoutine" Type="RLL">
                    <RLLContent>
                        <Rung Number="0" Type="N">
                            <Text>
                                <![CDATA[XIC(AutoSlateAutoRun);]]>
                            </Text>
                        </Rung>
                    </RLLContent>
                </Routine>
            </Routines>
    </Program>
</Programs>

使用的Python代码:

def create_l5x_import_file():
    with open('ProgramExport.L5X', encoding='UTF-8-SIG') as f:
        tree = ET.parse(f)
        root = tree.getroot() 
    
for elem in root.iter():   
    
    try:
        elem.text = elem.text.replace("(AutoSlateAutoRun)", "(THIS_IS_NEW)")
    except AttributeError:
        pass
      
tree.write('ProgramOutput.L5X', xml_declaration=True, method='xml', encoding='UTF-8-SIG')

解决方案

Python标准库的xml.etree.ElementTree默认会把CDATA内容视为普通文本,写入XML时不会保留<![CDATA[]]>标记。要解决这个问题,需要手动将修改后的内容重新包裹为CDATA节点,以下是两种可行方法:

方法一:使用Python 3.8+自带的CDATA类

Python 3.8及以上版本的ElementTree提供了原生CDATA类,可直接创建CDATA节点,代码修改如下:

import xml.etree.ElementTree as ET

def create_l5x_import_file():
    with open('ProgramExport.L5X', encoding='UTF-8-SIG') as f:
        tree = ET.parse(f)
        root = tree.getroot() 
    
    # 遍历所有Text节点,处理CDATA内容
    for elem in root.iter('Text'):   
        if elem.text is not None:
            # 替换目标文本
            new_content = elem.text.replace("(AutoSlateAutoRun)", "(THIS_IS_NEW)")
            # 清空原有内容,添加CDATA节点
            elem.clear()
            elem.append(ET.CDATA(new_content))
      
    tree.write('ProgramOutput.L5X', xml_declaration=True, method='xml', encoding='UTF-8-SIG')

create_l5x_import_file()

方法二:自定义序列化逻辑(兼容Python低版本)

如果你的Python版本低于3.8,可以通过重写ElementTree的序列化方法来支持CDATA:

import xml.etree.ElementTree as ET

# 重写XML序列化方法,识别并输出CDATA节点
def _serialize_xml(write, elem, encoding, qnames, namespaces):
    if elem.tag is ET.CDATA:
        write(f"<![CDATA[{elem.text}]]>".encode(encoding))
        return
    return ET._serialize_xml(write, elem, encoding, qnames, namespaces)

ET._serialize_xml = _serialize_xml
ET._serialize['xml'] = _serialize_xml

def create_l5x_import_file():
    with open('ProgramExport.L5X', encoding='UTF-8-SIG') as f:
        tree = ET.parse(f)
        root = tree.getroot() 
    
    for elem in root.iter('Text'):   
        if elem.text is not None:
            new_content = elem.text.replace("(AutoSlateAutoRun)", "(THIS_IS_NEW)")
            elem.clear()
            # 创建自定义CDATA节点
            cdata_node = ET.Element(ET.CDATA)
            cdata_node.text = new_content
            elem.append(cdata_node)
      
    tree.write('ProgramOutput.L5X', xml_declaration=True, method='xml', encoding='UTF-8-SIG')

create_l5x_import_file()

关键说明

  1. 原代码的核心问题:直接修改elem.text会丢失CDATA标记,因为ElementTree将CDATA内容等同于普通文本。
  2. 两种方法的核心逻辑一致:先替换文本内容,再将内容包裹为CDATA节点替换原文本节点。
  3. 修正了原代码的缩进错误:原代码中for循环和写入操作在函数外部,会导致root未定义的问题,需将其放入函数内部。

内容的提问来源于stack exchange,提问作者TumRums1989

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 10:05:17