You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现CSV转XML时嵌套节点结构生成问题求助

问题描述

我正在编写Python脚本,实现从CSV文件读取数据并输出为指定格式XML文件的功能,参考了Stack Overflow上的《With PYTHON convert CSV file to XML file》教程完成了初始脚本,脚本可正常输出数据,但无法生成目标XML要求的嵌套结构,所有字段均平级展示。

期望的XML结构

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ImportAcademicExtract xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <AcademicExtract>
        <StudentId>StudentID</StudentId>
        <LastName>LastName</LastName>
        <FirstName>FirstName</FirstName>
        <MiddleName>MiddleName</MiddleName>
        <SocialSecurityNumber>SocialSecurityNumber</SocialSecurityNumber>
        <BirthDate>BirthDate</BirthDate>
        <GradeLevel>GradeLevel</GradeLevel>
        <SpecialProgramIndicator>SpecialProgramIndicator</SpecialProgramIndicator>
        <CIPCode>CIPCode</CIPCode>
        <RegisteredHours>RegisteredHours</RegisteredHours>
        <PostalAddresses>
            <PostalAddress>
                <AddressLine1>Address</AddressLine1>
                <AddressLine2>Address2ndLn</AddressLine2>
                <City>City</City>
                <State>State</State>
                <PostalCode>PostalCode</PostalCode>
                <CountryCode>Country</CountryCode>
            </PostalAddress>
        </PostalAddresses>
        <EmailAddresses>
            <EmailAddress>Email</EmailAddress>
        </EmailAddresses>
        <PhoneNumbers>
            <PhoneNumber>PhoneNumber</PhoneNumber>
        </PhoneNumbers>
        <AdmissionsTerm>
            <AdmissionTerm>
                <TermName>TermName</TermName>
                <AcademicYear>AcademicYear</AcademicYear>
                <AdmittedDate>AdmittedDate</AdmittedDate>
            </AdmissionTerm>
        </AdmissionsTerm>
        <EnrollmentTerms>
            <EnrollmentTerm>
                <TermName>TermNames</TermName>
                <AcademicYear>AcademicYears</AcademicYear>
                <CumulativeAttemptedHours>CumulativeAttemptedHours</CumulativeAttemptedHours>
                <CumulativeRegisteredHours>CumulativeRegisteredHours</CumulativeRegisteredHours>
                <CumulativeEarnedHours>CumulativeEarnedHours</CumulativeEarnedHours>
                <CumulativeGPA>CumulativeGPA</CumulativeGPA>
                <TermStartDate>TermStartDate</TermStartDate>
                <TermEndDate>TermEndDate</TermEndDate>
                <EnrollmentType>EnrollmentType</EnrollmentType>
                <EnrollmentStatus>EnrollmentStatus</EnrollmentStatus>
                <FirstTimeDegreeSeeking>FirstTimeDegreeSeeking</FirstTimeDegreeSeeking>
                <IntentToReturn>IntentToReturn</IntentToReturn>
                <WithdrawnDate>WithdrawnDate</WithdrawnDate>
                <ExtTermName>ExtTermName</ExtTermName>
                <AcademicYearStartDate>AcademicYearStartDate</AcademicYearStartDate>
                <AcademicYearEndDate>AcademicYearEndDate</AcademicYearEndDate>
                <ExtEnrollmentType>ExtEnrollmentType</ExtEnrollmentType>
                <DateOfDetermination>DateOfDetermination</DateOfDetermination>
                <LastDateOfAttendance>LastDateOfAttendance</LastDateOfAttendance>
                <SAPStatus>SAPStatus</SAPStatus>
            </EnrollmentTerm>
        </EnrollmentTerms>
        <AcademicPrograms>
            <AcademicProgram>
                <ProgramCredentialLevel>ProgramCredentialLevel</ProgramCredentialLevel>
                <ProgramName>ProgramName</ProgramName>
                <EdMajor1>EdMajor1</EdMajor1>
                <SiteName>SiteName</SiteName>
                <EffectiveStartDate>EffectiveStartDate</EffectiveStartDate>
                <EffectiveEndDate>EffectiveEndDate</EffectiveEndDate>
                <GraduationDate>GraduationDate</GraduationDate>
                <AnticipatedGraduationDate>AnticipatedGraduationDate</AnticipatedGraduationDate>
                <ProgramLengthInWeeks>ProgramLengthInWeeks</ProgramLengthInWeeks>
                <ProgramLengthInMonths>ProgramLengthInMonths</ProgramLengthInMonths>
                <ProgramLengthInYears>ProgramLengthInYears</ProgramLengthInYears>
                <AcademicYearBeginDate>AcademicYearBeginDate2</AcademicYearBeginDate>
                <AcademicYearEndDate>AcademicYearEndDate2</AcademicYearEndDate>
                <WeeksInProgramAcademicYear>WeeksInProgramAcademicYear</WeeksInProgramAcademicYear>
            </AcademicProgram>
        </AcademicPrograms>
    </AcademicExtract>
</ImportAcademicExtract>

当前使用的代码

import itertools
import csv
import os

csvFile = r'J:\JFAFiles\JFA-BR.csv'
xmlFile = r'J:\JFAFiles\XML-BR.xml'

csvData = csv.reader(open(csvFile))
xmlData = open(xmlFile, 'w')
xmlData.write('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' + "\n" +'<ImportAcademicExtract xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' + "\n" )

rowNum = 0
for row in csvData:
    if rowNum == 0:
        tags = row
        # replace spaces w/ underscores in tag names
        for i in range(len(tags)):
            tags[i] = tags[i].replace(' ', '_')
    else: 
        xmlData.write('        '+'<AcademicExtract>' +"\n")
        for i in range (len(tags)):
            xmlData.write('                ' +'<' + tags[i] + '>' \
                      + row[i] + '</' + tags[i] + '>' + "\n")

        xmlData.write('        '+'</AcademicExtract>' + "\n")

    rowNum +=1

xmlData.write('</ImportAcademicExtract>' + "\n")
xmlData.close()

当前错误输出样例(敏感信息已隐藏)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ImportAcademicExtract xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <AcademicExtract>
                <StudentID>____</StudentID>
                <LastName>____</LastName>
                <FirstName>____</FirstName>
                <MiddleName>____</MiddleName>
                <SocialSecurityNumber>____</SocialSecurityNumber>
                <BirthDate>____</BirthDate>
                <GradeLevel>____</GradeLevel>
                <SpecialProgramIndicator>____</SpecialProgramIndicator>
                <CIPCode>____</CIPCode>
                <RegisteredHours>____</RegisteredHours>
                <Address>____</Address>
                <Address2ndLn>____</Address2ndLn>
                <City>____</City>
                <State>____</State>
                <PostalCode>____</PostalCode>
                <Country>____</Country>
                <Email>____</Email>
                <PhoneNumber>____</PhoneNumber>
                <TermName>____</TermName>
                <AcademicYear>____</AcademicYear>
                <AdmittedDate>____</AdmittedDate>
                <TermName2>____</TermName2>
                <AcademicYear2>____</AcademicYear2>
                <CumulativeAttemptedHours>____</CumulativeAttemptedHours>
                <CumulativeRegisteredHours>____</CumulativeRegisteredHours>
                <CumulativeEarnedHours>____</CumulativeEarnedHours>
                <CumulativeGPA>____</CumulativeGPA>
                <TermStartDate>____</TermStartDate>
                <TermEndDate>____</TermEndDate>
                <EnrollmentType>____</EnrollmentType>
                <EnrollmentStatus>____</EnrollmentStatus>
                <FirstTimeDegreeSeeking>____</FirstTimeDegreeSeeking>
                <IntentToReturn>____</IntentToReturn>
                <WithdrawnDate>____</WithdrawnDate>
                <ExtTermName>____</ExtTermName>
                <AcademicYearStartDate>____</AcademicYearStartDate>
                <AcademicYearEndDate>____</AcademicYearEndDate>
                <ExtEnrollmentType>____</ExtEnrollmentType>
                <DateOfDetermination>____</DateOfDetermination>
                <LastDateOfAttendance>____</LastDateOfAttendance>
                <SAPStatus>____</SAPStatus>
                <ProgramCredentialLevel>____</ProgramCredentialLevel>
                <ProgramName>____</ProgramName>
                <EdMajor1>____</EdMajor1>
                <SiteName>____</SiteName>
                <EffectiveStartDate>____</EffectiveStartDate>
                <EffectiveEndDate>____</EffectiveEndDate>
                <GraduationDateDate>____</GraduationDateDate>
                <AnticipatedGraduationDate>____</AnticipatedGraduationDate>
                <ProgramLengthInWeeks>____</ProgramLengthInWeeks>
                <ProgramLengthInMonths>____</ProgramLengthInMonths>
                <ProgramLengthInYears>____</ProgramLengthInYears>
                <AcademicYearBeginDate2>____</AcademicYearBeginDate2>
                <AcademicYearEndDate2>____</AcademicYearEndDate2>
                <WeeksInProgramAcademicYear>____</WeeksInProgramAcademicYear>
        </AcademicExtract>
</ImportAcademicExtract>
解决方案

核心思路是先预定义CSV列名到XML标签的映射关系,以及嵌套分组的层级结构,输出时按层级逐个写入节点即可,修改后的完整代码如下:

import csv

csvFile = r'J:\JFAFiles\JFA-BR.csv'
xmlFile = r'J:\JFAFiles\XML-BR.xml'

# 定义CSV列名到XML标签的映射,没有特殊映射的默认和列名一致
tag_mapping = {
    'StudentID': 'StudentId',
    'Address': 'AddressLine1',
    'Country': 'CountryCode',
    'TermName2': 'TermName',
    'AcademicYear2': 'AcademicYear',
    'GraduationDateDate': 'GraduationDate',
    'AcademicYearBeginDate2': 'AcademicYearBeginDate',
    'AcademicYearEndDate2': 'AcademicYearEndDate'
}

# 定义嵌套分组结构:外层节点名 → 内层节点名 → 该分组包含的CSV列名
group_config = [
    {
        'outer_tag': 'PostalAddresses',
        'inner_tag': 'PostalAddress',
        'fields': ['Address', 'Address2ndLn', 'City', 'State', 'PostalCode', 'Country']
    },
    {
        'outer_tag': 'EmailAddresses',
        'inner_tag': 'EmailAddress',
        'fields': ['Email']
    },
    {
        'outer_tag': 'PhoneNumbers',
        'inner_tag': 'PhoneNumber',
        'fields': ['PhoneNumber']
    },
    {
        'outer_tag': 'AdmissionsTerm',
        'inner_tag': 'AdmissionTerm',
        'fields': ['TermName', 'AcademicYear', 'AdmittedDate']
    },
    {
        'outer_tag': 'EnrollmentTerms',
        'inner_tag': 'EnrollmentTerm',
        'fields': ['TermName2', 'AcademicYear2', 'CumulativeAttemptedHours', 'CumulativeRegisteredHours', 'CumulativeEarnedHours', 'CumulativeGPA', 'TermStartDate', 'TermEndDate', 'EnrollmentType', 'EnrollmentStatus', 'FirstTimeDegreeSeeking', 'IntentToReturn', 'WithdrawnDate', 'ExtTermName', 'AcademicYearStartDate', 'AcademicYearEndDate', 'ExtEnrollmentType', 'DateOfDetermination', 'LastDateOfAttendance', 'SAPStatus']
    },
    {
        'outer_tag': 'AcademicPrograms',
        'inner_tag': 'AcademicProgram',
        'fields': ['ProgramCredentialLevel', 'ProgramName', 'EdMajor1', 'SiteName', 'EffectiveStartDate', 'EffectiveEndDate', 'GraduationDateDate', 'AnticipatedGraduationDate', 'ProgramLengthInWeeks', 'ProgramLengthInMonths', 'ProgramLengthInYears', 'AcademicYearBeginDate2', 'AcademicYearEndDate2', 'WeeksInProgramAcademicYear']
    }
]

# 定义一级字段(AcademicExtract下直接展示的字段)
root_fields = ['StudentID', 'LastName', 'FirstName', 'MiddleName', 'SocialSecurityNumber', 'BirthDate', 'GradeLevel', 'SpecialProgramIndicator', 'CIPCode', 'RegisteredHours']

with open(csvFile, 'r', encoding='utf-8') as f_in, open(xmlFile, 'w', encoding='utf-8') as f_out:
    reader = csv.DictReader(f_in)
    # 处理CSV列名,替换空格为下划线
    reader.fieldnames = [fn.replace(' ', '_') for fn in reader.fieldnames]
    
    # 写入XML头和根节点
    f_out.write('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n')
    f_out.write('<ImportAcademicExtract xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\n')
    
    for row in reader:
        f_out.write('    <AcademicExtract>\n')
        # 先写一级字段
        for field in root_fields:
            tag = tag_mapping.get(field, field)
            f_out.write(f'        <{tag}>{row[field]}</{tag}>\n')
        
        # 写各个嵌套分组
        for group in group_config:
            outer_tag = group['outer_tag']
            inner_tag = group['inner_tag']
            fields = group['fields']
            # 写外层节点
            f_out.write(f'        <{outer_tag}>\n')
            f_out.write(f'            <{inner_tag}>\n')
            # 写分组内的字段
            for field in fields:
                tag = tag_mapping.get(field, field)
                f_out.write(f'                <{tag}>{row[field]}</{tag}>\n')
            # 闭合内层和外层节点
            f_out.write(f'            </{inner_tag}>\n')
            f_out.write(f'        </{outer_tag}>\n')
        
        f_out.write('    </AcademicExtract>\n')
    
    # 闭合根节点
    f_out.write('</ImportAcademicExtract>\n')

如果你的CSV列名和上面定义的有出入,调整tag_mapping和group_config里的字段名即可。

内容的提问来源于stack exchange,提问作者daf0555

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 12:45:00