【问题标题】:Converting complex XML file to Pandas dataframe/CSV - Python将复杂的 XML 文件转换为 Pandas 数据框/CSV - Python
【发布时间】:2020-03-26 11:28:37
【问题描述】:

我目前正在将复杂的 XML 文件转换为 csv 或 pandas df。 我对 xml 数据格式的经验为零,我在网上找到的所有代码建议都不适合我。任何人都可以帮我解决这个问题吗?

数据中有很多我不需要的元素,所以我不会在此处包含这些元素。

出于隐私原因,我不会在这里上传原始数据,但我会分享结构的样子。

<RefData>
  <Attributes>
    <Id>1011</Id>
    <FullName>xxxx</FullName>
    <ShortName>xx</ShortName>
    <Country>UK</Country>
    <Currency>GBP</Currency>
  </Attributes>
  <PolicyID>000</PolicyID>
  <TradeDetails>
    <UniqueTradeId>000</UniqueTradeId>
    <Booking>UK</Booking>
    <Date>12/2/2019</Date>
    </TradeDetails>
</RefData>
<RefData>
  <Attributes>
    <Id>1012</Id>
    <FullName>xxx2</FullName>
    <ShortName>x2</ShortName>
    <Country>UK</Country>
    <Currency>GBP</Currency>
  </Attributes>
  <PolicyID>002</PolicyID>
  <TradeDetails>
    <UniqueTradeId>0022</UniqueTradeId>
    <Booking>UK</Booking>
    <Date>12/3/2019</Date>
    </TradeDetails>
</RefData>

我需要标签中的所有内容。

理想情况下,我希望标题和输出如下所示:

我真诚地感谢我能得到的任何帮助。万分感谢。

【问题讨论】:

  • 您好,感谢分享,但我在 2 天前尝试过,但它对我不起作用。帖子中使用的 xml 文件的结构与我的完全不同。

标签: python xml pandas


【解决方案1】:

关于您的输入 XML 文件的一个更正:它必须包含 一个单个主元素(任何名称),其中包含您的RefData 元素。

所以输入文件实际上包含:

<Main>
  <RefData>
    ...
  </RefData>
  <RefData>
    ...
  </RefData>
</Main>

要处理输入的XML文件,可以使用lxml包,所以要导入 它开始于:

from lxml import etree as et

然后我注意到您实际上并不需要整个已解析的 XML 树, 所以通常应用的方案是:

  • 解析后立即读取每个元素的内容,
  • 将任何子元素的内容(文本)保存在任何中间 数据结构(我选择了一个字典列表),
  • 删除源 XML 元素(不再需要),
  • 在读取循环之后,从上面创建结果DataFrame 中间数据结构。

所以我的代码如下所示:

rows = []
for _, elem in et.iterparse('RefData.xml', tag='RefData'):
    rows.append({'id':   elem.findtext('Attributes/Id'),
        'fullname':      elem.findtext('Attributes/FullName'),
        'shortname':     elem.findtext('Attributes/ShortName'),
        'country':       elem.findtext('Attributes/Country'),
        'currency':      elem.findtext('Attributes/Currency'),
        'Policy ID':     elem.findtext('PolicyID'),
        'UniqueTradeId': elem.findtext('TradeDetails/UniqueTradeId'),
        'Booking':       elem.findtext('TradeDetails/Booking'),
        'Date':          elem.findtext('TradeDetails/Date')
    })
    elem.clear()
    elem.getparent().remove(elem)
df = pd.DataFrame(rows)

要全面了解详细信息,请在 Web 上搜索 lxml 的描述和 使用的每种方法。

对于您的示例数据,结果是:

     id fullname shortname country currency Policy ID UniqueTradeId Booking      Date
0  1011     xxxx        xx      UK      GBP       000           000      UK 12/2/2019 
1  1012     xxx2        x2      UK      GBP       002          0022      UK 12/3/2019

可能要执行的最后一步是将上述 DataFrame 保存在 CSV 中 文件,但我想你知道怎么做。

【讨论】:

    【解决方案2】:

    另一种方法,使用 lxml 和 xpath:

       from lxml import etree
       dat = """[your FIXED xml]"""
       doc = etree.fromstring(dat)
       columns = []
       rows = []
       to_delete = ["TradeDetails",'Attributes']
       body = doc.xpath('.//RefData')
       for el in body[0].xpath('.//*'):
          columns.append(el.tag)
    
       for b in body:    
            items = b.xpath('.//*')
            row = []
            for item in items:
               if item.tag not in to_delete:
                   row.append(item.text)
            rows.append(row)
       for col in to_delete:
          if col in columns:
             columns.remove(col)
    
        pd.DataFrame(rows,columns=columns)
    

    输出是您问题中指示的数据框。

    【讨论】:

      猜你喜欢
      • 2014-08-07
      • 2013-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-13
      • 2019-12-16
      • 2019-12-11
      相关资源
      最近更新 更多