13. etbuilder.py: упрощенный модуль построителя XML

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

mainTitle  =  et.Element('h1')
mainTitle.text  =  "Welcome to Your Title Here!"

Блестящий и продуктивный Fredrik Lundh написал очень хороший модуль под названием builder.py, который значительно упрощает создание XML.

  • См. Оригинальную страницу Lundh, ElementTree Builder, для более старой версии его модуля, с документацией и примерами.
  • Вы можете использовать текущую версию builder.py со страницы репозитория SVN Lundh.
  • Автор написал модифицированную версию, основанную в основном на версии Lundh. Источник для этого модуля etbuilder.py доступен в Интернете.

    Инструкции по использованию авторской версии см. В разделе 13.1 «Использование модуля etbuilder».

    Для фактической реализации в форме легкого грамотного программирования см. Раздел 14 «Внедрение etbuilder».

13.1. Использование модуля etbuilder

Вместо импорта пакета ElementTree в качестве et используйте этот импорт:

from etbuilder import et, E

Имя E является фабричным объектом, который создает экземпляры et.Element.

Вот вызывающая последовательность для E:

E(tag, \*p, \**kw)

Первый аргумент, tag, является именем элемента в виде строки. Возвращаемое значение представляет собой новый экземпляр et.Element.

Вы можете предоставить любое количество позиционных аргументов p, за которыми следует любое количество аргументов ключевого слова. Интерпретация каждого аргумента зависит от его типа. Экран с подсказками «>>>» - это интерактивные примеры.

  • Любой аргумент ключевого слова формы «name = value» становится атрибутом XML «name = ‘value’» нового элемента.
>>> colElt=E('col', valign='top', align='left')
>>> et.tostring(colElt)
'<col align="left" valign="top" />'
  • Строковые аргументы добавляются в содержимое тега.
>>> p14 = E("p", "Welcome to ", "Your Paragraph Here.")
>>> et.tostring(p14)
'<p>Welcome to Your Paragraph Here.</p>'
  • Аргумент типа int преобразуется в строку и добавляется в содержимое тега.
  • Если вы передадите словарь в функцию, его члены также станут атрибутами XML. Например, вы можете создать элемент ячейки таблицы XHTML следующим образом:

    >>> cell = E('td', {'valign': 'top', 'align': 'right'}, 14)
    >>> et.tostring(cell)
    '<td align="right" valign="top">14</td>'
    
  • You can pass in an et.Element instance, and it becomes a child element of the element being built. This allows you to nest calls within calls, like this:

  • Вы можете передать экземпляр et.Element и стать дочерним элементом создаваемого элемента. Это позволяет вам встраивать вызовы в вызовы, например:

    >>> head = E('head',
    ...    E('title', 'Your Page Title Here'),
    ...    E('link', rel='stylesheet', href='/tcc/style.css'))
    >>> print et.tostring(head, pretty_print=True)
    <head>
    <title>Your Page Title Here</title>
    <link href="/tcc/style.css" rel="stylesheet" />
    </head>
    

У этого модуля есть еще одна приятная морщина. Если имя создаваемого тега также является допустимым именем Python, вы можете использовать это имя как имя вызова метода в экземпляре E. То есть,

E.name(...)

функционально эквивалентно

E("name", ...)

Вот пример:

>>> head = E.head(
...    E.title('Your title'),
...    E.link(rel='stylesheet', href='/tcc/style.css'))
>>> print et.tostring(head, pretty_print=True)
<head>
  <title>Your title</title>
  <link href="/tcc/style.css" rel="stylesheet" />
</head>

13.2. CLASS (): добавление атрибутов класса

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

<div class='warning'>
  Your brain may not be the boss!
</div>

Очевидный способ сделать это не работает:

E.div("Your brain may not be the boss!", class='warning')  # Fails!

Поскольку класс является зарезервированным словом в Python, вы не можете использовать его как ключевое слово аргумента. Поэтому пакет включает вспомогательную функцию с именем CLASS(), которая принимает одно или несколько имен в качестве аргументов и возвращает словарь, который может быть передан конструктору E(), чтобы добавить атрибут class= attribute. Этот пример действительно работает для создания вышеприведенного XML:

E.div("Your brain may not be the boss!", CLASS('warning'))  # Works.

Вот еще один пример, на этот раз с несколькими именами классов.

E.span(CLASS('ref', 'index'), "Pie, whole.")

Это генерирует:

<span class='ref index'>Pie, whole.</span>

13.3. FOR(): добавление для атрибутов

Эта функция аналогична той, которая определена в разделе 13.2, «CLASS (): добавление атрибутов класса»: он используется для присоединения атрибута к элементу, чье имя (for) является зарезервированным словом на Python. Такие атрибуты обычно используются для связывания элемента метки XHTML с элементом формы.

13.4. subElement(): добавление дочернего элемента

Эта функция объединяет две общие операции создания элемента и добавления его в качестве следующего дочернего элемента какого-либо родительского узла. Общая последовательность вызовов:

subNode = subElement(parent, child)

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

13.5. addText(): добавление текстового содержимого в элемент

Эта удобная функция обрабатывает специальную логику, используемую для добавления текстового содержимого в узел стиля ElementTree. Проблема в том, что если узел не имеет дочерних элементов, новый текст добавляется к атрибуту .text, но если есть дети, новый текст должен быть добавлен к атрибуту .tail последнего дочернего элемента. Обратитесь к разделу 2 «Как ElementTree представляет XML» для обсуждения того, почему это необходимо.

Вот общая последовательность вызовов, чтобы добавить некоторую текстовую строку s к существующему узлу:

addText(node, s)