将 XML 结构展平为 pandas 数据框

Flatten XML structure to pandas dataframe

我无法将 xml 文件中的数据提取到 pandas 数据框中。有问题的 xml 文件具有以下结构:

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Beleg_Exchange>

  <Beleg_List>
    <Beleg_Rec>
      <ID>16092</ID>
      <Adresse_ID>3127</Adresse_ID>
      <Belegzeile_List>
        <Belegzeile_Rec>
          <ID>59122</ID>
          <Zeilennummer>1</Zeilennummer>
          <Menge>1</Menge>
          <Einheit>Stk</Einheit>
          <Belegzeilentext>Importabwicklung</Belegzeilentext>
          <Preis>100</Preis>
        </Belegzeile_Rec>
        <Belegzeile_Rec>
          <ID>59123</ID>
          <Zeilennummer>2</Zeilennummer>
          <Menge>1</Menge>
          <Einheit>Stk</Einheit>
          <Belegzeilentext>Exportabwicklung</Belegzeilentext>
          <Preis>200</Preis>
        </Belegzeile_Rec>
      </Belegzeile_List>
    </Beleg_Rec>

    <Beleg_Rec>
      <ID>16093</ID>
      <Adresse_ID>3128</Adresse_ID>
      <Belegzeile_List>
        <Belegzeile_Rec>
          <ID>59125</ID>
          <Zeilennummer>1</Zeilennummer>
          <Menge>1</Menge>
          <Einheit>Stk</Einheit>
          <Belegzeilentext>Importabwicklung</Belegzeilentext>
          <Preis>100</Preis>
        </Belegzeile_Rec>
        <Belegzeile_Rec>
          <ID>59126</ID>
          <Zeilennummer>2</Zeilennummer>
          <Menge>1</Menge>
          <Einheit>Stk</Einheit>
          <Belegzeilentext>Exportabwicklung</Belegzeilentext>
          <Preis>200</Preis>
        </Belegzeile_Rec>
      </Belegzeile_List>
    </Beleg_Rec>
  </Beleg_List>
</Beleg_Exchange>

我想将其作为平面 table 导入到 pandas 中,如下所示,为每个 <Belegzeile_Rec>.[=19= 复制 <Beleg_Rec> 下的条目]

    ID      Adresse_ID  ID_inner    Zeilennummer    Menge   Einheit Belegzeilentext     Preis
0   16092   3127        59122       1               1       Stk     Importabwicklung    100
1   16092   3127        59123       2               1       Stk     Exportabwicklung    200
2   16093   3128        59125       1               1       Stk     Importabwicklung    100
3   16093   3128        59126       2               1       Stk     Exportabwicklung    200

或者,两个可以合并的数据帧也可以很好地工作。为此,我需要 <Beleg_Rec> 的 ID 以某种方式连接到每个订单项。

我可以使用 pandas.read_xml 和特定的 xpath 阅读每个部分,但我无法找到连接两者的方法:

df_outer = pd.read_xml(f, xpath="//Beleg_Exchange/Beleg_List/Beleg_Rec")

      ID  Adresse_ID  Belegzeile_List
0  16092        3127              NaN
1  16093        3128              NaN

df_inner = pd.read_xml(f, xpath="//Beleg_Exchange/Beleg_List/Beleg_Rec/Belegzeile_List/Belegzeile_Rec")

      ID  Zeilennummer  Menge Einheit   Belegzeilentext  Preis
0  59122             1      1     Stk  Importabwicklung    100
1  59123             2      1     Stk  Exportabwicklung    200
2  59125             1      1     Stk  Importabwicklung    100
3  59126             2      1     Stk  Exportabwicklung    200

我认为前进的方向是使用 xml2dict 然后遍历字典,将其附加到数据框。有没有我不知道的更有效的方法?

试试下面的方法

import pandas as pd
import xml.etree.ElementTree as ET


xml = '''<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Beleg_Exchange>

  <Beleg_List>
    <Beleg_Rec>
      <ID>16092</ID>
      <Adresse_ID>3127</Adresse_ID>
      <Belegzeile_List>
        <Belegzeile_Rec>
          <ID>59122</ID>
          <Zeilennummer>1</Zeilennummer>
          <Menge>1</Menge>
          <Einheit>Stk</Einheit>
          <Belegzeilentext>rtabwicklung1</Belegzeilentext>
          <Preis>100</Preis>
        </Belegzeile_Rec>
        <Belegzeile_Rec>
          <ID>59123</ID>
          <Zeilennummer>2</Zeilennummer>
          <Menge>1</Menge>
          <Einheit>Stk</Einheit>
          <Belegzeilentext>abwicklung2</Belegzeilentext>
          <Preis>200</Preis>
        </Belegzeile_Rec>
      </Belegzeile_List>
    </Beleg_Rec>

    <Beleg_Rec>
      <ID>16093</ID>
      <Adresse_ID>3128</Adresse_ID>
      <Belegzeile_List>
        <Belegzeile_Rec>
          <ID>59125</ID>
          <Zeilennummer>1</Zeilennummer>
          <Menge>1</Menge>
          <Einheit>Stk</Einheit>
          <Belegzeilentext>bwicklung3</Belegzeilentext>
          <Preis>101</Preis>
        </Belegzeile_Rec>
        <Belegzeile_Rec>
          <ID>59126</ID>
          <Zeilennummer>2</Zeilennummer>
          <Menge>1</Menge>
          <Einheit>Stk</Einheit>
          <Belegzeilentext>abwicklung4</Belegzeilentext>
          <Preis>201</Preis>
        </Belegzeile_Rec>
      </Belegzeile_List>
    </Beleg_Rec>
  </Beleg_List>
</Beleg_Exchange>'''

data = []
root = ET.fromstring(xml)
records = root.findall('.//Beleg_Rec')
for record in records:
  temp = {c.tag:c.text for c in record if not len(c)}
  sub_records = record.findall('.//Belegzeile_Rec')
  for sub in sub_records:
    entry = {c.tag if c.tag != 'ID' else 'ID_inner':c.text for c in sub}
    entry.update(temp)
    data.append(entry)
df = pd.DataFrame(data)
print(df)

输出

  ID_inner Zeilennummer Menge Einheit Belegzeilentext Preis     ID Adresse_ID
0    59122            1     1     Stk   rtabwicklung1   100  16092       3127
1    59123            2     1     Stk     abwicklung2   200  16092       3127
2    59125            1     1     Stk      bwicklung3   101  16093       3128
3    59126            2     1     Stk     abwicklung4   201  16093       3128