В течение десятилетий XML был формат доминирования, многие приложения используются для связи друг с другом. В последние годы XML стал менее и менее популярным в качестве формата данных для полуструктурированных случаев данных. Сейчас в современном облачном родном, микросервис приложения JSON или YAML стали нормой. Однако это не изменяет тот факт, что большая часть систем, инструментов и бизнес-процесса все еще на месте. XML – это также формат Defacto «нейтральный» для преобразования конкретных типов файлов в отрасли. Как профессиональный аналитик, способный обрабатывать XML так же легко, как CSV, является обязательным.
В этом посте мы создадим сценарий обработки пакетных данных для типичной лабораторной отчетности. Сценарий, техник, Susian, в конце каждого дня анализирует результаты тестирования отделов. Лабораторное оборудование выводит результаты теста как XML. Susian требует, чтобы XML был преобразован в CSV, чтобы накормить отчет Excel, которую она была предоставлена.
Я буду использовать образец лабораторного измерения-набора данных, который я автоматически генерируется в предыдущем посте здесь.
Содержание
- Обработка данных XML
- Конвертировать XML в CSV
- Шассинг XML: Корневой элемент
- Sharsing XML: элементы первого уровня
- Sharsing XML: подэлементы
- XML Parser Class.
- Пакетное исполнение
- Сохранить преобразованный набор данных
- TL; доктор
Конвертировать XML в CSV
Пример файла XML.
Machine_10 3c0c95f773bf426585a3a68642d2d41a Brett Kerr c/f/a/b Yes 8.63 0.39661 3736 -4.94 0.964363 3182
Целевая структура таблицы
да | 87729203DFCE4E9DA7EFBBB985C83BD9. | 47.81 | 1.878128 | 871 | Machine_03. | Стейси Симпсон | D / A / F | loc_1. |
да | 87729203DFCE4E9DA7EFBBB985C83BD9. | -2.10 | 0.995672 | 4694 | Machine_03. | Стейси Симпсон | D / A / F | loc_2. |
да | 98910CAE86864C3697E6E7FCCFB8CC33. | 2.50 | 0.236024 | 3034 | Machine_03. | Бритни Грей | F / D / A | loc_1. |
Шассинг XML: Корневой элемент
Чтобы обработать анализ XML, мы будем использовать Импорт XML.etreee. Elementtree
упаковка. Ключ к разбору XML является создание класса, представляющего один файл и методы, которые переводят каждый элемент. В примере файла первый элемент для изолята будет каждый Datafile
для Детали
коллекция:
import xml.etree.ElementTree as ET import uuid import pandas as pd import glob
file_path = '/sample-data-set/auto-gen/xml/a8971cf83bd84fd1b366bfb312278021.xml' with open(file_path) as f: tree = ET.parse(f) rootElem = tree.getroot() # Select each DataFile for data_file in rootElem.findall('DataFile'): print(data_file.get('id'))
>>> output: d7ecf46df41f4355a23c42c4607266c7
Sharsing XML: элементы первого уровня
Затем извлеките информацию «заголовка» для каждого теста
file_path = '/sample-data-set/auto-gen/xml/a8971cf83bd84fd1b366bfb312278021.xml' with open(file_path) as f: tree = ET.parse(f) rootElem = tree.getroot() for data_file in rootElem.findall('DataFile'): m_id = data_file.find('machine_id').text test_id = data_file.find('test_id').text tech_id = data_file.find('technician').text test_routine = data_file.find('test_routine').text batched = data_file.find('batched').text header_ar = [m_id, test_id, tech_id, test_routine, batched] print(header_ar)
>>> output: ['Machine_03', '9e0f95807ed44a468271eb6d3ff85a44', 'Jennifer Johnson', 'd', 'N/A']
Sharsing XML: подэлементы
Наконец, извлечь данные измерений для loc_1
и loc_2
file_path = '/sample-data-set/auto-gen/xml/a8971cf83bd84fd1b366bfb312278021.xml' def parse_measurement_location(dataFile, loc_name): res = [] measurement_loc = dataFile.find(loc_name) measurement_loc_id = measurement_loc.tag x_m = measurement_loc.find('x_offset').text y_m = measurement_loc.find('y_offset').text z_m = measurement_loc.find('z_offset').text return [measurement_loc_id,x_m,y_m,z_m] with open(file_path) as f: tree = ET.parse(f) rootElem = tree.getroot() for data_file in rootElem.findall('DataFile'): file_ar = [] m_id = data_file.find('machine_id').text test_id = data_file.find('test_id').text tech_id = data_file.find('technician').text test_routine = data_file.find('test_routine').text batched = data_file.find('batched').text header_ar = [m_id, test_id, tech_id, test_routine, batched] loc_ar = parse_measurement_location(data_file, 'loc_1') file_ar.append(header_ar + loc_ar) loc_ar = parse_measurement_location(data_file, 'loc_2') file_ar.append(header_ar + loc_ar) print(file_ar)
>>> output: [['Machine_03', '9e0f95807ed44a468271eb6d3ff85a44', 'Jennifer Johnson', 'd', 'N/A', 'loc_1', '17.35', '1.3074', '752'], ['Machine_03', '9e0f95807ed44a468271eb6d3ff85a44', 'Jennifer Johnson', 'd', 'N/A', 'loc_2', '2.68', '0.575979', '4483']]
XML Parser Class.
Затем мы помещаем логику преобразования в класс, который можно призвать для любого файла:
# Parsing class class Xml_Parser: def __init__(self): self.ResultAr = [] return def parse_datafiles(self,file_id,rootElem): res = [] for data_file in rootElem.findall('DataFile'): file_ar = self.parse_file(data_file) res += file_ar return res def parse_file(self, data_file): file_ar = [] m_id = data_file.find('machine_id').text test_id = data_file.find('test_id').text tech_id = data_file.find('technician').text test_routine = data_file.find('test_routine').text batched = data_file.find('batched').text header_ar = [m_id, test_id, tech_id, test_routine, batched] loc_ar = self.parse_measurement_location(data_file, 'loc_1') file_ar.append(header_ar + loc_ar) loc_ar = self.parse_measurement_location(data_file, 'loc_2') file_ar.append(header_ar + loc_ar) return file_ar def parse_measurement_location(self, dataFile, loc_name): res = [] measurement_loc = dataFile.find(loc_name) measurement_loc_id = measurement_loc.tag x_m = measurement_loc.find('x_offset').text y_m = measurement_loc.find('y_offset').text z_m = measurement_loc.find('z_offset').text return [measurement_loc_id,x_m,y_m,z_m]
Пакетное исполнение
Чтобы сделать пакетное преобразование на набор файлов, нам понадобится:
- Проанализируйте данный файл, выполнив наш разборщик
- Найти все тестовые файлы
# Conversion executor function def convert_xml_to_list(file_path): with open(file_path) as f: tree = ET.parse(f) root = tree.getroot() parser_obj = Xml_Parser() xml_list = parser_obj.parse_datafiles(f,root) return xml_list
# Batch executor def batch_convert_xml_to_df(xml_dir, dataset_columns,file_limit=-1): i=0 converted_dataset = [] # Recursively convert each target file for filepath in glob.iglob(xml_dir, recursive=True): c_ds = convert_xml_to_list(filepath) converted_dataset+=c_ds i+=1 if (i >= file_limit) and (file_limit>=0): break df = pd.DataFrame(converted_dataset, columns = dataset_columns) return df
Сохранить преобразованный набор данных
Последний шаг – принести все кусочки вместе преобразовывать и сохранить папку XML-файлов в один CSV.
measurement_file_path = '/sample-data-set/auto-gen/xml/*.xml' measurement_columns = ['machine_id','test_id','technician','test_routine','batched','measurement_location_id','x_offset','y_offset','z_offset'] file_process_limit = 20 # Set to -1 for unlimited converted_file_dir = '/sample-data-set/auto-gen/converted' lab_measurement_df = batch_convert_xml_to_df(measurement_file_path, measurement_columns, file_process_limit) # Save dataset to csv using unique name destPath = '/'.join([converted_file_dir,str(uuid.uuid4().hex)]) destPath = '.'.join([destPath,'csv']) lab_measurement_df.to_csv(destPath, index = False, header=True) lab_measurement_df.head()
да | 87729203DFCE4E9DA7EFBBB985C83BD9. | 47.81 | 1.878128 | 871 | 0 | Machine_03. | Стейси Симпсон | D / A / F | loc_1. |
да | 87729203DFCE4E9DA7EFBBB985C83BD9. | -2.10 | 0.995672 | 4694 | 1 | Machine_03. | Стейси Симпсон | D / A / F | loc_2. |
да | 98910CAE86864C3697E6E7FCCFB8CC33. | 2.50 | 0.236024 | 3034 | 2 | Machine_03. | Бритни Грей | F / D / A | loc_1. |
да | 98910CAE86864C3697E6E7FCCFB8CC33. | -13.38 | 0.795762 | 4337 | 3 | Machine_03. | Бритни Грей | F / D / A | loc_2. |
Нет | f505ffc52ad34b56a9f7f95451a813c3. | 44.20 | 1.982816 | 830 | 4 | Machine_03. | Джон Король | C / F / E | loc_1. |
TL; доктор
Полный скрипт здесь
Оригинал: “https://dev.to/darrylbrysondev0/xml-batch-data-processing-4fem”