7. Особенности модуля etree

etree содержит множество функций и конструкторов классов.

7.1. Конструктор Comment()

Чтобы создать узел комментариев, используйте этот конструктор:

etree.Comment(text=None)
text
Текст, который будет помещен в комментарий. После сериализации в формате XML этому тексту будет предшествовать «<! -», а затем «->».

Возвращаемое значение является экземпляром класса Comment. Используйте метод .append() для родительского элемента, чтобы поместить комментарий в ваш документ.

Например, предположим, что bodyElt является элементом HTML. Чтобы добавить комментарий к этому элементу, содержащему строку s, вы должны использовать этот код:

newComment = etree.Comment(s)
bodyElt.append(newComment)

7.2. Конструктор Element()

Этот конструктор создает и возвращает новый экземпляр Element.

etree.Element(tag, attrib={}, nsmap=None, **extras)
tag
Строка, содержащая имя создаваемого элемента.
attrib
Словарь, содержащий имена и значения атрибутов, которые необходимо добавить в элемент. Значение по умолчанию - отсутствие атрибутов.
nsmap
Если ваш документ содержит несколько пространств имен XML, вы можете указать карту пространства имен, которая определяет префиксы пространства имен, которые вы хотели бы использовать, когда этот документ преобразуется в XML. См. Раздел 4.3 «Карты пространства имен».
extras
Любые аргументы в виде name = value, которое вы поставляете конструктору, добавляются к атрибутам элемента. Например, этот код:
newReed = etree.Element('reed', pitch='440', id='a4')

создаст элемент, который выглядит так:

<reed pitch='440' id='a4'/>

Ниже приведен пример создания документа с несколькими пространствами имен с использованием аргумента ключевого слова nsmap.

#!/usr/bin/env python
import sys
from lxml import etree as et

HTML_NS  =  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
XSL_NS   =  "http://www.w3.org/1999/XSL/Transform"
NS_MAP = {None:  HTML_NS,
  "xsl": XSL_NS}

rootName = et.QName(XSL_NS, 'stylesheet')
root = et.Element(rootName, nsmap=NS_MAP)
sheet = et.ElementTree(root)

top = et.SubElement(root, et.QName(XSL_NS, "template"), match='/')
html = et.SubElement(top, et.QName(HTML_NS, "html"))
head = et.SubElement(html, "head")
title = et.SubElement(head, "title")
title.text = "Heading title"
body = et.SubElement(html, "body")
h1 = et.SubElement(body, "h1")
h1.text = "Body heading"
p = et.SubElement(body, "p")
p.text = "Paragraph text"
sheet.write(sys.stdout, pretty_print=True)

Когда этот корневой элемент сериализуется в XML, он будет выглядеть примерно так:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  <xsl:template match="/">
        <html>
                <head>
                        <title>Heading title</title>
                </head>
                <body>
                        <h1>Body heading</h1>
                        <p>Paragraph text</p>
                </body>
        </html>
  </xsl:template>
</xsl:stylesheet>

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

>>> from lxml import etree
>>> d = { 'name': 'Clem', 'clan': 'bozo' }
>>> clownElt = etree.Element('clown', d, attitude='bad')
>>> d
{'clan': 'bozo', 'attitude': 'bad', 'name': 'Clem'}
>>> etree.tostring(clownElt)
'<clown clan="bozo" attitude="bad" name="Clem"/>'
>>>

7.3. Конструктор ElementTree()

Чтобы создать новый пустой документ, используйте этот конструктор. Он возвращает новый экземпляр ElementTree.

etree.ElementTree(element=None, file=None)
element
Экземпляр элемента, который будет использоваться в качестве корневого элемента.
file
Чтобы создать ElementTree, который представляет существующий файл, передайте либо записываемый файловый объект, либо строку, содержащую имя файла. Не используйте аргумент element; если вы это сделаете, аргумент файла будет проигнорирован.

Например, чтобы преобразовать файл с именем balrog.xml в ElementTree, используйте это выражение:

balrogTree = etree.ElementTree(file='balrog.xml')

Исключения, которые могут быть вызваны этим конструктором, включают:

IOError
Если файл несуществующий или нечитаемый.
etree.XMLSyntaxError
Если файл доступен для чтения, но его содержимое не является корректным XML.

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

>>> try:
...   bad = etree.fromstring("<a>\n<<oops>\n</a>")
... except etree.XMLSyntaxError, detail:
...   pass
...
>>> detail
<etree.XMLSyntaxError instance at 0xb7eba10c>
>>> detail.error_log
<string>:2:FATAL:PARSER:ERR_NAME_REQUIRED: StartTag: invalid element name
<string>:3:FATAL:PARSER:ERR_TAG_NAME_MISMATCH: Opening and ending tag mismatch: oops line 2 and a
<string>:3:FATAL:PARSER:ERR_TAG_NOT_FINISHED: Premature end of data in tag a line 1
>>>

7.4. Функция fromstring(): создать элемент из строки

Вы можете создать элемент или дерево элементов из строки, содержащей XML, с помощью этой функции; он возвращает новый экземпляр Element, представляющий весь этот XML.

etree.fromstring(s)

где s - строка.

Вот пример:

>>> milne = '''<monster name='Heffalump'>
...   <trail>Woozle</trail>
...   <eeyore mood='boggy'/>
... </monster>'''
>>> doc = etree.fromstring(milne)
>>> print etree.tostring(doc)
<monster name="Heffalump">
  <trail>Woozle</trail>
  <eeyore mood="boggy"/>
</monster>
>>>

7.5. Функция parse(): постройте ElementTree из файла

Самый быстрый способ преобразования XML-файла в ElementTree - использовать эту функцию:

etree.parse(source)

где source - это имя файла или файл, содержащий XML. Если файл корректно сформирован, функция возвращает экземпляр ElementTree.

Исключения включают:

IOError
Файл отсутствует или не читается.
etree.XMLSyntaxError
Файл читается, но не содержит хорошо сформированного XML. Возвращенное исключение содержит атрибут .error_log, который вы можете распечатать, чтобы увидеть, где произошла ошибка. Пример отображения error_log см. В разделе 7.3 «Конструктор ElementTree ()».

7.6. Конструктор ProcessingInstruction()

Чтобы добавить инструкцию XML в документ, используйте этот конструктор. Он возвращает новый экземпляр ProcessingInstruction; чтобы поместить это в дерево, передать этот экземпляр методу .append() родительского элемента.

etree.ProcessingInstruction(target, text=None):
target
Строка, содержащая целевую часть инструкции обработки.
text
Необязательная строка, содержащая остальную часть инструкции обработки. Значение по умолчанию пуст.

Вот пример:

pi = etree.ProcessingInstruction('decor', 'danish,modern,ducksOnWall')

После преобразования в XML эта инструкция обработки будет выглядеть так:

<?decor danish,modern,ducksOnWall?>

7.7. Конструктор QName()

Когда вы работаете с несколькими пространствами имен, объект QName полезен для объединения части «URI пространства имен» с частью «локального имени». Экземпляр QName может использоваться для части имени атрибутов, которые находятся в другом пространстве имен, чем их содержащий элемент.

Хотя это не является законным в именах XML-элементов, существует конвенция под названием «обозначение Кларка» (после Джеймса Кларка), которая объединяет эти две части в строке этой формы:

{nsURI}local

Чтобы создать новый экземпляр QName, используйте инструкцию этого общего вида:

etree.QName(text, tag=none)
  • Если полное имя элемента уже указано в обозначении Кларка, вызовите конструктор QName только с этим аргументом.
  • Если вы хотите передать URI пространства имен и локальное имя отдельно, вызовите QName с URI пространства имен в качестве текстового аргумента и локальное имя в качестве аргумента тега.

Вот два примера создания экземпляра QName, представляющего квалифицированное имя в пространстве имен XSLT с локальным именем шаблона:

  • В нотации Кларка:
qn = etree.QName("{http://www.w3.org/1999/XSL/Transform}template")
  • Если URI пространства имен и локальное имя указаны отдельно:
qn = etree.QName("http://www.w3.org/1999/XSL/Transform", "template")

7.8. Конструктор SubElement()

Это удобный конструктор, который выполняет две основные операции при добавлении элемента в дерево:

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

Вот общая форма:

SubElement(parent, tag, attrib={}, nsmap=None, **extras):

Первый аргумент parent - это экземпляр Element, в котором новый экземпляр Element должен быть добавлен в качестве следующего дочернего элемента. Параметры тега, атрибута, nsmap и **extras работают точно так же, как и при вызове Element (), описанном в разделе 7.2, «Конструктор Element ()».

Возвращаемое значение - это вновь созданный элемент.

Вот пример. Предположим, вы хотите построить этот XML:

<state name="New Mexico">
  <county name="Socorro">
    <ppl name="Luis Lopez"/>
  </county>
</state>

Вот код для его создания, а затем отображать его в интерактивном режиме:

>>> st=etree.Element('state', name='New Mexico')
>>> co=etree.SubElement(st, 'county', name='Socorro')
>>> ppl=etree.SubElement(co, 'ppl', name='Luis Lopez')
>>> print etree.tostring(st)
<state name="New Mexico"><county name="Socorro"><ppl name="Luis Lopez"/>
</county></state>
>>>

7.9. Функция tostring(): Сериализовать как XML

Чтобы преобразовать Element и его содержимое обратно в XML, используйте вызов функции этой формы:

etree.tostring(elt, pretty_print=False, encoding=None)

где elt - экземпляр элемента. Функция возвращает строку, содержащую XML. Например, см. Раздел 7.8, «Конструктор SubElement ()».

Если вы установите опциональный аргумент pretty_print в значение True, метод попытается вставить разрывы строк, если возможно, чтобы длина строк была коротка.

Чтобы вывести Unicode, используйте ключевое слово encoding = unicode.

7.10. Функция XMLID(): преобразование текста в XML со словарем значений id

..To convert XML in the form of a string into an Element structure, use Section 7.4, “The fromstring() function: Create an element from a string”. However, there is a similar function named etree.XMLID() that does this and also provides a dictionary that allows you to find elements in a tree by their unique id attribute values.

Чтобы преобразовать XML в виде строки в структуру элемента, используйте раздел 7.4, «Функция fromstring (): создайте элемент из строки». Тем не менее, существует аналогичная функция с именем etree.XMLID (), которая делает это, а также предоставляет словарь, который позволяет находить элементы в дереве по их уникальным значениям атрибута id.

Стандарт XML предусматривает, что любой элемент в любом документе может иметь атрибут id, но каждое значение этого атрибута должно быть уникальным в документе. Цель этой функции заключается в том, что приложения могут ссылаться на любой элемент, используя его значение id.

Вот общий вид этой функции:

etree.XMLID(text)

Возвращаемое значение представляет собой кортеж (E, D), где:

  • E - это преобразованный XML как экземпляр элемента, укореняющий преобразованное дерево, так же, как если бы вы вызвали etree.fromstring (текст).
  • D - словарь, ключи которого являются значениями атрибутов id в преобразованном дереве, и каждое соответствующее значение является экземпляром элемента, который несет это значение id.

Вот небольшой пример скрипта:

#!/usr/bin/env python
from lxml import etree

SOURCE = '''<dog id="Fido">
Woof!
<cat id="Fluff">Mao?</cat>
<rhino id="ZR"/>
</dog>'''
tree, idMap = etree.XMLID(SOURCE)

for id in sorted(idMap.keys()):
        elt = idMap[id].text or "(none)"
        print "Tag {0}, text is '{1}'".format(id, elt.strip())

И его вывод:

Tag Fido, text is 'Woof!'
Tag Fluff, text is 'Mao?'
Tag ZR, text is '(none)'