Генерация xml на основе словаря python
Товарищи, помогите! :) Второй день бьюсь и не могу решить проблему.
Мне необходимо создавать xml файл на основе данных из словаря python. Данные которые потом будут в xml, берутся из БД. Данные из БД я получаю по названиям ключей самого словаря. Я накидал пример моего кода:
Вот такого вида словарь
data_config = {
'element_1': {
'main_name': 'Элемент_1'
},
'element_2': {
'main_name': 'Элемент_2',
'element_2_1': {
'main_name': 'Элемент_2_1',
},
'element_2_2': {
'main_name': 'Элемент_2_2',
},
'element_2_3': {
'main_name': 'Элемент_2_3',
'element_2_3_1': {
'main_name': 'Элемент_2_3_1',
},
'element_2_3_2': {
'main_name': 'Элемент_2_3_2',
},
'element_2_3_3': {
'main_name': 'Элемент_2_3_3',
'element_2_3_3_1': {
'main_name': 'Элемент_2_3_3_1',
},
'element_2_3_3_2': {
'main_name': 'Элемент_2_3_3_2',
},
}
},
},
}
Я хочу получить из него вот такой xml файл:
<?xml version='1.0' encoding='utf-8'?>
<Файл>
<Элемент_1>Данные</Элемент_1>
<Элемент_2>
<Элемент_2_1>Данные</Элемент_2_1>
<Элемент_2_2>Данные</Элемент_2_2>
<Элемент_2_3>
<Элемент_2_3_1>Данные</Элемент_2_3_1>
<Элемент_2_3_2>Данные</Элемент_2_3_2>
<Элемент_2_3_3>
<Элемент_2_3_3_1>Данные</Элемент_2_3_3_1>
<Элемент_2_3_3_2>Данные</Элемент_2_3_3_2>
</Элемент_2_3_3>
</Элемент_2_3>
</Элемент_2>
</Файл>
Моя проблема в том, что я не знаю, какая будет вложенность у словаря. Вложенность может быть любой. А так же есть элементы, которые одиночные и не имеют внутри себя других элементов. Я сделал код, который обрабатывает два первых уровня вложенности и использует списки вместо словарей, но мне необходимо использовать именно словари. Для генерации xml я использую библиотеку ElementTree.
Вот кусок кода который я не дописал, чтобы был понятен ход мыслей:
def generate_doc(user_data: dict, required_data: dict):
doc = Et.Element("Файл")
required_data_keys = required_data.keys()
for key in required_data_keys:
current_doc_list = required_data[key]
current_doc_name = current_doc_list['main_name']
if len(required_data[key].keys()) == 1:
Et.SubElement(doc, current_doc_name).text = user_data[key]
else:
current_doc = Et.SubElement(doc, current_doc_name)
return doc
В user_data мне приходит словарь из БД без вложенности т.е. структура ровная.
user_data = {
'element_1': 1,
'element_2': 'Данные',
'element_2_1': 'Данные',
'element_2_3_3': 'Данные',
'element_2_3_3_2': 'Данные'
}
В required_data Как раз тот самый словарь, который я разместил выше.
Вот таким образом я кладу данные в xml:
Et.SubElement(doc, current_doc_name).text = user_data[key]
user_data из ДБ, а ключ из ключа в required_data.
Как я понимаю, нужна рекурсия(но это не точно :)). Но у меня никак не выходит понять, как это реализовать.
Ответы (1 шт):
Не совсем понятно в первом примере откуда берется текст "Данные", но для превращения словаря в xml (без учета наличия списка в исходном словаре) можно использовать такой код:
import xml.etree.ElementTree as Xml
data_config = {
'element_1': {
'main_name': 'Элемент_1'
},
'element_2': {
'main_name': 'Элемент_2',
'element_2_1': {
'main_name': 'Элемент_2_1',
},
'element_2_2': {
'main_name': 'Элемент_2_2',
},
'element_2_3': {
'main_name': 'Элемент_2_3',
'element_2_3_1': {
'main_name': 'Элемент_2_3_1',
},
'element_2_3_2': {
'main_name': 'Элемент_2_3_2',
},
'element_2_3_3': {
'main_name': 'Элемент_2_3_3',
'element_2_3_3_1': {
'main_name': 'Элемент_2_3_3_1',
},
'element_2_3_3_2': {
'main_name': 'Элемент_2_3_3_2',
},
}
},
},
}
def get_xml_element_from_dict(data: dict, parent: Xml.Element) -> Xml.SubElement:
for key, value in data.items():
element = Xml.SubElement(parent, key)
if isinstance(value, dict):
get_xml_element_from_dict(value, element)
else:
element.text = value
def get_xml_from_dict(data: dict) -> Xml.ElementTree:
root = Xml.Element('Файл')
get_xml_element_from_dict(data, root)
tree = Xml.ElementTree(root)
return tree
def write_tree_to_file(tree: Xml.ElementTree) -> None:
with open('for_tests.xml', mode='wb') as file:
tree.write(file, encoding='utf-8', xml_declaration=True)
result = get_xml_from_dict(data_config)
write_tree_to_file(result)
В результате получится такой файл:
<?xml version='1.0' encoding='utf-8'?>
<Файл>
<element_1>
<main_name>Элемент_1</main_name>
</element_1>
<element_2>
<main_name>Элемент_2</main_name>
<element_2_1>
<main_name>Элемент_2_1</main_name>
</element_2_1>
<element_2_2>
<main_name>Элемент_2_2</main_name>
</element_2_2>
<element_2_3>
<main_name>Элемент_2_3</main_name>
<element_2_3_1>
<main_name>Элемент_2_3_1</main_name>
</element_2_3_1>
<element_2_3_2>
<main_name>Элемент_2_3_2</main_name>
</element_2_3_2>
<element_2_3_3>
<main_name>Элемент_2_3_3</main_name>
<element_2_3_3_1>
<main_name>Элемент_2_3_3_1</main_name>
</element_2_3_3_1>
<element_2_3_3_2>
<main_name>Элемент_2_3_3_2</main_name>
</element_2_3_3_2>
</element_2_3_3>
</element_2_3>
</element_2>
</Файл>