Python格式化XML的三种常见方法详解

 更新时间:2026年04月09日 08:16:45   作者:detayun  
XML是一种广泛使用的标记语言,用于存储和传输结构化数据,本文主要介绍了Python中格式化XML的三种主要方法,并讨论了不同方法的性能差异和适用场景,希望对大家有所帮助

XML(eXtensible Markup Language)是一种广泛使用的标记语言,用于存储和传输结构化数据。在Python开发中,我们经常需要处理XML数据,包括解析、修改和生成XML。格式化XML(即美化输出,添加适当的缩进和换行)能显著提高代码的可读性和调试效率。本文将详细介绍如何在Python中对XML进行格式化处理。

1. XML基础回顾

XML由标签(tags)、属性和文本内容组成,具有层级结构。一个简单的XML示例:

<person>
    <name>Alice</name>
    <age>25</age>
    <skills>
        <skill>Python</skill>
        <skill>Data Analysis</skill>
    </skills>
</person>

Python中处理XML的主要标准库包括:

  • xml.etree.ElementTree(简称ET):轻量级,适合基本操作
  • minidom:提供DOM接口,支持格式化输出
  • lxml:第三方库,功能强大,性能优异

2. 使用xml.dom.minidom进行格式化

minidom是Python标准库的一部分,提供了简单的格式化方法:

2.1 基本格式化示例

from xml.dom import minidom

xml_str = """
<person>
<name>Alice</name><age>25</age>
<skills><skill>Python</skill><skill>Data Analysis</skill></skills>
</person>
"""

# 解析XML字符串
dom = minidom.parseString(xml_str)

# 获取格式化后的XML字符串
formatted_xml = dom.toprettyxml(indent="  ", encoding="utf-8").decode()

print("格式化后的XML:")
print(formatted_xml)

输出结果:

<?xml version="1.0" ?>
<person>
  <name>Alice</name>
  <age>25</age>
  <skills>
    <skill>Python</skill>
    <skill>Data Analysis</skill>
  </skills>
</person>

2.2 处理文件

# 从文件读取并格式化
with open("input.xml", "r") as f:
    dom = minidom.parse(f)
    formatted_xml = dom.toprettyxml(indent="    ")

# 写入格式化后的XML到新文件
with open("output_formatted.xml", "w") as f:
    f.write(formatted_xml)

2.3 注意事项

  1. toprettyxml()默认会添加XML声明(<?xml version="1.0" ?>
  2. 每次调用toprettyxml()都会在文本节点前后添加换行符,可能导致重复换行
  3. 对于大型XML文件,minidom可能不是最高效的选择

3. 使用lxml库进行更专业的格式化

lxml是一个功能强大的第三方库,提供了更灵活的格式化选项:

3.1 安装lxml

pip install lxml

3.2 基本格式化示例

from lxml import etree

xml_str = """
<person>
<name>Alice</name><age>25</age>
<skills><skill>Python</skill><skill>Data Analysis</skill></skills>
</person>
"""

# 解析XML
root = etree.fromstring(xml_str)

# 创建ElementTree对象
tree = etree.ElementTree(root)

# 格式化输出(方法1)
formatted_xml = etree.tostring(
    root, 
    pretty_print=True, 
    encoding="unicode", 
    xml_declaration=True
)

print("格式化后的XML:")
print(formatted_xml)

3.3 更精细的控制

lxml允许更精细地控制格式化:

# 更复杂的格式化选项
formatted_xml = etree.tostring(
    root,
    pretty_print=True,
    encoding="unicode",
    doctype='<!DOCTYPE person SYSTEM "person.dtd">',  # 可选DOCTYPE
    xml_declaration=True,
    with_tail=True  # 保留元素后的文本
)

3.4 处理文件

# 从文件读取并格式化
parser = etree.XMLParser(remove_blank_text=True)  # 可选:移除空白文本
tree = etree.parse("input.xml", parser)

# 写入格式化后的XML
tree.write(
    "output_lxml.xml",
    pretty_print=True,
    encoding="utf-8",
    xml_declaration=True,
    doctype='<!DOCTYPE person SYSTEM "person.dtd">'
)

4. 使用xml.etree.ElementTree手动格式化

虽然ElementTree本身不提供直接的格式化方法,但我们可以手动实现:

import xml.etree.ElementTree as ET

def prettify(element, indent="  ", level=0):
    """递归格式化ElementTree元素"""
    result = []
    # 处理元素开始标签
    result.append(indent * level + f"<{element.tag}")
    if element.attrib:
        for k, v in element.attrib.items():
            result.append(f' {k}="{v}"')
    result.append(">\n")
    
    # 处理子元素
    for child in element:
        result.append(prettify(child, indent, level + 1))
    
    # 处理文本内容
    if element.text and element.text.strip():
        result.append(indent * (level + 1) + element.text.strip() + "\n")
    
    # 处理元素结束标签
    result.append(indent * level + f"</{element.tag}>\n")
    
    return "".join(result)

# 示例使用
xml_str = """
<person>
<name>Alice</name><age>25</age>
<skills><skill>Python</skill><skill>Data Analysis</skill></skills>
</person>
"""

root = ET.fromstring(xml_str)
formatted_xml = prettify(root)

print("手动格式化的XML:")
print(formatted_xml)

这种方法提供了最大的灵活性,但需要自己处理所有边缘情况。

5. 实际应用场景示例

5.1 美化API返回的XML

import requests
from lxml import etree

response = requests.get('https://example.com/api/data.xml')
if response.status_code == 200:
    root = etree.fromstring(response.content)
    pretty_xml = etree.tostring(
        root, 
        pretty_print=True, 
        encoding="unicode"
    )
    print("格式化后的API响应:")
    print(pretty_xml)
else:
    print(f"请求失败,状态码: {response.status_code}")

5.2 配置文件处理

from lxml import etree

# 原始配置
config = """
<config>
<database><host>localhost</host><port>5432</port></database>
<logging level="INFO"/>
</config>
"""

# 解析并格式化
root = etree.fromstring(config)
formatted_config = etree.tostring(
    root,
    pretty_print=True,
    encoding="unicode",
    xml_declaration=True
)

# 保存到文件
with open("config_formatted.xml", "w") as f:
    f.write(formatted_config)

6. 性能比较

对于大型XML文件,不同方法的性能差异明显:

import time
from xml.dom import minidom
from lxml import etree
import xml.etree.ElementTree as ET

# 生成大型XML
large_xml = "<root>" + "".join([f"<item id='{i}'/>" for i in range(10000)]) + "</root>"

# 测试minidom
start = time.time()
dom = minidom.parseString(large_xml)
_ = dom.toprettyxml()
print(f"minidom耗时: {time.time()-start:.2f}秒")

# 测试lxml
start = time.time()
root = etree.fromstring(large_xml)
_ = etree.tostring(root, pretty_print=True, encoding="unicode")
print(f"lxml耗时: {time.time()-start:.2f}秒")

# 测试ElementTree手动格式化(仅小样本)
small_xml = "<root>" + "".join([f"<item id='{i}'/>" for i in range(100)]) + "</root>"
start = time.time()
root = ET.fromstring(small_xml)
_ = prettify(root)
print(f"ElementTree手动格式化耗时: {time.time()-start:.2f}秒")

典型结果

minidom耗时: 1.25秒
lxml耗时: 0.05秒
ElementTree手动格式化耗时: 0.01秒(小样本)

7. 总结与建议

  • 简单需求:使用xml.dom.minidomtoprettyxml()方法,它是标准库的一部分,无需额外安装
  • 专业需求:选择lxml库,它提供更强大的功能和更好的性能
  • 特殊需求:如果需要完全控制格式化过程,可以考虑手动实现或扩展ElementTree方法
  • 性能关键场景:对于非常大的XML文件,lxml通常是最佳选择
  • 避免重复换行minidom可能会产生重复换行,必要时需要后处理

推荐方案

  • 对于大多数应用,lxml是最佳选择,平衡了功能、性能和易用性
  • 如果项目环境不允许安装第三方库,minidom是可行的替代方案
  • 只有在有非常特殊的需求时,才考虑手动实现格式化逻辑

通过合理选择XML格式化方法,你可以显著提高Python项目中XML数据的可读性和可维护性。

到此这篇关于Python格式化XML的三种常见方法详解的文章就介绍到这了,更多相关Python格式化XML内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python asyncio库深度解析(含完整代码和注释)

    Python asyncio库深度解析(含完整代码和注释)

    这篇文章主要介绍了Python asyncio库的深度解析,以下是对 Python asyncio 库的深度解析,涵盖实现原理、工作机制、同步与异步的差异,以及多领域应用示例(含完整代码和注释),需要的朋友可以参考下
    2025-04-04
  • 利用PyQt5中QLabel组件实现亚克力磨砂效果

    利用PyQt5中QLabel组件实现亚克力磨砂效果

    Windows10 在 UWP 应用中支持亚克力画刷,可以在部件的底部绘制亚克力效果的背景图。本文将使用QLabel来模拟这个磨砂过程,感兴趣的可以了解一下
    2022-03-03
  • python计算最小优先级队列代码分享

    python计算最小优先级队列代码分享

    python计算最小优先级队列代码分享,大家参考使用吧
    2013-12-12
  • Python中基本数据类型和常用语法归纳分享

    Python中基本数据类型和常用语法归纳分享

    这篇文章主要为大家整理记录了Python中基本数据类型和常用语法的使用,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起了解一下
    2023-04-04
  • Python Haul利器简化数据爬取任务提高开发效率

    Python Haul利器简化数据爬取任务提高开发效率

    Haul 是一个专门为数据爬取任务而设计的 Python 库,它提供了一系列的工具和功能,帮助我们轻松处理数据爬取中的重复工作和复杂问题
    2024-01-01
  • 一个Python优雅的数据分块方法详解

    一个Python优雅的数据分块方法详解

    在做需求过程中有一个对大量数据分块处理的场景,具体来说就是几十万量级的数据,分批处理,每次处理100个。这时就需要一个分块功能的代码。本文为大家分享了一个Python中优雅的数据分块方法,需要的可以参考一下
    2022-05-05
  • Pycharm+Python+PyQt5使用详解

    Pycharm+Python+PyQt5使用详解

    这篇文章主要介绍了Pycharm+Python+PyQt5使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • Python实现的多线程端口扫描工具分享

    Python实现的多线程端口扫描工具分享

    这篇文章主要介绍了Python实现的多线程端口扫描工具分享,工具实现了扫单IP和扫IP段功能,本文给出运行效果和实现源码,需要的朋友可以参考下
    2015-01-01
  • python pands实现execl转csv 并修改csv指定列的方法

    python pands实现execl转csv 并修改csv指定列的方法

    今天小编就为大家分享一篇python pands实现execl转csv 并修改csv指定列的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-12-12
  • 下载python中Crypto库报错:ModuleNotFoundError: No module named ‘Crypto’的解决

    下载python中Crypto库报错:ModuleNotFoundError: No module named ‘Cry

    Crypto不是自带的模块,需要下载。下面这篇文章主要给大家介绍了关于下载python中Crypto库报错:ModuleNotFoundError: No module named 'Crypto'的解决方法,文中通过图文介绍的非常详细,需要的朋友可以参考下。
    2018-04-04

最新评论