Парсинг XML с использованием lxml

автор

Ранее мы рассматривали некоторые встроенные в Python XML парсеры. В этой статье, мы рассмотрим один интересный сторонний пакет lxml от codespeak. Он, в частности, использует API ElementTree. Пакет lxml имеет поддержку XPath и XSLT, включая API для SAX и API уровня С для совместимости с модулями C/Pyrex. В статье мы рассмотрим следующее:

  • Парсинг XML используя lxml
  • Пример рефакторинга
  • Как выполнять парсинг XML с lxml.objectify
  • Как создавать XML с lxml.objectify

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

Давайте посмотрим, как происходит парсинг с использованием lxml.

Парсинг XML с lxml

Данный пример XML показывает два назначения. Время начинается спустя секунды после эпохи. Наш uid сгенерирован на основе хеша начала времени и ключа. Время сигнала – несколько секунд после эпохи, но не раньше начала времени. Состояние – если назначение было отменено или перенесено, или нет, так или иначе. Остальная часть XML, как мы видим, в пояснении не нуждается. Давайте взглянем на то, как делается парсинг:

Во первых, мы импортировали необходимые модули, а именно модуль etree из пакета lxml Python и функцию StringIO из встроенного модуля StringIO. Наша функция parseXML принимает один аргумент: путь к рассматриваемому файлу XML. Мы открываем файл, читаем и закрываем его. Теперь начинается самое веселое. Мы используем функцию парсинга etree, чтобы парсировать код XML, который вернулся из модуля StringIO. По причинам, которые я не могу полностью понять, функция парсинга требует файловый объект. В любом случае, мы итерируем контекст (другими словами, объект lxml.etree.iterparse) и извлекаем теговые элементы. Далее, мы добавляем условный оператор if, для замещения пустых полей словом “None” для получения более чистой выдачи.

Парсинг на примере книги

Что-ж, результат нашего примера немного скучный. Большую часть времени, вам нужно будет сохранить извлеченные данные, и сделать с ними что-нибудь, а не просто вывести его в stdout. Так что в следующем нашем примере мы создадим структуру данных для сбора результатов. В данном примере структура наших данных будет представлять собой список словарей. Мы используем пример книги MSDN. Сохраните следующий код XML под названием example.xml.

Теперь мы выполним парсинг данного XML и вставим его в нашу структуру данных!

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

Текст может быть как elem.text так и None. Наконец, если тег окажется книгой, тогда мы в конце книжной секции, и нам нужно добавить словарь в наш список, а также сбросить словарь для следующей книги. Как мы видим, это именно то, что мы сделали. Более реалистичным примером будет размещение извлеченных данных в Python класс Book. Ранее я делал последнее с json feeds. Теперь мы готовы к тому, чтобы приступить к парсингу XML с lxml.objectify!

Парсинг XML с lxml.objectify

Модуль lxml содержит модуль, под названием objectify, который превращает документы XML в объекты Python. Для меня данная возможность оказалась весьма кстати во время работы, надеюсь, вам она тоже пригодиться. Вам может понадобиться немного помучаться при его установке, так как pip не работает с lxml в Windows. Обязательно перейдите в Индекс пакетов Python (https://pypi.python.org/pypi) и поищите версию, которая была разработана под вашу версию Python.

Установка lxml: http://lxml.de/installation.html

В любом случае, после установки, мы можем начать исследовать это чудесный кусок XML снова:

Теперь нам нужно написать код, который может выполнять парсинг и модифицировать XML. Давайте взглянем на это небольшое демо, которое показывает кучу чудесных возможностей, которые нам дает objectify.

Данный код детально прокомментирован, но мы потратим немного времени на том, чтобы исключить все недопонимания. В начале, мы передали наш пример файла XML и использовали objectify. Если вам нужно получить доступ к атрибутам тега, используйте свойство attrib. Оно вернет словарь атрибутов тега. Для доступа к под-теговым элементам, вам нужно использовать точечную нотацию. Как вы видите, для того, чтобы попасть к началу значения тега, мы можем просто сделать что-то на подобии этого:

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

Если вам нужно выполнить итерацию над дочерними элементами, вы можете использовать метод iterchildren. Возможно, вам придется использовать вложенную структуру цикла for, чтобы получить все необходимое. Изменение значения элемента это также просто, как присвоение ему нового значения.

Теперь мы готовы к тому, чтобы перейти к созданию XML при помощи lxml.objectify.

Создание XML при помощи lxml.objectify

Субпакет lxml.objectify очень удобный инструмент для парсинга и создания XML. В данном разделе мы рассмотрим, как создавать XML при помощи модуля lxml.objectify. Мы начнем с примера простого XML кода и попробуем копировать его. Приступим!

Мы будем использовать следующий XML в качестве нашего примера:

Давайте посмотрим, как мы будем использовать lxml.objectify для воссоздания XML:

Давайте немного разъясним код. Мы начнем с функции create_xml. В ней мы создаем корневой объект XML при помощи функции fromstring модуля objectify. Корневой объект будет содержать zAppointment в качестве его тега. Мы настроим корневой атрибут напоминания, после чего вызовем нашу функцию create_appt, используя словарь Python для её аргумента. В функции create_appt мы создаем экземпляр Element (технически, ObjectifiedElement), который мы назначаем нашей переменной apt. Здесь мы используем точечную нотацию для создания тегов для данного элемента. Наконец, мы возвращаем элемент appt назад и присоединяем его к нашему объекту root. Мы повторяем процесс для второго экземпляра назначения. Следующая секция функции create_xml удалит аннотацию lxml. Если этого не сделать, ваш XML будет выглядеть следующим образом:

Для удаления всех ненужных аннотаций, мы можем вызвать две следующие функции:

  1. objectify.deannotate(root)
  2. etree.cleanup_namespaces(root)

Последняя часть головоломки заключается в том, чтобы позволить lxml генерировать XML самостоятельно. Для этого мы используем модуль lxml etree, чтобы выполнить эту непростую задачу.

Функция tostring возвращает опрятную строку XML, и если вы установите pretty_print на True, это также вернет XML в приемлемом формате. Аргумент ключа xml_declaration указывает модулю etree включать или убирать первую строку декларации (другими словами, ).

Подведем итоги

Теперь вы знаете, как использовать модуль lxml etree и модули objectify для парсинга XML. Вы также научились использовать objectify для создания XML. Навыки использования более одного модуля для решения одной задачи может быть очень полезным, если нужно взглянуть на проблему под разными углами. Также это позволит вам понять, какой нужно выбрать инструмент для решения проблемы.

Вам может быть интересно

Scroll Up