Преобразование сложного файла 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, но я полагаю, вы знаете, как это сделать.