Преобразование сложного файла XML в фрейм данных Pandas /CSV - Python

В настоящее время я занимаюсь преобразованием сложного 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 ответа

Решение

Другой способ сделать это, используя 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)

Выход - это фрейм данных, указанный в вашем вопросе.

Одно исправление, касающееся вашего входного 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)

Чтобы получить полное представление о деталях, поищите в Интернете описание 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, но я полагаю, вы знаете, как это сделать.

Другие вопросы по тегам