minidom 是 Python 标准库中 xml.dom 模块的一部分,它提供了一个简单、轻量级的文档对象模型接口来解析 XML 文件,它非常易于上手,适合处理结构相对简单的 XML 文档。

什么是 minidom?
minidom 是 "Mini DOM" 的缩写,即“小型文档对象模型”,它将整个 XML 文档加载到内存中,并将其转换为一个树状结构,你可以通过遍历这个树来访问、查询和修改 XML 数据的各个部分。
核心概念:
- 文档: 整个 XML 文档的根节点,代表整个文档。
- 节点: 树中的任何一个元素,包括元素节点(如
<book>)、文本节点(如 "Python Guide")、属性节点(如id="1")等。 - 元素: 代表 XML 标签,如
<title>、<author>。 - 属性: 元素的特性,如
id、lang。 - 子节点: 一个元素节点内部的直接节点,如
<book>的子节点是<title>和<author>。 - 后代节点: 一个元素节点内部的所有节点,包括子节点的子节点。
准备工作:一个示例 XML 文件
为了演示,我们创建一个名为 books.xml 的文件。
books.xml

<?xml version="1.0" ?>
<catalog>
<book id="1">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
</book>
<book id="2">
<author>Ralls, Kim</author>
<title>Midnight Rain</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-12-16</publish_date>
</book>
<book id="3">
<author>Corets, Eva</author>
<title>Maeve Ascendant</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-11-17</publish_date>
</book>
</catalog>
解析 XML 的基本步骤
使用 minidom 解析 XML 通常遵循以下三个步骤:
- 导入模块:
from xml.dom import minidom - 解析文件:
minidom.parse()或minidom.parseString() - 操作 DOM 树:遍历节点,获取数据
核心操作详解
1 解析 XML
从文件解析
from xml.dom import minidom
# 打开并解析 XML 文件
# 使用 with 语句可以确保文件被正确关闭
with open('books.xml', 'r', encoding='utf-8') as f:
dom = minidom.parse(f)
# dom 变量就代表了整个 XML 文档的 DOM 树
从字符串解析
如果你已经有了一个 XML 格式的字符串,可以直接使用 parseString。
from xml.dom import minidom
xml_string = """
<catalog>
<book id="1">
<title>XML Developer's Guide</title>
</book>
</catalog>
"""
dom = minidom.parseString(xml_string)
2 获取根元素
解析完成后,dom.documentElement 属性指向整个文档的根元素。

root = dom.documentElement
print(f"根元素标签名: {root.tagName}") # 输出: 根元素标签名: catalog
3 遍历子节点
childNodes 属性返回一个包含所有子节点的列表,这个列表包含文本节点(如换行符和空格)和元素节点。
# 获取根元素的所有子节点
children = root.childNodes
print("\n--- 遍历根元素的所有子节点 ---")
for child in children:
# nodeType == 1 表示这是一个元素节点
if child.nodeType == child.ELEMENT_NODE:
print(f"找到元素节点: {child.tagName}")
输出:
--- 遍历根元素的所有子节点 ---
找到元素节点: book
找到元素节点: book
找到元素节点: book
注意:
minidom会保留 XML 文件中的格式(如换行和缩进),这些通常以文本节点的形式存在,在遍历时,通常需要检查nodeType是否为ELEMENT_NODE,以过滤掉这些非元素节点。
4 获取特定元素
使用 getElementsByTagName() 方法可以根据标签名获取所有匹配的元素列表。
# 获取所有 <book> 元素
book_elements = root.getElementsByTagName('book')
print(f"\n找到了 {book_elements.length} 个 <book> 元素.")
# 遍历所有 book 元素
for book in book_elements:
print(f"\n--- 处理一本书 ---")
# 获取元素的属性
book_id = book.getAttribute('id')
print(f"书籍ID: {book_id}")
# 获取子元素
# 再次使用 getElementsByTagNameelement = book.getElementsByTagName('title')[0]
author_element = book.getElementsByTagName('author')[0]
# 获取元素的文本内容
# .firstChild.data 是获取文本节点内容的常用方法= title_element.firstChild.data
author = author_element.firstChild.data
print(f"书名: {title}")
print(f"作者: {author}")
输出:
找到了 3 个 <book> 元素.
--- 处理一本书 ---
书籍ID: 1
书名: XML Developer's Guide
作者: Gambardella, Matthew
--- 处理一本书 ---
书籍ID: 2
书名: Midnight Rain
作者: Ralls, Kim
--- 处理一本书 ---
书籍ID: 3
书名: Maeve Ascendant
作者: Corets, Eva
5 获取文本内容
获取元素内部的文本内容是 minidom 中最常见也最容易出错的一步,因为元素内的文本被表示为一个文本节点。
正确的方法是:
- 获取元素节点。
- 访问它的
firstChild属性,这通常指向其内部的文本节点。 - 访问文本节点的
data属性,得到最终的字符串。
# 错误示范:直接访问 element.data 会失败element = book.getElementsByTagName('title')[0]
# print(title_element.data) # AttributeError: no attribute 'data'
# 正确示范element = book.getElementsByTagName('title')[0]text = title_element.firstChild.data
print(f"正确获取书名: {title_text}")
6 创建和修改 XML
minidom 不仅可以读取,还可以创建和修改 XML。
创建新元素和节点:
# 创建一个新的 <book> 元素
new_book = dom.createElement('book')
new_book.setAttribute('id', '4')
# 创建子元素
new_author = dom.createElement('author')= dom.createElement('title')
# 创建文本节点
author_text = dom.createTextNode('New Author')text = dom.createTextNode('New Book Title')
# 将文本节点添加到元素中
new_author.appendChild(author_text)appendChild(title_text)
# 将子元素添加到 <book> 元素中
new_book.appendChild(new_author)
new_book.appendChild(new_title)
# 将新的 <book> 元素添加到根元素中
root.appendChild(new_book)
将修改后的 DOM 树写回文件:
# toprettyxml() 方法可以将 DOM 树格式化并输出为字符串
# indent="\t" 设置缩进为制表符
new_xml_string = dom.toprettyxml(indent="\t")
# 写入新文件
with open('new_books.xml', 'w', encoding='utf-8') as f:
f.write(new_xml_string)
print("\n新的 XML 文件已生成: new_books.xml")
完整示例代码
下面是一个完整的、结合了读取、查询和写入的脚本。
from xml.dom import minidom
import os
def parse_and_modify_xml():
# 1. 解析原始 XML 文件
try:
with open('books.xml', 'r', encoding='utf-8') as f:
dom = minidom.parse(f)
except FileNotFoundError:
print("错误: books.xml 文件未找到,请确保该文件在脚本同目录下。")
return
root = dom.documentElement
# 2. 查询并打印所有书籍信息
print("--- 原始书籍信息 ---")
books = root.getElementsByTagName('book')
for book in books:
book_id = book.getAttribute('id')
title = book.getElementsByTagName('title')[0].firstChild.data
author = book.getElementsByTagName('author')[0].firstChild.data
print(f"ID: {book_id}, 书名: {title}, 作者: {author}")
# 3. 创建并添加一本新书
print("\n--- 正在添加新书 ---")
new_book = dom.createElement('book')
new_book.setAttribute('id', '4')
new_author = dom.createElement('author')
new_author.appendChild(dom.createTextNode('Pragmatic Programmer'))
new_title = dom.createElement('title')
new_title.appendChild(dom.createTextNode('The Pragmatic Programmer'))
new_book.appendChild(new_author)
new_book.appendChild(new_title)
root.appendChild(new_book)
print("新书已添加。")
# 4. 将修改后的内容保存到新文件
new_xml_content = dom.toprettyxml(indent=" ")
# toprettyxml 会添加一个空的文档声明行,我们可以手动处理一下
# 或者直接写入,通常影响不大
with open('modified_books.xml', 'w', encoding='utf-8') as f:
f.write(new_xml_content)
print("\n修改后的 XML 已保存到 modified_books.xml")
if __name__ == '__main__':
parse_and_modify_xml()
minidom 的优缺点
优点:
- Python 标准库:无需安装任何第三方库,开箱即用。
- API 简单直观:对于简单的 XML 操作,API 设计得比较容易理解。
- 支持完整的 DOM:可以随意在树中移动、添加、删除节点,非常灵活。
缺点:
- 内存消耗大:它会将整个 XML 文档加载到内存中,对于非常大的 XML 文件(几百MB或GB级别),这会导致内存不足。
- 性能较低:相比于更底层的解析器(如
lxml),minidom的解析和操作速度较慢。 - 处理空白符:
childNodes会包含大量的文本节点(换行、空格),使得遍历变得繁琐,需要额外判断nodeType。
更现代的替代方案:ElementTree
对于大多数应用场景,Python 标准库中的 xml.etree.ElementTree 是比 minidom 更好的选择,它更轻量、更快,并且内存效率更高(特别是配合 iterparse 处理大文件时)。
ElementTree 的一个简单示例:
import xml.etree.ElementTree as ET
tree = ET.parse('books.xml')
root = tree.getroot()
# 遍历所有 book 元素,语法更简洁
for book in root.findall('book'):
book_id = book.get('id')= book.find('title').text
author = book.find('author').text
print(f"ID: {book_id}, 书名: {title}, 作者: {author}")
可以看到,ElementTree 的 API 更加简洁,直接通过 .text 获取文本内容,通过 .find() 和 .findall() 查找元素,避免了 minidom 中复杂的节点类型判断。
| 特性 | minidom |
ElementTree |
|---|---|---|
| 位置 | Python 标准库 | Python 标准库 |
| 模型 | 完整 DOM | 简化的树模型 |
| 内存 | 高,加载整个文档 | 低,更高效 |
| 性能 | 较慢 | 较快 |
| 易用性 | API 繁琐,需处理节点类型 | API 简洁直观 |
| 适用场景 | 简单、小型 XML 文档,需要复杂 DOM 操作 | 推荐,绝大多数 XML 处理场景 |
建议:
- 如果只是简单地读取或写入 XML,优先使用
xml.etree.ElementTree。 - 如果你的 XML 文件非常小,或者你需要利用 DOM 模型的强大功能(如在节点间任意移动、复制等),
minidom仍然是一个可行的选择。
