Преобразуйте вложенный XML контент в CSV, используя xml дерево в python - PullRequest
0 голосов
/ 23 марта 2020

Я очень новичок в python и, пожалуйста, относитесь ко мне так же. Когда я пытался преобразовать содержимое XML в Список словарей, я получаю вывод, но не так, как ожидалось, и много пытался поиграться.

XML Содержимое

<project>
<data>
    <row>
        <respondent>m0wxo5f6w42h3fot34m7s6xij</respondent>
        <timestamp>10-06-16 11:30</timestamp>
        <product>1</product>
        <replica>1</replica>
        <seqnr>1</seqnr>
        <session>1</session>
        <column>
            <question>Q1</question>
            <answer>a1</answer>
        </column>
        <column>
            <question>Q2</question>
            <answer>a2</answer>
        </column>
    </row>
<row>
        <respondent>w42h3fot34m7s6x</respondent>
        <timestamp>10-06-16 11:30</timestamp>
        <product>1</product>
        <replica>1</replica>
        <seqnr>1</seqnr>
        <session>1</session>
        <column>
            <question>Q3</question>
            <answer>a3</answer>
        </column>
        <column>
            <question>Q4</question>
            <answer>a4</answer>
        </column>
    <column>
            <question>Q5</question>
            <answer>a5</answer>
        </column>
    </row>
</data>
</project>

Код Я использовал:

import xml.etree.ElementTree as ET

tree = ET.parse(xml_file.xml)   # import xml from
root = tree.getroot()  
data_list = []

for item in root.find('./data'):    # find all projects node
  data = {}              # dictionary to store content of each projects
  for child in item:
    data[child.tag] = child.text   # add item to dictionary

#-----------------for loop with subchild is not working as expcted in my case
    for subchild in child:
      data[subchild.tag] = subchild.text
      data_list.append(data)
print(data_list)

headers = {k for d in data_list for k in d.keys()} # headers for csv 
with open(csv_file,'w') as f:
    writer = csv.DictWriter(f, fieldnames = headers)    # creating a DictWriter object
    writer.writeheader()    # write headers to csv
    writer.writerows(data_list)

Вывод для data_list получает последнюю информацию о вопросе в список словарей. Я думаю, что проблема в subchild forl oop, но я не понимаю, как добавить список в словари. тег столбца.

[{
    'respondent': 'anonymous_m0wxo5f6w42h3fot34m7s6xij',
    'timestamp': '10-06-16 11:30',
    'product': '1',
    'replica': '1',
    'seqnr': '1',
    'session': '1',
    'question': 'Q1',
    'answer': 'a1'
  },
  {
    'respondent': 'anonymous_m0wxo5f6w42h3fot34m7s6xij',
    'timestamp': '10-06-16 11:30',
    'product': '1',
    'replica': '1',
    'seqnr': '1',
    'session': '1',
    'question': 'Q2',
    'answer': 'a2'
  },
  {
    'respondent': 'w42h3fot34m7s6x',
    'timestamp': '10-06-16 11:30',
    'product': '1',
    'replica': '1',
    'seqnr': '1',
    'session': '1',
    'question': 'Q3',
    'answer': 'a3'
  },
  {
    'respondent': 'w42h3fot34m7s6x',
    'timestamp': '10-06-16 11:30',
    'product': '1',
    'replica': '1',
    'seqnr': '1',
    'session': '1',
    'question': 'Q4',
    'answer': 'a4'
  },
  {
    'respondent': 'w42h3fot34m7s6x',
    'timestamp': '10-06-16 11:30',
    'product': '1',
    'replica': '1',
    'seqnr': '1',
    'session': '1',
    'question': 'Q5',
    'answer': 'a5'
  }
]

Я ответил на очень много вопросов о переполнении стека на дереве xml, но все равно мне не помогло.

любая помощь / предложение приветствуется.

1 Ответ

0 голосов
/ 23 марта 2020

У меня была проблема с пониманием того, что должен делать этот код, потому что он использует абстрактные имена переменных, такие как item, child, subchild, и это затрудняет рассуждение о коде. Я не такой умный, поэтому я переименовал переменные в row, tag и column, чтобы мне было легче видеть, что делает код. (В моей книге даже строка и столбец немного абстрактны, но я полагаю, что непрозрачность ввода XML вряд ли является вашей ошибкой.)

Вы есть 2 строки, но вы хотите 5 словарей, потому что у вас есть 5 <column> тегов, и вы хотите, чтобы данные каждого <column> находились в отдельном словаре. Но вы хотите, чтобы теги other в <row> повторялись вместе с данными <column>.

Это означает, что вам нужно создать словарь для каждого <row>, затем для каждого <column>, добавьте данные этого столбца в словарь, затем выведите их перед переходом к следующему столбцу.

Этот код делает упрощающее предположение, что все ваши <columns> имеют одинаковую структуру, с ровно одним <question> и ровно одним <answer> и ничем иным. Если это предположение не выполняется, то <column> может быть сообщено с устаревшими данными, которые он унаследовал от предыдущего <column> в той же строке. Он также не выдаст вообще никакого вывода для любого <row>, у которого нет хотя бы одного <column>.

Код должен дважды пропустить через теги oop, один раз для не <column> s и один раз для <column> s. В противном случае он не может быть уверен, что он видел все не-1038 * теги, прежде чем он начнет выводить <column> s.

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

for row in root.find('./data'):    # find all projects node
    data = {}              # dictionary to store content of each projects
    for tag in row:
        if tag.tag != "column":
            data[tag.tag] = tag.text   # add row to dictionary
    # Now the dictionary data is built for the row level
    for tag in row:
        if tag.tag == "column":
            for column in tag:
                data[column.tag] = column.text
            # Now we have added the column level data for one column tag
            data_list.append(data.copy())

Вывод будет таким, как показано ниже. Порядок ключевых слов не сохраняется, потому что для удобства я использовал pprint.pprint.

[{'answer': 'a1',
  'product': '1',
  'question': 'Q1',
  'replica': '1',
  'respondent': 'm0wxo5f6w42h3fot34m7s6xij',
  'seqnr': '1',
  'session': '1',
  'timestamp': '10-06-16 11:30'},
 {'answer': 'a2',
  'product': '1',
  'question': 'Q2',
  'replica': '1',
  'respondent': 'm0wxo5f6w42h3fot34m7s6xij',
  'seqnr': '1',
  'session': '1',
  'timestamp': '10-06-16 11:30'},
 {'answer': 'a3',
  'product': '1',
  'question': 'Q3',
  'replica': '1',
  'respondent': 'w42h3fot34m7s6x',
  'seqnr': '1',
  'session': '1',
  'timestamp': '10-06-16 11:30'},
 {'answer': 'a4',
  'product': '1',
  'question': 'Q4',
  'replica': '1',
  'respondent': 'w42h3fot34m7s6x',
  'seqnr': '1',
  'session': '1',
  'timestamp': '10-06-16 11:30'},
 {'answer': 'a5',
  'product': '1',
  'question': 'Q5',
  'replica': '1',
  'respondent': 'w42h3fot34m7s6x',
  'seqnr': '1',
  'session': '1',
  'timestamp': '10-06-16 11:30'}]
...