如何使用FOR LOOP将关系型Pandas Dataframe 转换为XML?

eqoofvh9  于 2023-03-16  发布在  其他
关注(0)|答案(2)|浏览(121)

我有一个问题,就是如何通过循环遍历每个表中基于公共列的所有字段,为一些关系 Dataframe 编写XML文档。
我有3个名为admission、diagnosis和dailyintervention的表。这3个表通过一个公共列adNo关联。我想导出每个adNo的每个相关记录
我导入了以下三个df
一个月一个月一个月一个月一个月一个月一个月一个月一个月二个月一个月

入院

| 广告号|F姓名|L名称|B|
| - ------|- ------|- ------|- ------|
| 二○ ○一年|大卫|迪安|一九八四年四月二十三日|
| 二○ ○二年|约翰|雪|一九八八年二月十一日|
| 二○ ○三年|布拉特|杰夫|一九八七年十二月三十日|

诊断

| 描述ID|描述|读取代码|广告号|
| - ------|- ------|- ------|- ------|
| 第二章|支气管炎|XVGF|二○ ○一年|
| 四个|心肌病|尔秋|二○ ○一年|
| 六个|室间隔缺损|奥尤格|二○ ○二年|

每日干预

| 内部ID|活动日期|心电图|广告号|
| - ------|- ------|- ------|- ------|
| 一百|2023年2月3日|1个|二○ ○一年|
| 一百零一|2023年2月4日|1个|二○ ○一年|
| 一百零二|2023年2月3日|无|二○ ○一年|
| 一百零三|2023年2月2日|无|二○ ○二年|
| 一百零四|2023年2月5日|1个|二○ ○三年|
我喜欢将录取 Dataframe 上存在的每个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>
fjnneemd

fjnneemd1#

这是一个相当大的任务,但是可以通过panda、lxml和f字符串的组合来完成。注意,在实际的csv中,一些间距等可能与问题中的不同,但是如果需要,可以进行调整。
主要构件是入院、诊断和日常干预部分的一系列模板;然后,将这些模板插入到它们各自的情节细节容器中,然后将情节细节容器插入到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())

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

bvpmtnay

bvpmtnay2#

可以使用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>")

首先将相应的 Dataframe 收集到字典中,并将所需的标签名称作为关键字。然后按adNo对每个 Dataframe 进行分组(这里假设这是将 Dataframe 粘合在一起的相关密钥)并经由.to_xml将对应的XML结构提取到串中,移除根相关部分,并将组合后的字符串存储在以adNo为键的字典中,然后将各部分连接在一起,嵌入到EpisodeDetails标签中,并添加根级别。
如果您想要与预期输出中的日期时间格式完全相同,请事先转换相应列,例如:

admission["D.O.B"] = (
    pd.to_datetime(admission["D.O.B"], dayfirst=True)
    .dt.strftime("%Y-%m-%dT%H:%M:%S")
)

相关问题