Есть ли простой способ конвертировать xml формат в CSV, используя python? - PullRequest
0 голосов
/ 15 января 2020

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

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

  1. Есть тег xyz, который не нужен в CSV, так как избежать или игнорировать это? Все, что я хочу, - это данные из тега ab c.
  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 Ответ

1 голос
/ 15 января 2020

Я бы сделал это очень явно, вместо того, чтобы пытаться взломать 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
...