ElementTree是Python解析XML的首选,因其性能高、API简洁、内存效率好;minidom则冗余慢、不支持XPath、易空指针报错,仅适用于需严格DOM兼容的小规模场景。

直接用 xml.etree.ElementTree,别碰 minidom —— 它慢、冗余、容易空指针报错,且对配置类 XML 来说纯属杀鸡用牛刀。
为什么不用 minidom?
你查到的那些 parse + getelementsbytagname + 手动遍历 childnodes + 判 nodetype 的写法,本质是 DOM 模型的老套路。在 Python 3.9 下:
• minidom 不支持 XPath,找嵌套属性得层层 .getElementsByTagName;
• node.data 和 node.nodeValue 行为不一致,遇到空白换行就返回空字符串;
• 没有内置的 .text.strip() 这种安全取值方式,一不留神就拿到 \n \t;
• 性能比 ElementTree 低 3–5 倍(实测 10KB 配置文件,minidom 解析耗时约 8ms,ET 约 1.6ms)。
ElementTree 读取配置的最小可靠写法
假设你有如下 config.xml:
<?xml version="1.0" encoding="utf-8"?>
<config>
<database host="127.0.0.1" port="5432" user="admin">
<password>secret123</password>
</database>
<features enabled="true">
<item name="logging">on</item>
<item name="cache">off</item>
</features>
</config>对应解析代码应这样写:
立即学习“Python免费学习笔记(深入)”;
- 用
ET.parse("config.xml")加载,不是ET.fromstring()—— 后者要求传入完整字符串,不适合文件场景; - 根节点用
tree.getroot()拿,别用tree.find(".")这种绕路写法; - 取属性统一用
elem.get("attr_name", "default"),避免KeyError; - 取文本内容必须加
.text.strip(),否则可能含换行或空格; - 嵌套结构用
.find("path/to/element"),不是靠循环 +tag == "xxx"判断。
示例:
import xml.etree.ElementTree as ET
<p>tree = ET.parse("config.xml")
root = tree.getroot()</p><p>db = root.find("database")
host = db.get("host", "localhost")
port = int(db.get("port", "5432"))
pwd = db.find("password").text.strip() # ← 这里 .strip() 不可省</p><p>features = root.find("features")
logging_on = features.find("item[@name='logging']").text.strip() == "on"常见坑:find() 找不到元素就返回 None
.find() 和 .findall() 在没匹配时都返回 None 或空列表,不是抛异常。所以这些写法会崩:
-
db.find("password").text→ 如果<password>标签不存在,直接AttributeError: 'NoneType' object has no attribute 'text'; -
root.find("nonexistent").get("x")→ 同样崩; - 用
for item in root.find("features"):→.find()返回单个Element,不能直接 for,得用.findall()或先判非空。
安全做法是:先检查是否存在,再取值。例如:
pwd_elem = db.find("password")
pwd = pwd_elem.text.strip() if pwd_elem is not None else ""或者更紧凑地用 Walrus 操作符(Python 3.8+ 支持):
if (pwd_elem := db.find("password")) is not None:
pwd = pwd_elem.text.strip()
else:
pwd = ""需要改写配置时,别用 write() 默认参数
调用 tree.write("config.xml") 会丢掉 XML 声明、破坏缩进、把中文写成 Unicode 转义(如 \u4f60\u597d),且默认编码是系统 locale(Windows 上常是 cp936,Linux 是 utf-8,不统一)。
正确写法必须显式指定:
-
encoding="utf-8"—— 强制 UTF-8; -
xml_declaration=True—— 补上<?xml version="1.0" encoding="utf-8"?>; -
method="xml"(默认值,可省略); - 如果想保留原始缩进,得自己调用
ET.indent(tree)(Python 3.9+ 内置,无需额外库)。
完整保存示例:
ET.indent(tree, space=" ", level=0) # Python 3.9+ 才有
tree.write("config.xml", encoding="utf-8", xml_declaration=True)注意:ET.indent() 不会修改原始 XML 的语义,只加空白;但若原文件用了 tab 缩进,它会统一换成空格 —— 这是预期行为,不是 bug。
最易被忽略的一点:ElementTree 对恶意 XML 不安全,但配置文件一般来自可信路径,所以不用刻意换 defusedxml;可一旦配置来源不可控(比如用户上传),就得立刻切到 defusedxml.etree 并禁用外部实体。


















