14. Реализация etbuilder

Вот авторский модуль etbuilder.py с описанием.

14.1. Особенности, отличные от оригинала Лунда

Версия автора отличается от версии Лунда в этом отношении:

  • Для этого требуется пакет lxml. Версия Lundh не использовала lxml; он использует cElementTree или elementtree, если первый недоступен.
  • Для этого требуется Python 2.5 или новее. Версия Lundh будет работать с более ранними версиями, возможно, вернется, по крайней мере, к 2.2.
  • Версия автора также допускает значения int в вызове экземпляра E.

14.2. Пролог

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

"""etbuilder.py: An element builder for lxml.etree
================================================================
    $Revision: 1.55 $  $Date: 2012/08/11 21:44:19 $
================================================================
For documentation, see:
    http://www.nmt.edu/tcc/help/pubs/pylxml/
Borrows heavily from the work of Fredrik Lundh; see:
    http://effbot.org/zone/
"""

et в модуле lxml.etree.

#================================================================
# Imports
#----------------------------------------------------------------

from lxml import etree as et

Функция functools.partial() используется для выполнения вызова функции в разделе 14.11, «ElementMaker .__ getattr __ (): обрабатывать вызовы произвольных методов».

Однако модуль functools является новым в Python 2.5. Чтобы этот модуль работал в установке Python 2.4, мы ожидаем возможного отказа от импорта functools, предоставляя эту функциональность с помощью функции partial() substitute. Эта функция украдена непосредственно из справочника библиотеки Python.

try:
        from functools import partial
except ImportError:
        def partial(func, *args, **keywords):
        def newfunc(*fargs, **fkeywords):
                newkeywords = keywords.copy()
                newkeywords.update(fkeywords)
                return func(*(args + fargs), **newkeywords)
        newfunc.func  =  func
        newfunc.args  =  args
        newfunc.keywords  =  keywords
        return newfunc

14.3. CLASS(): вспомогательная функция для добавления атрибутов класса CSS

Далее идет определение вспомогательной функции CLASS(), обсуждаемой в разделе 13.2, «CLASS (): добавление атрибутов класса».

# - - -   C L A S S

def CLASS(*names):
'''Helper function for adding 'class=...' attributes to tags.

[ names is a list of strings ->
        return a dictionary with one key 'class' and the related
        value the concatenation of (names) with one space between
        them ]
'''
return {'class': ' '.join(names)}

14.4. FOR(): вспомогательная функция для добавления XHTML для атрибутов

# - - -   F O R

def FOR(id):
'''Helper function for adding 'for=ID' attributes to tags.
'''
return {'for': id}

14.5. subElement(): добавить дочерний элемент

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

    # - - -   s u b E l e m e n t

def subElement(parent, child):

    '''Add a child node to the parent and return the child.

[ (parent is an Element) and
(child is an Element with no parent) ->
parent  :=  parent with child added as its new last child
return child ]
'''
#-- 1 --
parent.append(child)

#-- 2 --
return child

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

См. Раздел 13.5. addText(): добавление текстового содержимого в элемент. Чтобы упростить работу вызывающего, мы ничего не делаем, если s равно None, как это может быть в случае с атрибутом .text или .tail для элемента et.Element.

# - - -   a d d T e x t

def addText(node, s):
    '''Add text content to an element.

    [ (node is an Element) and (s is a string) ->
    if node has any children ->
        last child's .tail  +:=  s
    else ->
        node.text +:= s ]
    '''
    #-- 1 --
    if not s:
        return

    #-- 2 --
    if len(node) == 0:
        node.text = (node.text or "") + s
    else:
        lastChild = node[-1]
        lastChild.tail = (lastChild.tail or "") + s

14.7. class ElementMaker: The factory class

# - - - - -   c l a s s   E l e m e n t M a k e r

class ElementMaker(object):
'''ElementTree element factory class

Exports:
    ElementMaker(typeMap=None):
        [ (typeMap is an optional dictionary whose keys are
        type objects T, and each corresponding value is a
        function with calling sequence
        f(elt, item)
        and generic intended function
        [ (elt is an et.Element) and
        (item has type T) ->
        elt  :=  elt with item added ]) ->
        return a new ElementMaker instance that has
        calling sequence
        E(*p, **kw)
        and intended function
        [ p[0] exists and is a str ->
                return a new et.Element instance whose name
                is p[0], and remaining elements of p become
                string content of that element (for types
                str, unicode, and int) or attributes (for
                type dict, and members of kw) or children
                (for type et.Element), plus additional
                handling from typeMap if it is provided ]
          and allows arbitrary method calls of the form
            E.tag(*p, **kw)
          with intended function
            [ return a new et.Element instance whose name
              is (tag), and elements of p and kw have
              the same effects as E(*(p[1:]), **kw) ]
'''