Python ElementTree遍历CSV写入XML 所有输出均为第一行数据问题
问题说明
实现目标:读取csv文件数据,写入xml模板后,以「output+记录编号」为文件名导出结果文件。
当前异常表现:
- 代码可正常生成所有命名规则正确的文件,调试确认for循环可正常遍历全部csv数据,计数器最终输出为15(对应csv共15行数据),遍历逻辑无异常
- 使用ElementTree库完成xml模板修改、文件保存操作,但所有生成的输出文件内填充的均为csv第一行的记录数据
原问题代码:
from xml.etree import ElementTree as ET def Task(): """ This Function uses an XML template and replaces certain variables (parameters) with data in a csv file :)""" CSV_File = open('records1.csv', 'r', encoding = 'UTF-8') tree = ET.parse('Template1.xml') root = tree.getroot() count = 0 for line in CSV_File: x = line.split(',') count +=1 print(x) for node in root.getiterator(): if node.attrib.get('val') == 'X1': node.attrib['val'] = x[0] if node.attrib.get('val') == 'X2': node.attrib['val'] = x[1] if node.attrib.get('val') == 'X3': node.attrib['val'] = x[2] if node.attrib.get('val') == 'X4': node.attrib['val'] = x[3] if node.attrib.get('val') == 'X5': node.attrib['val'] = x[4] if node.attrib.get('val') == 'X6': node.attrib['val'] = x[5] if node.attrib.get('val') == 'X7': node.attrib['val'] = x[6] XML_File= open('output'+str(count)+'.xml', 'wb') tree.write(XML_File) XML_File.close()
错误原因
一共3个核心问题导致异常:
- xml模板只在循环外加载了1次:第一次循环处理csv第一行数据时,就把所有
val为X1`X7`的占位符替换成了第一行的实际值,后续循环遍历节点时,已经找不到值为X1X7的属性,替换逻辑完全不触发,内存里的xml对象始终存的是第一行替换后的内容。 - 缩进逻辑完全错误:打开xml输出文件的代码被放在了遍历xml节点的内层循环里,等于每遍历一个节点就重新打开一次对应计数的文件覆盖之前的内容;而
tree.write和文件关闭的代码被放在了遍历csv行的循环外层,最终只会执行一次写入操作,所有写操作都指向最后一次打开的文件句柄。 - 没有做文件资源的规范处理,csv文件打开后也没有关闭逻辑,容易出现资源泄漏。
修复方案
每次处理新的csv行时,重新加载一份原始的xml模板,调整缩进让文件写入操作对应每一行csv的处理流程,用上下文管理器自动处理文件关闭:
from xml.etree import ElementTree as ET def Task(): """读取csv数据填充xml模板,按编号导出文件""" # 先读完全部csv数据,避免文件长时间占用 with open('records1.csv', 'r', encoding='UTF-8') as CSV_File: csv_lines = CSV_File.readlines() count = 0 for line in csv_lines: x = line.strip().split(',') count += 1 print(x) # 每次处理新行,重新加载原始模板,保证占位符存在 tree = ET.parse('Template1.xml') root = tree.getroot() for node in root.iter(): if node.attrib.get('val') == 'X1': node.attrib['val'] = x[0] elif node.attrib.get('val') == 'X2': node.attrib['val'] = x[1] elif node.attrib.get('val') == 'X3': node.attrib['val'] = x[2] elif node.attrib.get('val') == 'X4': node.attrib['val'] = x[3] elif node.attrib.get('val') == 'X5': node.attrib['val'] = x[4] elif node.attrib.get('val') == 'X6': node.attrib['val'] = x[5] elif node.attrib.get('val') == 'X7': node.attrib['val'] = x[6] # 调整缩进,每个csv行对应一次文件写入 with open(f'output{count}.xml', 'wb') as XML_File: tree.write(XML_File, encoding='UTF-8', xml_declaration=True)
补充说明:如果xml模板体积很大,每次重新加载性能差,可以在第一次加载模板后做深拷贝,每次循环用深拷贝的副本做替换即可,不需要重复读文件。
内容的提问来源于stack exchange,提问作者adhdcode'25
相关产品推荐
相关产品推荐

