如何使用 FOR 循环将关系型 pandas 数据框转换为 XML?

问题描述 投票:0回答:2

我有一个问题,关于如何通过基于它们的公共列遍历每个表中的所有字段来为某些关系数据框编写 XML 文档。

我有 3 个表,分别是入院、诊断和日常干预。这 3 个表通过公共列 adNo 相关联。我想导出每个广告号的所有相关记录

我导入了以下三个df

admission = pd.read_csv(r'Path where the CSV file is stored\File name.csv')
diagnosis = pd.read_csv(r'Path where the CSV file is stored\File name.csv')
dailyIntervention = pd.read_csv(r'Path where the CSV file is stored\File name.csv')

入场

广告否 F姓名 L名字 D.O.B
2001 大卫 院长 23/04/1984
2002 约翰 11/02/1988
2003 小子 杰夫 30/12/1987

诊断

descID 描述 阅读代码 adNo
2 细支气管炎 XVGF 2001
4 心肌病 rtyu 2001
6 VSD oiug 2002

每日干预

内部ID 活动日期 心电图 广告否
100 02/03/2023 1 2001
101 04/02/2023 1 2001
102 03/02/2023 0 2001
103 02/02/2023 0 2002
104 05/02/2023 1 2003

我想将存在于admission数据框上的每个adNo的所有记录写入一个xml文件。

请看下面我想要的结果

<?xml version="1.0" encoding="UTF-8"?>
<dataroot xmlns:od="urn:schemas-microsoft-com:officedata" generated="2023-03-10T11:15:55">
    <EpisodeDetails>
        <Admission>
            <adNo>2001</adNo>
            <FName>David</FName>
            <LName>Dean</LName>
            <D.O.B>1984-04-23T00:00:00</D.O.B>
        </Admission>
        <diagnosis>
            <dascID>2</dascID>
            <description>BRONCHIOLITIS</description>
            <readCode>XVGF</readCode>
            <adNo>2001</adNo>
        </diagnosis>
        <diagnosis>
            <dascID>4</dascID>
            <description>CARDIOMYOPATHY</description>
            <readCode>rtyu</readCode>
            <adNo>2001</adNo>
        </diagnosis>
        <dailyIntervention>
            <IntID>100</IntID>
            <activitydate>2023-03-02T00:00:00</activitydate>
            <ecg>1</ecg>
            <adNo>2001</adNo>
        </dailyIntervention>
        <dailyIntervention>
            <IntID>101</IntID>
            <activitydate>2023-02-04T00:00:00</activitydate>
            <ecg>1</ecg>
            <adNo>2001</adNo>
        </dailyIntervention>
        <dailyIntervention>
            <IntID>102</IntID>
            <activitydate>2023-02-03T00:00:00</activitydate>
            <ecg>0</ecg>
            <adNo>2001</adNo>
        </dailyIntervention>
    </EpisodeDetails>
    <EpisodeDetails>
        <Admission>
            <adNo>2002</adNo>
            <FName>John</FName>
            <LName>Snow</LName>
            <D.O.B>1988-02-11T00:00:00</D.O.B>
        </Admission>
        <diagnosis>
            <dascID>6</dascID>
            <description>VSD</description>
            <readCode>oiug</readCode>
            <adNo>2002</adNo>
        </diagnosis>
        <dailyIntervention>
            <IntID>103</IntID>
            <activitydate>2023-02-02T00:00:00</activitydate>
            <ecg>0</ecg>
            <adNo>2002</adNo>
        </dailyIntervention>
    </EpisodeDetails>
    <EpisodeDetails>
        <Admission>
            <adNo>2003</adNo>
            <FName>Brat</FName>
            <LName>Jeff</LName>
            <D.O.B>1987-12-30T00:00:00</D.O.B>
        </Admission>
        <dailyIntervention>
            <IntID>104</IntID>
            <activitydate>2023-02-05T00:00:00</activitydate>
            <ecg>1</ecg>
            <adNo>2002</adNo>
        </dailyIntervention>
    </EpisodeDetails>
</dataroot>
python pandas xml dataframe
2个回答
0
投票

你在这里完成的任务相当艰巨,但可以结合使用 pandas、lxml 和 f-strings 来完成。请注意,在您的实际 csvs 中,某些间距等可能与问题中的不同,但您可以根据需要进行调整。

主要构建块是一系列用于入院、诊断和日常干预部分的模板;然后将这些模板插入到各自的剧集详细信息容器中,然后将其插入到 XML 文档本身中。

其中一些可能会通过添加一两个辅助函数来简化,但恐怕我没有时间去尝试。

import pandas as pd
from lxml import etree

#the document skeleton
xml_string = """<?xml version="1.0" encoding="UTF-8"?>
<dataroot xmlns:od="urn:schemas-microsoft-com:officedata" generated="2023-03-10T11:15:55">   
</dataroot>"""
doc = etree.XML(xml_string.encode())

#create the structure for each episode:
for a in admission['adNo']:
    #create an episode container:
    epi = etree.fromstring('<EpisodeDetails/>')
    #get episode data
    ad_det = admission[admission['adNo ']==a].to_csv(index=False, header=False).strip().split(',')
    #use f-strings to insert the details into an Admission template
    admit = f"""<Admission>
            <adNo>{ad_det[0]}</adNo>
            <FName>{ad_det[1]}</FName>
            <LName>{ad_det[2]}</LName>
            <D.O.B>{ad_det[3]}</D.O.B>            
        </Admission>"""
    #insert this into the Episode container
    epi.append(etree.fromstring(admit))

    #repeat the process for the diagnosis section:
    diags=diagnosis[diagnosis['adNo']==a].to_csv(index=False, header=False).strip().split('\r\n')
    for d in range(len(diags)):
        diag_det = diags[d].split(',')
        if len(diag_det)==4:
            #use the diagnosis template this time:
            diagno = f"""<diagnosis>
                <dascID>{diag_det[0]}</dascID>
                <description>{diag_det[1]}</description>
                <readCode>{diag_det[2]}</readCode>
                <adNo>{diag_det[3]}</adNo>
            </diagnosis>"""
            epi.append(etree.fromstring(diagno))

    #finally, do the same for daily interventions
    intervs = dailyIntervention[dailyIntervention['adNo']==a].to_csv(index=False, header=False).strip().split('\r\n')
    for d in range(len(intervs)):
        interv_det = intervs[d].split(',')
        if len(interv_det)==4:
            daily_i =f""" <dailyIntervention>
            <IntID>{interv_det[0]}</IntID>
            <activitydate>{interv_det[1]}</activitydate>
            <ecg>{interv_det[2]}</ecg>
            <adNo>{interv_det[3]}</adNo>
        </dailyIntervention>"""
            epi.append(etree.fromstring(daily_i))  
    #now append the whole thing to the document itself
    doc.append(epi)

#you need python 3.9 for this:
etree.indent(doc, space='  ')
print(etree.tostring(doc).decode())  

输出应该是您的预期输出。


0
投票

您可以使用

DataFrame.to_xml
方法获取部分 XML 结构,然后组合它们:

import re
from textwrap import indent

re_data = re.compile("</?data>\n?")

dfs = {"Admission": admission, "diagnosis": diagnosis, "dailyIntervention": dailyIntervention}
groups = {}
for name, df in dfs.items():
    for adNo, sdf in df.groupby("adNo"):
        if adNo not in groups:
            groups[adNo] = ""
        xml_str = sdf.to_xml(index=False, row_name=name, xml_declaration=False)
        groups[adNo] += "\n" + re_data.sub("", xml_str).rstrip()

with open("result.xml", "w") as file:
    file.write('<?xml version="1.0" encoding="UTF-8"?>\n')
    file.write('<dataroot>\n')
    for group in groups.values():
        xml_str = "<EpisodeDetails>" + group + "\n</EpisodeDetails>\n"
        file.write(indent(xml_str, " "))
    file.write("</dataroot>")

首先收集resp。字典中的数据帧,以所需的标签名称作为键。然后将每个数据帧按

adNo
分组(这里假设这是将数据帧粘合在一起的相关键)并通过
.to_xml
将相应的XML结构提取到字符串中,删除与根相关的部分,并存储以
adNo
为键的字典中的组合字符串。然后将各个部分连接在一起,嵌入到
EpisodeDetails
标签中,并添加根级别。

如果您想要与预期输出中一样的确切日期时间格式,请转换 resp。预先列,例如:

admission["D.O.B"] = (
    pd.to_datetime(admission["D.O.B"], dayfirst=True)
    .dt.strftime("%Y-%m-%dT%H:%M:%S")
)
© www.soinside.com 2019 - 2024. All rights reserved.