minidom.writexml() 在标签间插入空行是因为DOM将原始XML中的换行和缩进解析为Text节点,writexml()原样输出这些空白节点;解决方法是递归删除纯空白Text节点或改用xml.etree.ElementTree。

minidom.writexml() 为什么总在标签间塞空行
因为 writexml() 默认把文本节点(哪怕只是换行符和缩进)当普通内容处理,遇到 Text 或 Whitespace 节点就原样输出。而 DOM 解析 XML 时,原始文件里的换行和缩进会被读成独立的 Text 节点——这些节点在你没动过文档结构时,恰好夹在元素之间,writexml() 一视同仁地写出来,就成了肉眼可见的“空行”。
这不是 bug,是 DOM 规范对“空白即内容”的忠实实现。但多数人导出 XML 只想要结构清晰、无冗余换行的紧凑格式,这时候就得干预节点树本身。
手动清理 text 节点:删掉所有纯空白子节点
最直接的办法是在调用 writexml() 前,递归遍历整棵树,把父元素下所有只含空白字符(' '、'\n'、'\t'、'\r')的 Text 子节点干掉。
- 必须检查
node.nodeType == node.TEXT_NODE,再判断node.data.strip() == '' - 删除时要用
parent.removeChild(node),不能只设node.data = ''——后者仍会触发writexml()输出空字符串 - 遍历时要倒序删(从最后一个子节点往前),否则删完一个,后续索引会偏移,漏删或报
IndexError
示例片段:
立即学习“Python免费学习笔记(深入)”;
def remove_blank_text_nodes(node):
if node.nodeType == node.ELEMENT_NODE:
# 倒序遍历子节点
for child in reversed(node.childNodes):
if child.nodeType == child.TEXT_NODE and not child.data.strip():
node.removeChild(child)
else:
remove_blank_text_nodes(child)
用 toprettyxml() 替代 writexml()?小心编码和换行陷阱
toprettyxml() 看似能自动缩进,但它默认用 '\n' 换行、不支持指定编码、且会在每个元素前后都加换行——反而更容易产生“空行”,尤其当原始节点已有空白时,问题更明显。
- 它不能跳过已有空白节点,只是在它们基础上再加缩进
- 输出字符串开头带
'<?xml ...?>'声明,若你已手动写过声明,会重复 - 若需 UTF-8 输出,必须用
.encode('utf-8')再解码,否则可能抛UnicodeEncodeError
所以除非你完全控制输入 DOM(比如全由代码新建,没解析过外部文件),否则 toprettyxml() 不解决根本问题,还可能让空行更多。
真正可控的方案:用 xml.etree.ElementTree + tostring()
如果项目允许换库,xml.etree.ElementTree 是比 minidom 更轻、更符合直觉的选择。它的 tostring() 默认不保留无关空白,且可通过 method='xml' 和 encoding 精确控制输出。
- 新建树时不会把源文件空白当节点,天然规避问题
- 需要缩进可用第三方
xml.dom.minidom.parseString(...).toprettyxml()套一层,但仅限最终输出;中间操作仍用 ET - 若必须兼容 minidom 接口,可用
ElementTree.fromstring(minidom.toxml())转换一次,丢弃所有原始空白
关键点:minidom 的“空行”本质是它对 XML 信息模型的严格映射,不是格式化开关没开对。想彻底干净,就得接受要么动手删节点,要么换更面向用途的工具链。










