使用Python将CSV数据转换为XML文件的问题求助
CSV转XML格式生成异常排查与修复
输入数据(Input.csv)
CustID,CardNo A00001,C000000001 A00001,C000000002 A00002,C000000003
尝试的Python代码
import csv import io import xml.etree.ElementTree as ET from collections import defaultdict def generate_xml(input_file, output_file): # Read input data from the file with open(input_file, 'r') as file: input_data = file.readlines() cards_per_custid = defaultdict(list) for line in csv.DictReader(input_data): cards_per_custid[line["CustID"]].append(line["CardNo"]) root = ET.Element( "ReceivableAccounting", attrib={"xmlns": "http://www.sample.com/testing"}, ) for cust_id, cards in sorted(cards_per_custid.items()): card_el = ET.SubElement(root, "Card") header = ET.SubElement(card_el, "CustHolderHeader") ET.SubElement(header, "CustID").text = cust_id for card_no in cards: line = ET.SubElement(card_el, "CardLine") ET.SubElement(line, "CardDetail").text = card_no tree = ET.ElementTree(root) ET.indent(tree) tree.write(output_file) # Example usage: input_file = "Input.csv" output_file = "output.xml" generate_xml(input_file, output_file)
当前生成的XML结果
<ReceivableAccounting xmlns="http://www.sample.com/testing"> <Card> <CustHolderHeader> <CustID>A00001</CustID> </CustHolderHeader> </Card> <Card> <CustHolderHeader> <CustID>A00003</CustID> </CustHolderHeader> <CardLine> <CardDetail>C000000003</CardDetail> </CardLine> </Card>
预期的XML结果
<?xml version="1.0" encoding="UTF-8"?> <ReceivableAccounting xmlns=http://www.sample.com/testing> <Card> <CustHolderHeader> <CustID>A00001</CustID> </CustHolderHeader> <CardLine> <CardDetail>C000000001</CardDetail> </CardLine> <CardLine> <CardDetail>C000000002</CardDetail> </CardLine> </Card> <Card> <CustHolderHeader> <CustID>A00002</CustID> </CustHolderHeader> <CardLine> <CardDetail>C000000003</CardDetail> </CardLine> </Card>
问题分析与修复
原代码存在两个核心问题:
- 缩进错误:生成
CardLine的for循环未嵌套在遍历客户的外层循环中,导致仅最后一个客户的卡片被生成,其他客户的CardLine完全缺失。 - XML输出配置缺失:未指定编码和XML声明,导致输出结果缺少
<?xml version="1.0" encoding="UTF-8"?>头。
额外可处理CardNo的前后空白,避免输出带空格的卡号。
修正后的代码
import csv import xml.etree.ElementTree as ET from collections import defaultdict def generate_xml(input_file, output_file): # 读取CSV数据 cards_per_custid = defaultdict(list) with open(input_file, 'r') as file: for line in csv.DictReader(file): # 去除卡号前后空白 cards_per_custid[line["CustID"]].append(line["CardNo"].strip()) root = ET.Element( "ReceivableAccounting", attrib={"xmlns": "http://www.sample.com/testing"}, ) # 遍历每个客户,生成对应的Card节点 for cust_id, cards in sorted(cards_per_custid.items()): card_el = ET.SubElement(root, "Card") # 添加客户头信息 header = ET.SubElement(card_el, "CustHolderHeader") ET.SubElement(header, "CustID").text = cust_id # 为当前客户的每张卡生成CardLine for card_no in cards: line = ET.SubElement(card_el, "CardLine") ET.SubElement(line, "CardDetail").text = card_no tree = ET.ElementTree(root) ET.indent(tree) # 写入XML,指定编码和声明 tree.write(output_file, encoding='UTF-8', xml_declaration=True) # 执行转换 input_file = "Input.csv" output_file = "output.xml" generate_xml(input_file, output_file)
修正后输出结果
<?xml version='1.0' encoding='UTF-8'?> <ReceivableAccounting xmlns="http://www.sample.com/testing"> <Card> <CustHolderHeader> <CustID>A00001</CustID> </CustHolderHeader> <CardLine> <CardDetail>C000000001</CardDetail> </CardLine> <CardLine> <CardDetail>C000000002</CardDetail> </CardLine> </Card> <Card> <CustHolderHeader> <CustID>A00002</CustID> </CustHolderHeader> <CardLine> <CardDetail>C000000003</CardDetail> </CardLine> </Card> </ReceivableAccounting>
内容的提问来源于stack exchange,提问作者vijay
相关产品推荐
相关产品推荐

