Как преобразовать XML-файл в файл Excel?

#python #excel #xml

Вопрос:

У меня есть каталог, который содержит несколько XML-файлов, допустим, он содержит следующие 2:

 <Record>
        <RecordID>Madird01</RecordID>
        <Location>Madird</Location>
        <Date>07-09-2020</Date>
        <Time>07u43m55s</Time>
        <Version>2.0.1</Version>
        <Version_2>v1.9</Version_2>
    <Max_30e>
        <I_25Hz_1s>56.40</I_25Hz_1s>
        <I_25Hz_2s>7.44</I_25Hz_2s>
    </Max_30e>
    <Max_30e>
        <I_75Hz_1s>1.56</I_75Hz_1s>
        <I_75Hz_2s>0.36</I_75Hz_2s>
    </Max_30e>
</Record>
 

И:

 <Record>
        <RecordID>London01</RecordID>
        <Location>London</Location>
        <Date>07-09-2020</Date>
        <Time>08u53m45s</Time>
        <Version>2.0.1</Version>
        <Version_2>v1.9</Version_2>
    <Max_30e>
        <I_25Hz_1s>56.40</I_25Hz_1s>
        <I_25Hz_2s>7.44</I_25Hz_2s>
    </Max_30e>
    <Max_30e>
        <I_75Hz_1s>1.56</I_75Hz_1s>
        <I_75Hz_2s>0.36</I_75Hz_2s>
    </Max_30e>
</Record>
 

Теперь я хочу преобразовать это в файл Excel, который показывает каждый XML-файл в горизонтальном порядке следующим образом:
введите описание изображения здесь

Я попытался сначала преобразовать XML в строку csv, а затем в Excel, но я застрял, должны быть более простые способы.

Это мой текущий код:

 import xml.etree.ElementTree as ET
import os

xml_root = r'c:dataDesktopBlueXML-files'

for file in os.listdir(xml_root):
    xml_file_path = os.path.join(xml_root, file)
    
    tree = ET.parse(xml_file_path)
    root = tree.getroot()
    tree = ET.ElementTree(root)

    for child in root:
        mainlevel = child.tag
        xmltocsv = ''
        for elem in root.iter():
            if elem.tag == root.tag:
                continue
            if elem.tag == mainlevel:
                xmltocsv = xmltocsv   'n'
            xmltocsv = xmltocsv   str(elem.tag).rstrip()   str(elem.attrib).strip()   ';'   str(elem.text).rstrip()   ';'
 

Комментарии:

1. Эта библиотека может быть вашим другом: openpyxl.readthedocs.io/en/stable

2. @floatingpurr это только для Excel 2010, у меня последняя версия я нахожу эту библиотеку довольно сложной

3. Он создает файлы xlsx. У вас не должно возникнуть проблем с последней версией Excel. Здесь вы можете найти еще больше ресурсов: python-excel.org

Ответ №1:

создайте CSV-файл в формате, удобном для Excel.

 import xml.etree.ElementTree as ET
from os import listdir


xml_lst = [f for f in listdir() if f.startswith('xml')]
fields = ['RecordID','I_25Hz_1s','I_75Hz_2s'] # TODO - add rest of the fields
with open('out.csv','w') as f:
  f.write(','.join(fields)   'n')
  for xml in xml_lst:
    root = ET.parse(xml)
    values = [root.find(f'.//{f}').text for f in fields]
    f.write(','.join(values)   'n')
 

вывод

 RecordID,I_25Hz_1s,I_75Hz_2s
Madird01,56.40,0.36
London01,56.40,0.36
 

Комментарии:

1. Я использую XML-файлы вместо XML-строк. У меня есть ET.parse(xml_file_path) , а затем я использую root=tree.getroot() so после того, как я это сделаю root.text , я получаю AttributeError: 'NoneType' object has no attribute 'text'

2. Вам просто нужно заменить fromstring на parse

3. Это то, что у меня уже есть, но все та же ошибка: root = ET.parse(xml_file_path) values = [root.find(f'.//{f}').text for f in fields] я получаю следующую ошибку: AttributeError: 'NoneType' object has no attribute 'text'

4. Каков путь к файлу XML? Возможно, ваша проблема в этом

5. Это абсолютный путь к файлу XML-файла. ET.parse создает elementtree элемент, в то время ET.fromstring как создает элемент.

Ответ №2:

Когда вам нужно перебирать файлы в папке с похожими именами , одним из способов может быть создание шаблона и использование glob . Чтобы убедиться , что возвращаемый путь — это файл, который вы можете использовать isfile() .

Что касается XML, я вижу, что в основном вам нужно записать значения каждого терминального тега в столбец с именем этого тега. Поскольку у вас есть различные файлы, вы можете создавать словари значений тегов из каждого файла и сохранять их в ChainMap нем. После обработки всех файлов вы можете использовать DictWriter их для записи всех данных в конечный CSV-файл.

Этот метод гораздо более безопасен и гибок, чем использование статических имен столбцов. Сначала программа соберет все возможные имена тегов (столбцов) из всех файлов, поэтому в случае, если в XML нет такого тега или есть несколько дополнительных тегов, он не выдаст исключение, и все данные будут сохранены.

Код:

 import xml.etree.ElementTree as ET
from glob import iglob
from os.path import isfile, join
from csv import DictWriter
from collections import ChainMap

xml_root = r"C:dataDesktopBlueXML-files"
pattern = "xmlfile_*"
data = ChainMap()
for filename in iglob(join(xml_root, pattern)):
    if isfile(filename):
        tree = ET.parse(filename)
        root = tree.getroot()
        temp = {node.tag: node.text for node in root.iter() if not node}
        data = data.new_child(temp)

with open(join(xml_root, "data.csv"), "w", newline="") as f:
    writer = DictWriter(f, data)
    writer.writeheader()
    writer.writerows(data.maps[:-1])  # last is empty dict
 

Upd. Если вы хотите использовать xlsx format вместо csv того, чтобы использовать стороннюю библиотеку (например openpyxl ). Пример использования:

 from openpyxl import Workbook

...

wb = Workbook(write_only=True)
ws = wb.create_sheet()
ws.append(list(data))  # write header
for row in data.maps[:-1]:
    ws.append([row.get(key, "") for key in data])
wb.save(join(xml_root, "data.xlsx"))
 

Комментарии:

1. как мне записать точно такой же файл data.csv в Excel?

2. @Аль-Андалус, что ты имеешь в виду? Вам нужен xlsx формат? Excel должен поддерживать CSV

3. Какую строку мне добавить после writer.writerows(data.maps[:-1]) , чтобы превратить этот csv-файл в файл Excel?

4. @Al-Andalus, вы можете открыть .csv файл с помощью Excel, это поддерживаемый формат.

5. Я пробовал это, но я получаю все до первой запятой внутри 1 столбца. Я предпочитаю, чтобы это был непосредственно файл Excel, а затем файл csv