XML-обработка в Python: библиотеки и методы для эффективной работы

Пройдите тест, узнайте какой профессии подходите
Сколько вам лет
0%
До 18
От 18 до 24
От 25 до 34
От 35 до 44
От 45 до 49
От 50 до 54
Больше 55

Для кого эта статья:

  • Python-разработчики, особенно начинающие и среднего уровня
  • Специалисты, работающие с XML и API
  • Разработчики, заинтересованные в улучшении своих навыков обработки данных

    Обработка XML-документов – навык, который рано или поздно понадобится каждому Python-разработчику. Будь то обмен данными с внешними API, работа с конфигурационными файлами или извлечение информации из структурированных данных – XML встречается повсеместно. Многие начинающие разработчики теряются в разнообразии библиотек и подходов: DOM, SAX, потоковая обработка, древовидные структуры... 🤔 В этой статье я проведу вас через джунгли XML-парсинга в Python, покажу оптимальные инструменты для различных задач и поделюсь реальными примерами кода, которые можно сразу внедрить в свои проекты.

Хотите углубить свои навыки и стать востребованным Python-разработчиком? Курс Python-разработки от Skypro даст вам не только фундаментальные знания, но и практический опыт работы с XML и другими форматами данных. Вы научитесь создавать эффективные веб-приложения с нуля, работать с API и базами данных. Наши выпускники трудоустраиваются уже через 8 месяцев обучения – инвестируйте в своё будущее прямо сейчас!

XML в Python: основные библиотеки и их возможности

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

Библиотека Тип парсера Производительность Удобство использования Особенности
ElementTree DOM Высокая Простой API Встроен в стандартную библиотеку
minidom DOM Средняя Соответствие W3C DOM API Встроен в стандартную библиотеку
lxml DOM/SAX Очень высокая ElementTree-совместимый API Поддержка XPath, XSLT, валидация схем
SAX Событийный Высокая для больших файлов Сложный API Низкое потребление памяти
Beautifulsoup4 DOM Низкая Очень простой API Устойчивость к ошибкам в разметке

Выбор библиотеки зависит от нескольких факторов:

  • Размер данных: для гигантских XML-файлов событийные парсеры (SAX) или потоковые (iterparse в ElementTree) будут предпочтительнее DOM-парсеров, загружающих весь документ в память.
  • Сложность обработки: если требуется выполнять XPath-запросы или XSLT-преобразования, lxml будет оптимальным выбором.
  • Производительность: lxml обычно в 10-100 раз быстрее встроенных парсеров благодаря использованию библиотек libxml2 и libxslt, написанных на C.
  • Совместимость: для кода, который должен работать без внешних зависимостей, стоит выбирать встроенные библиотеки (ElementTree или minidom).

Александр Петров, Senior Python Developer

Однажды я получил задачу обработать XML-файл с историческими данными биржевых котировок. Размер файла превышал 5 ГБ, и первая попытка загрузить его через ElementTree привела к исчерпанию оперативной памяти. Я перепробовал все стандартные методы, но каждый раз сталкивался с OOM-ошибками.

Решение пришло, когда я применил комбинированный подход: использовал итеративный парсинг через ElementTree.iterparse() для последовательного чтения файла и обрабатывал каждый элемент сразу после его чтения, очищая память. Ключевым трюком стало не только извлечение данных, но и явное удаление обработанных элементов из дерева:

Python
Скопировать код
for _, element in etree.iterparse(huge_xml_file, events=('end',), tag='QUOTE'):
process_data(element)
element.clear()
# Освобождаем ссылки на удаленные элементы
while element.getprevious() is not None:
del element.getparent()[0]

Эта техника позволила обработать файл с постоянным потреблением памяти менее 200 МБ, что на порядки эффективнее прямолинейных подходов.

Пошаговый план для смены профессии

ElementTree: быстрый и эффективный парсинг XML

ElementTree — это встроенная в стандартную библиотеку Python библиотека, которая представляет XML-документ как древовидную структуру. Она сочетает производительность и удобство использования, что делает её отличным выбором для большинства задач по обработке XML.

Основные преимущества ElementTree:

  • Простой и интуитивно понятный API
  • Достаточная производительность для большинства задач
  • Встроенная поддержка в Python (не требует установки дополнительных пакетов)
  • Возможность итеративной обработки для больших XML-файлов

Рассмотрим базовые операции с ElementTree на примерах. Допустим, у нас есть файл users.xml:

xml
Скопировать код
<users>
<user id="1">
<name>John Doe</name>
<email>john@example.com</email>
<roles>
<role>admin</role>
<role>developer</role>
</roles>
</user>
<user id="2">
<name>Jane Smith</name>
<email>jane@example.com</email>
<roles>
<role>developer</role>
</roles>
</user>
</users>

Базовое чтение XML-файла с помощью ElementTree:

Python
Скопировать код
import xml.etree.ElementTree as ET

# Загрузка из файла
tree = ET.parse('users.xml')
root = tree.getroot()

# Или из строки
xml_string = '''<users>...</users>'''
root = ET.fromstring(xml_string)

# Перебор всех элементов user
for user in root.findall('user'):
user_id = user.get('id')
name = user.find('name').text
email = user.find('email').text

print(f"User {user_id}: {name}, {email}")

# Получение вложенных элементов
roles = [role.text for role in user.findall('./roles/role')]
print(f"Roles: {', '.join(roles)}")

ElementTree предлагает несколько методов для поиска элементов:

  • element.find(path) – находит первый дочерний элемент, соответствующий пути
  • element.findall(path) – находит все соответствующие элементы
  • element.findtext(path) – находит текст первого соответствующего элемента

Путь может содержать ограниченный набор XPath-выражений:

Python
Скопировать код
# Получить всех пользователей с ролью admin
admin_users = []
for user in root.findall('.//user'):
roles = [role.text for role in user.findall('./roles/role')]
if 'admin' in roles:
admin_users.append(user.find('name').text)

print(f"Administrators: {', '.join(admin_users)}")

Создание и модификация XML с ElementTree:

Python
Скопировать код
# Создание нового документа
root = ET.Element('users')
user = ET.SubElement(root, 'user', {'id': '3'})
ET.SubElement(user, 'name').text = 'Bob Johnson'
ET.SubElement(user, 'email').text = 'bob@example.com'
roles = ET.SubElement(user, 'roles')
ET.SubElement(roles, 'role').text = 'tester'

# Запись в файл
tree = ET.ElementTree(root)
tree.write('new_users.xml', encoding='utf-8', xml_declaration=True)

Для больших XML-файлов рекомендуется использовать итеративный подход:

Python
Скопировать код
# Обработка большого файла с минимальным использованием памяти
for event, elem in ET.iterparse('huge_file.xml', events=('end',)):
if elem.tag == 'user':
process_user(elem)
elem.clear() # Освобождаем память

ElementTree — это сбалансированный инструмент, подходящий для большинства задач по работе с XML. Однако, для более сложных операций, таких как выполнение полноценных XPath-запросов или XSLT-преобразований, может потребоваться более мощная библиотека, такая как lxml.

Работа с XML через minidom: особенности и применение

Библиотека minidom представляет собой легковесную реализацию DOM (Document Object Model) API в Python. Она является частью встроенного модуля xml.dom и предоставляет более традиционный подход к работе с XML-документами в соответствии со спецификациями W3C.

Minidom может быть предпочтительным выбором в следующих случаях:

  • Когда требуется строгое соответствие DOM API (например, для совместимости с существующим кодом)
  • При работе с небольшими XML-документами, где удобство использования важнее производительности
  • Когда необходимо сохранить форматирование и комментарии в XML

Дмитрий Соколов, Python Team Lead

В одном из проектов мне пришлось интегрировать Python-код с устаревшей системой, работающей с XML через строгий DOM-интерфейс. Большинство современных библиотек не подходили из-за несоответствия API.

Изначально я пытался использовать ElementTree и адаптировать его результаты к ожидаемому формату, но это приводило к ошибкам и потере данных. После нескольких дней борьбы я обратился к minidom:

Python
Скопировать код
from xml.dom import minidom

# Загружаем документ
doc = minidom.parse('legacy_data.xml')

# Работаем напрямую через DOM API
elements = doc.getElementsByTagName('record')
for element in elements:
id_attr = element.getAttribute('id')
name_node = element.getElementsByTagName('name')[0]
name_text = name_node.firstChild.nodeValue

# Модификация данных в DOM-стиле
if some_condition:
new_node = doc.createElement('status')
text = doc.createTextNode('active')
new_node.appendChild(text)
element.appendChild(new_node)

Этот подход позволил сохранить все тонкости исходного XML-формата: комментарии, порядок атрибутов, пространства имён — всё то, что обычно "сглаживается" более высокоуровневыми библиотеками. Несмотря на более многословный код, интеграция прошла безупречно.

Базовые операции с minidom:

Python
Скопировать код
from xml.dom import minidom

# Разбор XML из файла
doc = minidom.parse('users.xml')

# Или из строки
xml_string = '''<users>...</users>'''
doc = minidom.parseString(xml_string)

# Получение элементов по тегу
users = doc.getElementsByTagName('user')
for user in users:
# Получение атрибута
user_id = user.getAttribute('id')

# Получение текста элемента
name = user.getElementsByTagName('name')[0].firstChild.nodeValue
email = user.getElementsByTagName('email')[0].firstChild.nodeValue

print(f"User {user_id}: {name}, {email}")

# Получение вложенных элементов
roles_elem = user.getElementsByTagName('roles')[0]
role_elems = roles_elem.getElementsByTagName('role')
roles = [role.firstChild.nodeValue for role in role_elems]
print(f"Roles: {', '.join(roles)}")

Создание и модификация XML с minidom:

Python
Скопировать код
# Создание нового документа
doc = minidom.getDOMImplementation().createDocument(None, "users", None)
root = doc.documentElement

# Создание элемента user
user = doc.createElement('user')
user.setAttribute('id', '3')
root.appendChild(user)

# Добавление дочерних элементов
name = doc.createElement('name')
name_text = doc.createTextNode('Bob Johnson')
name.appendChild(name_text)
user.appendChild(name)

email = doc.createElement('email')
email_text = doc.createTextNode('bob@example.com')
email.appendChild(email_text)
user.appendChild(email)

# Создание ещё одного уровня вложенности
roles = doc.createElement('roles')
user.appendChild(roles)
role = doc.createElement('role')
role_text = doc.createTextNode('tester')
role.appendChild(role_text)
roles.appendChild(role)

# Сохранение с отступами
xml_str = doc.toprettyxml(indent=" ")
with open('new_users.xml', 'w') as f:
f.write(xml_str)

Операция ElementTree minidom
Загрузка из файла ET.parse('file.xml') minidom.parse('file.xml')
Загрузка из строки ET.fromstring(xml_string) minidom.parseString(xml_string)
Получение элементов root.findall('element') doc.getElementsByTagName('element')
Получение атрибута element.get('attr') element.getAttribute('attr')
Получение текста element.text element.firstChild.nodeValue
Создание элемента ET.SubElement(parent, 'tag') doc.createElement('tag')<br>parent.appendChild(element)
Запись в файл tree.write('file.xml') f.write(doc.toprettyxml())

Основные недостатки minidom:

  • Более многословный и менее интуитивный API по сравнению с ElementTree
  • Более низкая производительность, особенно для больших документов
  • Отсутствие поддержки XPath и других продвинутых функций
  • Более высокое потребление памяти для крупных XML-файлов

Несмотря на эти недостатки, minidom остаётся полезным инструментом, особенно в ситуациях, где важна совместимость с DOM API или необходимо точное сохранение структуры XML, включая комментарии и форматирование. 🔄

Мощь lxml: продвинутые методы обработки XML-документов

Библиотека lxml — это мощный инструмент для обработки XML, который объединяет скорость и функциональность библиотек libxml2 и libxslt, написанных на C, с удобством Python API. Это делает lxml одним из самых быстрых и функциональных XML-парсеров для Python. 🚀

Ключевые преимущества lxml:

  • Высокая производительность (в 10-100 раз быстрее встроенных парсеров)
  • Полная поддержка XPath 1.0
  • Встроенная поддержка XSLT-трансформаций
  • Валидация XML через DTD, XML Schema, Relax NG
  • API, совместимый с ElementTree, что облегчает миграцию
  • Устойчивость к ошибкам в XML через lxml.html
  • Поддержка инкрементального парсинга больших файлов

Установка lxml:

Bash
Скопировать код
pip install lxml

Базовые операции с lxml:

Python
Скопировать код
from lxml import etree

# Разбор из файла
tree = etree.parse('users.xml')
root = tree.getroot()

# Или из строки
xml_string = '''<users>...</users>'''
root = etree.fromstring(xml_string)

# Работа как с ElementTree
for user in root.findall('user'):
user_id = user.get('id')
name = user.find('name').text
email = user.find('email').text
print(f"User {user_id}: {name}, {email}")

Где lxml действительно выделяется, так это в поддержке полноценного XPath. В отличие от ограниченной реализации XPath в ElementTree, lxml поддерживает полный стандарт XPath 1.0, включая функции, предикаты и сложные выражения:

Python
Скопировать код
# Использование полноценного XPath
# Найти всех пользователей с ролью 'admin'
admin_users = root.xpath('//user[roles/role="admin"]')
for user in admin_users:
print(f"Admin user: {user.find('name').text}")

# Выбор атрибутов через XPath
all_user_ids = root.xpath('//user/@id')
print(f"User IDs: {all_user_ids}")

# Комбинирование условий
developers_with_email = root.xpath('//user[roles/role="developer" and contains(email, "@example.com")]')
print(f"Found {len(developers_with_email)} developers with example.com email")

# Использование функций XPath
first_user_name = root.xpath('string(//user[1]/name)')
user_count = root.xpath('count(//user)')
print(f"First user: {first_user_name}, Total users: {int(user_count)}")

lxml также предлагает мощные возможности для модификации XML-документов:

Python
Скопировать код
# Добавление нового элемента
new_user = etree.SubElement(root, 'user', id='4')
etree.SubElement(new_user, 'name').text = 'Alice Cooper'
etree.SubElement(new_user, 'email').text = 'alice@example.com'
roles = etree.SubElement(new_user, 'roles')
etree.SubElement(roles, 'role').text = 'manager'

# Модификация существующих элементов
for user in root.xpath('//user[roles/role="developer"]'):
# Добавляем новую роль для разработчиков
roles = user.find('roles')
new_role = etree.SubElement(roles, 'role')
new_role.text = 'coder'

# Удаление элементов
for old_role in root.xpath('//role[text()="developer"]'):
parent = old_role.getparent()
parent.remove(old_role)

# Запись с красивым форматированием
tree = etree.ElementTree(root)
tree.write('modified_users.xml', pretty_print=True, encoding='utf-8', xml_declaration=True)

XSLT-трансформации — ещё одна мощная возможность lxml:

Python
Скопировать код
# Определение XSLT-преобразования
xslt_string = '''
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>

<xsl:template match="/">
<html>
<body>
<h1>User List</h1>
<table border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Roles</th>
</tr>
<xsl:for-each select="users/user">
<tr>
<td><xsl:value-of select="@id"/></td>
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="email"/></td>
<td>
<xsl:for-each select="roles/role">
<xsl:value-of select="."/>
<xsl:if test="position() != last()">, </xsl:if>
</xsl:for-each>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
'''

# Создание XSLT-преобразователя
xslt_root = etree.XML(xslt_string)
transform = etree.XSLT(xslt_root)

# Применение преобразования
result = transform(tree)

# Сохранение результата
with open('users.html', 'wb') as f:
f.write(etree.tostring(result, pretty_print=True))

Валидация XML с использованием схем — ещё одна важная функция lxml:

Python
Скопировать код
# XML Schema валидация
schema_str = '''
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="users">
<xs:complexType>
<xs:sequence>
<xs:element name="user" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="email" type="xs:string"/>
<xs:element name="roles">
<xs:complexType>
<xs:sequence>
<xs:element name="role" type="xs:string" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="id" type="xs:positiveInteger" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
'''

schema_root = etree.XML(schema_str)
schema = etree.XMLSchema(schema_root)

# Проверка документа на соответствие схеме
try:
schema.assertValid(tree)
print("Document is valid")
except etree.DocumentInvalid as err:
print(f"Document is invalid: {err}")

lxml также эффективно обрабатывает большие XML-файлы через итеративный парсинг:

Python
Скопировать код
# Обработка большого XML-файла с минимальным использованием памяти
for event, element in etree.iterparse('huge_file.xml', events=('end',), tag='user'):
# Обработка каждого пользователя
process_user(element)

# Очистка памяти
element.clear()
while element.getprevious() is not None:
del element.getparent()[0]

lxml — это невероятно мощная библиотека, которая сочетает высокую производительность с богатым набором возможностей. Если ваш проект требует серьезной работы с XML, включая XPath-запросы, XSLT-преобразования или валидацию схем, lxml является оптимальным выбором. 💪

Практические задачи: от чтения до модификации XML в Python

Для закрепления материала рассмотрим несколько практических задач, с которыми часто сталкиваются разработчики при работе с XML. Эти примеры демонстрируют применение различных библиотек и подходов в реальных сценариях. 📊

Задача 1: Чтение и анализ конфигурационного XML-файла

Предположим, у нас есть конфигурационный файл приложения в формате XML:

xml
Скопировать код
<?xml version="1.0" encoding="UTF-8"?>
<config>
<database>
<host>localhost</host>
<port>3306</port>
<name>myapp_db</name>
<user>app_user</user>
<password>s3cr3t</password>
</database>
<api>
<endpoint>https://api.example.com/v1</endpoint>
<timeout>30</timeout>
<retry>3</retry>
</api>
<logging>
<level>INFO</level>
<path>/var/log/myapp.log</path>
<max_size>10485760</max_size>
<backups>5</backups>
</logging>
</config>

Решение с использованием ElementTree:

Python
Скопировать код
import xml.etree.ElementTree as ET
import os

def load_config(config_path):
"""Загружает конфигурацию из XML-файла в словарь Python."""
if not os.path.exists(config_path):
raise FileNotFoundError(f"Config file not found: {config_path}")

tree = ET.parse(config_path)
root = tree.getroot()

config = {}

# Обработка секции database
db = root.find('database')
if db is not None:
config['database'] = {
'host': db.findtext('host', 'localhost'),
'port': int(db.findtext('port', '3306')),
'name': db.findtext('name', 'default_db'),
'user': db.findtext('user', ''),
'password': db.findtext('password', '')
}

# Обработка секции api
api = root.find('api')
if api is not None:
config['api'] = {
'endpoint': api.findtext('endpoint', ''),
'timeout': int(api.findtext('timeout', '60')),
'retry': int(api.findtext('retry', '3'))
}

# Обработка секции logging
logging = root.find('logging')
if logging is not None:
config['logging'] = {
'level': logging.findtext('level', 'INFO'),
'path': logging.findtext('path', './app.log'),
'max_size': int(logging.findtext('max_size', '1048576')),
'backups': int(logging.findtext('backups', '3'))
}

return config

# Использование
try:
app_config = load_config('config.xml')
print(f"Database connection: {app_config['database']['user']}@{app_config['database']['host']}")
print(f"API endpoint: {app_config['api']['endpoint']}")
print(f"Log level: {app_config['logging']['level']}")
except Exception as e:
print(f"Error loading config: {e}")

Задача 2: Преобразование данных из CSV в XML

Часто требуется конвертировать данные из одного формата в другой. Рассмотрим пример преобразования CSV-файла в XML:

Python
Скопировать код
import csv
import xml.etree.ElementTree as ET
from xml.dom import minidom

def csv_to_xml(csv_file, xml_file, root_element='data', row_element='item'):
"""Преобразует CSV-файл в XML."""
# Чтение CSV
with open(csv_file, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)

# Создание корневого элемента XML
root = ET.Element(root_element)

# Обработка каждой строки CSV
for row in reader:
# Создание элемента для строки
item = ET.SubElement(root, row_element)

# Добавление всех полей из строки CSV как атрибуты или вложенные элементы
for field, value in row.items():
# Заменяем проблемные символы в именах полей
field_name = ''.join(c if c.isalnum() else '_' for c in field)

# Создаём элемент для каждого поля
field_elem = ET.SubElement(item, field_name)
field_elem.text = value

# Преобразование в строку с отступами
xml_str = minidom.parseString(ET.tostring(root)).toprettyxml(indent=" ")

# Запись в файл
with open(xml_file, 'w', encoding='utf-8') as out:
out.write(xml_str)

return True

# Пример использования
try:
result = csv_to_xml('employees.csv', 'employees.xml', 'employees', 'employee')
print(f"Conversion {'successful' if result else 'failed'}")
except Exception as e:
print(f"Error during conversion: {e}")

Задача 3: Извлечение данных из XML с использованием XPath

Предположим, у нас есть XML с данными о книгах в библиотеке, и нам нужно извлечь определённую информацию. Здесь пригодится lxml с его поддержкой XPath:

Python
Скопировать код
from lxml import etree

def extract_books_info(xml_file, author=None, category=None, min_year=None):
"""
Извлекает информацию о книгах с применением фильтров.
Возвращает список словарей с данными о книгах.
"""
tree = etree.parse(xml_file)
root = tree.getroot()

# Построение XPath-запроса на основе фильтров
xpath_query = "//book"
conditions = []

if author:
conditions.append(f"author[contains(text(), '{author}')]")
if category:
conditions.append(f"@category='{category}'")
if min_year:
conditions.append(f"year >= {min_year}")

if conditions:
xpath_query += "[" + " and ".join(conditions) + "]"

# Выполнение запроса
books = root.xpath(xpath_query)

# Сбор результатов
results = []
for book in books:
book_info = {
'id': book.get('id'),
'title': book.findtext('title', ''),
'author': book.findtext('author', ''),
'year': int(book.findtext('year', '0')),
'price': float(book.findtext('price', '0')),
'category': book.get('category', '')
}
results.append(book_info)

return results

# Использование
try:
# Поиск книг по фантастике после 2000 года
sci_fi_books = extract_books_info('library.xml', category='sci-fi', min_year=2000)

print(f"Found {len(sci_fi_books)} sci-fi books published after 2000:")
for book in sci_fi_books:
print(f"- {book['title']} by {book['author']} ({book['year']})")

# Поиск книг определённого автора
author_books = extract_books_info('library.xml', author='Tolkien')
print(f"\nFound {len(author_books)} books by Tolkien:")
for book in author_books:
print(f"- {book['title']} ({book['year']}) – ${book['price']}")

except Exception as e:
print(f"Error processing books: {e}")

Задача 4: Модификация существующего XML-документа

Рассмотрим пример, где нам нужно обновить XML-документ с данными о сотрудниках:

Python
Скопировать код
import xml.etree.ElementTree as ET

def update_employee_data(xml_file, employee_id, updates):
"""
Обновляет информацию о сотруднике в XML-файле.

Args:
xml_file: путь к XML-файлу
employee_id: ID сотрудника для обновления
updates: словарь с обновляемыми полями

Returns:
bool: True если обновление успешно, False если сотрудник не найден
"""
tree = ET.parse(xml_file)
root = tree.getroot()

# Поиск сотрудника по ID
employee = root.find(f".//employee[@id='{employee_id}']")
if employee is None:
return False

# Обновление полей
for field, value in updates.items():
# Проверяем, существует ли такой элемент
field_elem = employee.find(field)
if field_elem is not None:
# Обновляем существующий элемент
field_elem.text = str(value)
else:
# Создаём новый элемент
new_field = ET.SubElement(employee, field)
new_field.text = str(value)

# Сохраняем изменения
tree.write(xml_file, encoding='utf-8', xml_declaration=True)
return True

# Пример использования
try:
updates = {
'position': 'Senior Developer',
'salary': '75000',
'department': 'Engineering'
}

success = update_employee_data('employees.xml', '1001', updates)
if success:
print("Employee information updated successfully")
else:
print("Employee not found")

except Exception as e:
print(f"Error updating employee data: {e}")

Задача 5: Генерация отчёта в формате HTML на основе XML-данных

Часто XML используется как промежуточный формат данных, которые затем преобразуются в более удобный для конечного пользователя вид. Рассмотрим пример генерации HTML-отчёта:

Python
Скопировать код
from lxml import etree

def generate_sales_report(xml_file, output_html):
"""Генерирует HTML-отчёт о продажах на основе XML-данных."""
# XSLT-шаблон для преобразования
xslt_str = '''
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" encoding="UTF-8"/>

<xsl:template match="/">
<html>
<head>
<title>Sales Report</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
h1 { color: #2c3e50; }
table { border-collapse: collapse; width: 100%; margin-top: 20px; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
tr:nth-child(even) { background-color: #f9f9f9; }
.total { font-weight: bold; background-color: #e9f7ef; }
</style>
</head>
<body>
<h1>Sales Report</h1>

<h2>Summary</h2>
<p>Period: <xsl:value-of select="sales/@period"/></p>
<p>Total Sales: $<xsl:value-of select="format-number(sum(//sale/amount), '#,##0.00')"/></p>
<p>Number of Transactions: <xsl:value-of select="count(//sale)"/></p>

<h2>Sales by Product</h2>
<table>
<tr>
<th>Product</th>
<th>Total Units</th>
<th>Total Amount</th>
</tr>
<xsl:for-each select="//product[not(@name=preceding::product/@name)]/@name">
<xsl:variable name="product_name" select="."/>
<tr>
<td><xsl:value-of select="$product_name"/></td>
<td><xsl:value-of select="sum(//sale[product/@name=$product_name]/quantity)"/></td>
<td>$<xsl:value-of select="format-number(sum(//sale[product/@name=$product_name]/amount), '#,##0.00')"/></td>
</tr>
</xsl:for-each>
<tr class="total">
<td>Total</td>
<td><xsl:value-of select="sum(//quantity)"/></td>
<td>$<xsl:value-of select="format-number(sum(//amount), '#,##0.00')"/></td>
</tr>
</table>

<h2>Detailed Sales</h2>
<table>
<tr>
<th>Date</th>
<th>Customer</th>
<th>Product</th>
<th>Quantity</th>
<th>Amount</th>
</tr>
<xsl:for-each select="//sale">
<xsl:sort select="date" order="descending"/>
<tr>
<td><xsl:value-of select="date"/></td>
<td><xsl:value-of select="customer"/></td>
<td><xsl:value-of select="product/@name"/></td>
<td><xsl:value-of select="quantity"/></td>
<td>$<xsl:value-of select="format-number(amount, '#,##0.00')"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
'''

try:
# Загружаем XML и XSLT
xml_doc = etree.parse(xml_file)
xslt_doc = etree.fromstring(xslt_str)
transform = etree.XSLT(xslt_doc)

# Применяем трансформацию
result = transform(xml_doc)

# Сохраняем результат
with open(output_html, 'wb') as f:
f.write(etree.tostring(result, pretty_print=True, method='html', encoding='utf-8'))

return True
except Exception as e:
print(f"Error generating report: {e}")
return False

# Пример использования
if generate_sales_report('sales_data.xml', 'sales_report.html'):
print("Sales report generated successfully!")
else:
print("Failed to generate sales report")

Эти практические примеры демонстрируют, как Python-библиотеки для работы с XML могут применяться для решения разнообразных задач — от простого чтения конфигураций до сложного анализа данных и генерации отчётов. 🔍

Python предлагает богатый арсенал инструментов для работы с XML, подходящих для любой задачи. ElementTree подойдет для повседневных операций благодаря своей простоте и интеграции со стандартной библиотекой. Minidom незаменим при необходимости строгого соответствия DOM-спецификации. А lxml станет выбором профессионалов для высокопроизводительной обработки больших XML-документов с поддержкой XPath и XSLT. Главное — правильно оценить масштаб задачи и выбрать библиотеку, которая обеспечит баланс между удобством разработки и эффективностью исполнения. Вооружившись этими знаниями, вы превратите работу с XML из рутинной задачи в мощный инструмент решения бизнес-задач.

Загрузка...