Python XML添加元素时出现多余换行问题及解决方法
XML添加元素后出现多余换行的问题分析与修复
问题重现
执行以下Python代码向XML文件添加元素后,文件中出现了多余的换行:
from xml.dom import minidom import xml.etree.ElementTree as ET def example(name, category): tree = ET.parse("example1.xml") root = tree.getroot() for i in root: if i.tag == category: ET.SubElement(i, name).text = name xmlStr = minidom.parseString(ET.tostring(root)).toprettyxml(indent=" ") with open("example1.xml", "w") as f: f.write(xmlStr) example("test", 'FRUITS')
原XML文件内容:
<?xml version="1.0" ?> <root> <FRUITS> <APPLE>apple</APPLE> <PEAR>pear</PEAR> <PLUM>plum</PLUM> </FRUITS> <VEGETABLES> <CARROT>carrot</CARROT> <POTATO>potato</POTATO> </VEGETABLES> </root>
问题成因
- 格式叠加冲突:ElementTree的
tostring()方法输出的XML已经包含基础换行结构,而minidom的toprettyxml()会再次给所有节点插入换行和缩进,两者叠加后产生多余空行。 - minidom默认行为:
toprettyxml()会自动处理所有文本节点,包括原XML中的空白文本节点,额外插入换行,导致空行数量增多。
修复方案
方案一:过滤多余空行
在写入文件前,过滤掉toprettyxml()生成的空行:
from xml.dom import minidom import xml.etree.ElementTree as ET def example(name, category): tree = ET.parse("example1.xml") root = tree.getroot() for i in root: if i.tag == category: ET.SubElement(i, name).text = name xmlStr = minidom.parseString(ET.tostring(root)).toprettyxml(indent=" ") # 过滤空行和仅含空白字符的行 xmlStr = '\n'.join(line for line in xmlStr.split('\n') if line.strip()) with open("example1.xml", "w") as f: f.write(xmlStr) example("test", 'FRUITS')
方案二:使用ElementTree自带的indent方法(Python 3.9+)
Python 3.9及以上版本的ElementTree新增了indent()方法,无需依赖minidom,直接给XML树添加规范缩进:
import xml.etree.ElementTree as ET def example(name, category): tree = ET.parse("example1.xml") root = tree.getroot() for i in root: if i.tag == category: ET.SubElement(i, name).text = name # 设置缩进为4个空格 ET.indent(root, space=" ") # 写入文件时指定编码和XML声明 tree.write("example1.xml", encoding="utf-8", xml_declaration=True) example("test", 'FRUITS')
方案三:手动处理XML输出(兼容低版本Python)
如果使用Python 3.8及以下版本,可以手动构建带缩进的XML字符串,避免依赖minidom:
import xml.etree.ElementTree as ET def indent(elem, level=0): indent_str = " " i = "\n" + level * indent_str if len(elem): if not elem.text or not elem.text.strip(): elem.text = i + indent_str if not elem.tail or not elem.tail.strip(): elem.tail = i for elem in elem: indent(elem, level+1) if not elem.tail or not elem.tail.strip(): elem.tail = i else: if level and (not elem.tail or not elem.tail.strip()): elem.tail = i def example(name, category): tree = ET.parse("example1.xml") root = tree.getroot() for i in root: if i.tag == category: ET.SubElement(i, name).text = name # 手动添加缩进 indent(root) tree.write("example1.xml", encoding="utf-8", xml_declaration=True) example("test", 'FRUITS')
内容的提问来源于stack exchange,提问作者Solomon Baker
相关产品推荐
相关产品推荐

