Python — Преобразование xml в csv с использованием Python pandas

#python #xml #pandas #export-to-csv

#python #xml #pandas #экспорт в csv

Вопрос:

Я новичок здесь, и я пытался создать небольшой скрипт на Python для преобразования xml в csv. Основываясь на моем чтении различных сообщений здесь, в Stackoverflow, мне удалось придумать пример кода, который работает просто отлично.. Однако данные, с которыми я пытаюсь работать, имеют несколько слоев, и поэтому я не уверен, как извлечь данные на конечном уровне.

Ниже приведено, как выглядят данные:

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Transmission>
    <TransmissionBody>
        <level1>
            <level2>
                <level3>
                    <level4>
                        <level5>
                            <level6>
                                <ColA>ABC</ColA>
                                <ColB>123</ColB>
                            </level6>
                        </level5>
                    </level4>
                </level3>
            </level2>
        </level1>
    </TransmissionBody>
</Transmission>
  

Я пытаюсь использовать приведенный ниже код, чтобы попытаться преобразовать xml в csv

 import pandas as pd
import xml.etree.ElementTree as ET

tree = ET.parse('file.xml')
root = tree.getroot()
final = {}
for elem in root:
    if len(elem):
        for c in elem.getchildren():
            final[c.tag] = c.text
    else:
        final[elem.tag] = elem.text

df = pd.DataFrame([final])
df.to_csv('file.csv)
  

Однако этот код просто извлекает level2, а не ColA из level6.

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

 Transmission,TransmissionBody,level1,level2,level3,level4,level5,level6,ColA,ColB
,,,,,,,,ABC,123
,,,,,,,,DEF,456
  

Обновленный код:

 allFiles = glob.glob(folder)
for file in allFiles:
    xmllist = [file]
    for xmlfile in xmllist:
        tree = ET.parse(xmlfile)
        root = tree.getroot()

        def f(elem, result):
            result[elem.tag] = elem.text
            cs = elem.getchildren()
            for c in cs:
                result = f(c, result)
            return result

         d = f(root, {})
         df = pd.DataFrame(d, index=['values'])
  

Ответ №1:

у вас проблема с отступом на

 if len(elem):
  

Я думаю, это должно решить проблему.

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

1. if len(elem): находится на базовом уровне, какой отступ вы предлагаете в этой строке?

2. Что заставляет вас думать, что строка if () находится на базовой линии? Для меня это выглядит как часть элемента for в root: loop, поэтому в нем должен быть отступ.

Ответ №2:

Если я правильно понял ваш вопрос, вам нужно пройти по дереву XML, поэтому вы, вероятно, хотите иметь рекурсивную функцию, которая делает это. Что-то вроде следующего:

 import pandas as pd
import xml.etree.ElementTree as ET

tree = ET.parse('file.xml')
root = tree.getroot()

def f(elem, result):
    result[elem.tag] = elem.text
    cs = elem.getchildren()
    for c in cs:
        result = f(c, result)
    return result

d = f(root, {})
df = pd.DataFrame(d, index=['values']).T
df
  

Выход:

     values
Transmission    n
TransmissionBody    n
level1  n
level2  n
level3  n
level4  n
level5  n
level6  n
ColA    ABC
ColB    123
  

Обновить:
Вот когда нам нужно сделать это для нескольких XML-файлов. Я добавил еще один файл, похожий на исходный, с ColA, строки ColB заменены на

 <ColA>DEF</ColA>
<ColB>456</ColD>
  

Вот код:

 def f(elem, result):
    result[elem.tag] = elem.text
    cs = elem.getchildren()
    for c in cs:
        result = f(c, result)
    return result

result = {}
for file in glob.glob('*.xml'):
    tree = ET.parse(file)
    root = tree.getroot()
    result = f(root, result)

df = pd.DataFrame(result, index=['values']).T
df
  

И вывод:

                     0    1
Transmission       n   n
TransmissionBody   n   n
level1             n   n
level2             n   n
level3             n   n
level4             n   n
level5             n   n
level6             n   n
ColA              ABC  DEF
ColB              123  456
  

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

1. Сомнение: почему вы это переносите? Требовалось создать csv с заголовками в верхней строке, в отличие от заголовков в первом столбце, не так ли?