Есть ли простой способ преобразовать формат xml в csv с помощью python?

У меня есть приведенный ниже xml, который я хотел бы преобразовать в csv (разделитель, например '|' или восьмеричный), используя python. Я попытался преобразовать xml в dict, а затем в csv. Я ищу, есть ли какие-нибудь простые или эффективные методы для этого.

Проблемы с приведенным ниже кодом:

  1. Есть тег xyz, который не нужен в csv, так как его избежать или проигнорировать? Все, что мне нужно, это данные из тега abc.
  2. Хотел бы, чтобы вложенный тег был префиксом для базовых ключей
  3. Ожидаемый результат - это строка с ключами в качестве заголовка и значениями под ним.

Пример XML:

    <?xml version="1.0" encoding="utf-8"?>
    <xyz date="2019-07-01T09:00:29">
      <abc>
        <id>23</id>
        <uniqueid>23_0</uniqueid>
        <Name></Name>
        <Rate>
          <mrp>6.40000</mrp>
          <discount>10.00%</discount>
          <discountmonths>2</discountmonths>
        </Rate>
        <fee>
          <type>off</type>
          <minimumfee>£1,500.75</minimumfee>
          <maxfee>£10K</maxfee>
        </fee>
      </abc>
      <abc>
        <id>35</id>
        <uniqueid>35_0</uniqueid>
        <Name></Name>
        <Rate>
          <mrp>7.90000</mrp>
          <discount>5.00%</discount>
          <discountmonths>5</discountmonths>
        </Rate>
        <fee>
          <type>offer</type>
          <minimumfee>£1k</minimumfee>
          <maxfee>£22,000</maxfee>
        </fee>
      </abc>
    </xyz>

Код: (не обращайте внимания на незрелость кода, просто новичок, в основном копирую пасту с нескольких сайтов... пытаясь понять, работает ли это, а потом подумал, что буду знать, с чего начать или изменить существующий)

    import xml.etree.ElementTree as ET
    import xmltodict
    import csv
    tree = ET.parse('myxml_1.xml')
    xml_data = tree.getroot()
    xmlstr = ET.tostring(xml_data, encoding='utf-8', method='xml')
    data_dict = dict(xmltodict.parse(xmlstr))

    with open('test1.csv','w') as f:
        w = csv.writer(f)
        w.writerow(data_dict.keys())
        w.writerow(data_dict.values())

ожидаемый результат:

    id|uniqueid|Name|rate_mrp|rate_discount|rate_discountmonths|fee_type|fee_minimumfee|fee_maxfee
    23|23_0||6.40000|10.00%|2|off|£1,500.75|£10K
    35|35_0||7.90000|5.00%|5|offer|£1k|£22,000

1 ответ

Я бы сделал это очень явным образом, вместо того, чтобы пытаться взломать xmltodict чтобы соответствовать вашим потребностям.

Единственный недостаток этого подхода, который я вижу, - это небольшое повторение жестко запрограммированных заголовков и имен тегов.

Кроме того, я не знаю, насколько регулярным будет ваш ввод XML. Если возможно, что некоторые из тегов не будут присутствовать, вам нужно будет добавить некоторую обработку ошибок (потому чтоnode.find вернусь None, тогда .text вызовет AttributeError).

rows = []
for abc_node in tree.findall('abc'):
    rate_node = abc_node.find('Rate')
    fee_node = abc_node.find('fee')
    row = {'id': abc_node.find('id').text,
           'uniqueid': abc_node.find('uniqueid').text,
           'Name': abc_node.find('Name').text,
           'rate_mrp': rate_node.find('mrp').text,
           'rate_discount': rate_node.find('discount').text,
           'rate_discountmonths': rate_node.find('discountmonths').text,
           'fee_type': fee_node.find('type').text,
           'fee_minimumfee': fee_node.find('minimumfee').text,
           'fee_maxfee': fee_node.find('maxfee').text}
    rows.append(row)

with open('test.csv', 'w', encoding='utf8') as f:
    headers = ['id', 'uniqueid', 'Name', 'rate_mrp', 'rate_discount', 'rate_discountmonths',
               'fee_type', 'fee_minimumfee', 'fee_maxfee']
    dict_writer = csv.DictWriter(f, fieldnames=headers, lineterminator='\n')
    dict_writer.writeheader()
    dict_writer.writerows(rows)

Выход

id,uniqueid,Name,rate_mrp,rate_discount,rate_discountmonths,fee_type,fee_minimumfee,fee_maxfee
23,23_0,,6.40000,10.00%,2,off,"£1,500.75",£10K
35,35_0,,7.90000,5.00%,5,offer,£1k,"£22,000" 

Если ты хочешь | в качестве разделителя просто добавьте delimiter='|' к csv.DictWriter(f, fieldnames=headers, lineterminator='\n')

тогда вывод

id|uniqueid|Name|rate_mrp|rate_discount|rate_discountmonths|fee_type|fee_minimumfee|fee_maxfee
23|23_0||6.40000|10.00%|2|off|£1,500.75|£10K
35|35_0||7.90000|5.00%|5|offer|£1k|£22,000
Другие вопросы по тегам