10. Обработка XPath¶
Одним из наиболее важных преимуществ пакета lxml над другими пакетами в стиле ElementTree является поддержка полного языка XPath. Выражения XPath дают вам гораздо более мощный механизм для выбора и извлечения частей документа по сравнению с относительно простым синтаксисом «path», используемым в разделе 8.1. ElementTree.find().
Если вы не знакомы с XPath, см. Эти источники:
- XSLT reference, в частности раздел «Ссылка XPath».
- Стандарт XML Path Language (XPath), Version 1.0.
Имейте в виду, что каждое выражение XPath оценивается с использованием трех элементов контекста:
- Контекстный узел является отправной точкой для любых операций, значение которых относительно некоторой точки в дереве.
- Размер контекста - это число элементов, которые являются дочерними элементами родительского узла контекста, то есть узлом контекста и всеми его братьями и сестрами.
- Позиция контекста - это позиция контекстного узла относительно его братьев и сестер, считая первого брата как позицию 1.
Вы можете оценить выражение XPath с помощью метода .xpath(s) на экземпляре Element или экземпляре ElementTree. См. Раздел 9.21. Element.xpath(): оценка выражения XPath и раздел 8.6. ElementTree.xpath(): оценить выражение XPath.
В зависимости от используемого выражения XPath эти методы .xpath() могут возвращать один из нескольких значений:
- Для выражений, возвращающих логическое значение, метод .xpath() возвращает True или False.
- Выражения с числовым результатом всегда возвращают тип float.
- Выражения со строковым результатом возвращают строку (string) Python или строку unicode.
- Выражения, которые производят список значений, таких как узлы, возвращают список Python. Элементами этого списка могут быть, в свою очередь, любой из нескольких типов:
- Элементы, комментарии и инструкции по обработке будут представлены как экземпляры элементов lxml, Comment и ProcessingInstruction.
- Текстовый контент и значения атрибутов возвращаются в виде экземпляров Python str (string).
- Объявления пространства имен возвращаются как два кортежа (префикс, namespaceURI).
Для получения дополнительной информации о функциях XPath от lxml см. XML Path Language (XPath).
10.1. Пример XPath¶
Ниже приведен пример ситуации, когда выражение XPath поможет вам сократить много работы. Предположим, у вас есть документ с элементом, который называется para, который представляет абзац текста. Далее предположим, что ваш para имеет модель смешанного контента, поэтому ее содержимое представляет собой бесплатную смесь текста и несколько видов встроенной разметки. Однако ваше приложение должно извлекать только текст в абзаце, отбрасывая все теги.
Используя только классический интерфейс ElementTree, вам потребуется написать какую-то функцию, которая рекурсивно перемещает элемент para и его поддерево, извлекает атрибуты .text и .tail на каждом уровне и в конечном итоге склеивает их все вместе.
Тем не менее, существует относительно простое выражение XPath, которое делает все это для вас:
descendant-or-self::text()
«Descendant-or-self ::» - это селектор оси, который ограничивает поиск узлом контекста, его дочерними элементами, их дочерними элементами и т. д. к листьям дерева. Функция «text()» выбирает только текстовые узлы, отбрасывая любые элементы, комментарии и другое нетекстовое содержимое. Возвращаемое значение представляет собой список строк.
Вот пример этого выражения на практике.
>>> node=etree.fromstring('''<a>
... a-text <b>b-text</b> b-tail <c>c-text</c> c-tail
... </a>''')
>>> alltext = node.xpath('descendant-or-self::text()')
>>> alltext
['\n a-text ', 'b-text', ' b-tail ', 'c-text', ' c-tail\n']
>>> clump = "".join(alltext)
>>> clump
'\n a-text b-text b-tail c-text c-tail\n'
>>>