Парсим какой-нибудь XML

Каждый, кто написал в жизни хоть строчку кода, слышал такое выражение – не нужно изобретать велосипед, то есть, зачем писать то, что уже написано. И мы полностью согласны с этой мыслью — зачем изобретать велосипед, когда им уже можно с удовольствием пользоваться. Тема парсинга XML уже разобрана не раз, поэтому прокатимся на велосипеде парсинга XML по документам с неизвестной структурой.

В сети существует множество руководств, где авторы бодро разбирают структуру XML известного документа – решительно находят root у дерева, после чего мужественно пробегают циклом по тэгам, при этом циклы используют столько раз, сколько уровней вложенности у документа. Это все хорошо и отлично, когда мы знаем сколько раз нужно натравить цикл на очередной уровень вложенности.

Но у нас возникла задача, с которой мы еще не сталкивались, когда есть много документов XML, а документации по структуре данных нет, вообще. Нет, не та… . НЕТ вообще!. Как в таком случае, мы с помощью имеющегося опыта можем опознать структуру и глубину текущих файлов?

Данные XML хранятся в базе в текстовом виде — xml_text. Для начала считаем и опознаем то, что можно – получим root документа – он есть у всех.

from lxml import etree as ET from io import BytesIO import os byte_obj = BytesIO(xml_text.encode()) tree = ET.parse(byte_obj) root = tree.getroot()

Так как у нас нет никакой гарантии, что файл, который будет записан завтра, не будет иметь другую структуру, для начала, прокатимся на велосипеде рекурсивного алгоритма, и получим структуру в линейном виде. Так как нам важен порядок, то сохранять данные будем в список с именем xml_data.

xml_data = [] deffind_Etree(xml_elements, level=0): # Формируем список вида - уровень, тэг, тектовое значение ifstr(type(xml_elements)) == "<class 'lxml.etree._Element'>": level = level forxml_elementinxml_elements: xml_data.append((level, xml_element.tag.split('}')[1], xml_element.text)) find_Etree(xml_element, level+1) returnxml_elements

Результат работы сохранен в список xml_data и имеет следующую структуру — список кортежей, где каждый кортеж — это уровень вложения от корневого тэга, наименование тэга и значение тэга.

[(0, 'ProductType', 'новый продукт'), (0, 'AgrNum', '1-YYYYYY'), (0, 'AgrDate', '22.07.2014'), (0, 'Account', None), (1, 'INN', '9900000099'), (1, 'Name', 'Компания'), (0, 'User', None), (1, 'FIO', 'Мошкин Сергей Михайлович'), (1, 'Position', 'ANALYST'), (0, 'ListOfCollateral', None), (1, 'Collateral', None), (2, 'CRMId', 'Квартиры'), (2, 'CollType', 'OSNResidential_Real_Estate'), (2, 'AssessType', 'Market'), (2, 'AssessSource', 'Int_Appraiser')]

Полученный список уже можно разносить по таблицам для формирования реляционной БД. Каждый уровень вложения — это новая таблица (наименование столбца — наименование тэга xml, значения в столбце – значения тэга xml). Так, уровень вложения 1 — это новая таблица, она связана с таблицей из данных уровня 0 через ключевое поле (внешний ключ). Каждое последующее вложение — это новая таблица, логика связи с таблицей предыдущего уровня такая же.

Реализация данного проекта позволила еще раз на практике доказать, что многое уже придумали за нас и, прежде чем изобретать что-то новое, нужно максимально использовать прошлый опыт и ранее написанный код.

0
3 комментария
Leha Shum

Проверенные AI решения, ага
🤷‍♀️🤦‍♀️

Ответить
Развернуть ветку
NTA
Автор

Leha, поделитесь, пожалуйста, с чем не согласны. Где-то ошибка/опечатка? Будем признательны

Ответить
Развернуть ветку
Leha Shum

Я имел ввиду что название вашего блога прописано как AI решения.
А в посте две строчки кода

Ответить
Развернуть ветку
0 комментариев
Раскрывать всегда