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

如何在Python LXML迭代写入时强制XML元素嵌套缩进?

问题描述

我用LXML生成数据库导出的XML文件,因为数据量太大,直接导出etree会把32GB内存的服务器撑爆,所以改用了LXML的增量XML生成方式,现在服务器只用5GB内存就能生成XML,但迭代写入的时候没法保留etree导出时的缩进格式。

试过etree.indent()方法,只能给Client节点内部加4空格缩进;硬编码空格又会导致标签错位。想知道怎么让Client的嵌套节点比当前层级多缩进4个空格。

附错误缩进的代码:

from lxml import etree

client = etree.Element("Client")

client.append(etree.Element("ClientID"))
client[0].text = "12345"

client.append(etree.Element("ClientProfile"))
client[1].append(etree.Element("User"))

client[1][0].append(etree.Element("FirstName"))
client[1][0][0].text = "John"

client[1][0].append(etree.Element("LastName"))
client[1][0][1].text = "Doe"

client[1][0].append(etree.Element("AccountName"))
client[1][0][2].text = "Acme Inc"

client[1][0].append(etree.Element("EmailAddress"))
client[1][0][3].text = "user14@acmeinc.com"

client.append(etree.Element("SalesMetric"))
client[2].text = "12345"

filename = "test.xml"
with etree.xmlfile(filename, encoding="utf-8") as xml_file:
    with xml_file.element("DbDump"):
        xml_file.write("\n    ")

        version = etree.Element("ModelVersion")
        version.text = "1.2.1"
        xml_file.write(version, pretty_print=True)

        etree.indent(client, space="    ")

        for value in "12":
            xml_file.write(client, pretty_print=True)
解决方案

方法1:利用xmlfile.element上下文嵌套控制层级

增量写入时,xmlfile.element支持上下文管理器嵌套,能自动处理缩进层级。把Client节点的写入逻辑整合到父节点的上下文里,结合pretty_print即可实现正确缩进:

from lxml import etree

def create_client():
    # 提取Client节点创建逻辑,方便批量生成
    client = etree.Element("Client")
    
    client.append(etree.Element("ClientID"))
    client[0].text = "12345"
    
    client.append(etree.Element("ClientProfile"))
    client[1].append(etree.Element("User"))
    
    client[1][0].append(etree.Element("FirstName"))
    client[1][0][0].text = "John"
    
    client[1][0].append(etree.Element("LastName"))
    client[1][0][1].text = "Doe"
    
    client[1][0].append(etree.Element("AccountName"))
    client[1][0][2].text = "Acme Inc"
    
    client[1][0].append(etree.Element("EmailAddress"))
    client[1][0][3].text = "user14@acmeinc.com"
    
    client.append(etree.Element("SalesMetric"))
    client[2].text = "12345"
    
    return client

filename = "test.xml"
with etree.xmlfile(filename, encoding="utf-8") as xml_file:
    # 根节点开启pretty_print,自动处理子节点缩进逻辑
    with xml_file.element("DbDump", pretty_print=True):
        version = etree.Element("ModelVersion")
        version.text = "1.2.1"
        xml_file.write(version)
        
        # 批量写入Client节点,手动添加前置换行和父层级缩进
        for _ in "12":
            client = create_client()
            xml_file.write("\n    ")
            xml_file.write(client)
        # 补充根节点闭合前的换行,保证格式完整
        xml_file.write("\n")

方法2:预生成带缩进的节点字符串再写入

如果不想调整上下文结构,可以先用etree.tostring生成带内部缩进的Client节点内容,再手动添加父层级的缩进后写入:

from lxml import etree

def create_client():
    client = etree.Element("Client")
    
    client.append(etree.Element("ClientID"))
    client[0].text = "12345"
    
    client.append(etree.Element("ClientProfile"))
    client[1].append(etree.Element("User"))
    
    client[1][0].append(etree.Element("FirstName"))
    client[1][0][0].text = "John"
    
    client[1][0].append(etree.Element("LastName"))
    client[1][0][1].text = "Doe"
    
    client[1][0].append(etree.Element("AccountName"))
    client[1][0][2].text = "Acme Inc"
    
    client[1][0].append(etree.Element("EmailAddress"))
    client[1][0][3].text = "user14@acmeinc.com"
    
    client.append(etree.Element("SalesMetric"))
    client[2].text = "12345"
    
    return client

filename = "test.xml"
with etree.xmlfile(filename, encoding="utf-8") as xml_file:
    with xml_file.element("DbDump"):
        xml_file.write("\n    ")
        
        version = etree.Element("ModelVersion")
        version.text = "1.2.1"
        xml_file.write(version, pretty_print=True)
        
        for _ in "12":
            client = create_client()
            # 生成带内部缩进的Client字符串,去掉XML声明
            client_str = etree.tostring(client, encoding='utf-8', pretty_print=True, xml_declaration=False)
            # 给每一行添加父层级的4空格缩进
            indented_client = b"\n    " + client_str.replace(b"\n", b"\n    ")
            xml_file.write(indented_client)
        xml_file.write("\n")

关键说明

  • xmlfile.element的pretty_print=True仅处理当前层级下子节点的内部缩进,直接用xml_file.write()写入节点时,需要手动添加节点所在层级的前置空格和换行。
  • etree.indent()只负责节点内部子节点的缩进对齐,不会给节点本身添加外部层级的缩进,所以必须配合手动写入的前置空格来匹配父节点的层级。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 03:55:42