[Lxml-checkins] r39387 - in lxml/trunk: . src/lxml

scoder at codespeak.net scoder at codespeak.net
Sun Feb 25 14:59:32 CET 2007


Author: scoder
Date: Sun Feb 25 14:59:29 2007
New Revision: 39387

Added:
   lxml/trunk/src/lxml/builder.py
   lxml/trunk/src/lxml/htmlbuilder.py
Modified:
   lxml/trunk/CHANGES.txt
Log:
integrated element generator factory by Fredrik Lundh

Modified: lxml/trunk/CHANGES.txt
==============================================================================
--- lxml/trunk/CHANGES.txt	(original)
+++ lxml/trunk/CHANGES.txt	Sun Feb 25 14:59:29 2007
@@ -8,6 +8,10 @@
 Features added
 --------------
 
+* HTML generator helpers by Fredrik Lundh in ``lxml.htmlbuilder``
+
+* ``ElementMaker`` XML generator by Fredrik Lundh in ``lxml.builder.E``
+
 * Support for pickeling ``objectify.ObjectifiedElement`` objects to XML
 
 * ``update()`` method on Element.attrib

Added: lxml/trunk/src/lxml/builder.py
==============================================================================
--- (empty file)
+++ lxml/trunk/src/lxml/builder.py	Sun Feb 25 14:59:29 2007
@@ -0,0 +1,161 @@
+"""
+Element generator factory by Fredrik Lundh.
+
+Source:
+    http://online.effbot.org/2006_11_01_archive.htm#et-builder
+    http://effbot.python-hosting.com/file/stuff/sandbox/elementlib/builder.py
+"""
+
+import etree as ET
+
+try:
+    from functools import partial
+except ImportError:
+    # fake it for pre-2.5 releases
+    def partial(func, tag):
+        return lambda *args, **kwargs: func(tag, *args, **kwargs)
+
+
+class _C:
+    pass
+
+class ElementMaker(object):
+    """Element generator factory.
+
+    Unlike the ordinary Element factory, the E factory allows you to pass in
+    more than just a tag and some optional attributes; you can also pass in
+    text and other elements.  The text is added as either text or tail
+    attributes, and elements are inserted at the right spot.  Some small
+    examples::
+
+        >>> from lxml import etree as ET
+        >>> from lxml.builder import E
+
+        >>> ET.tostring(E("tag"))
+        '<tag/>'
+        >>> ET.tostring(E("tag", "text"))
+        '<tag>text</tag>'
+        >>> ET.tostring(E("tag", "text", key="value"))
+        '<tag key="value">text</tag>'
+        >>> ET.tostring(E("tag", E("subtag", "text"), "tail"))
+        '<tag><subtag>text</subtag>tail</tag>'
+
+    For simple tags, the factory also allows you to write ``E.tag(...)`` instead
+    of ``E('tag', ...)``::
+
+        >>> ET.tostring(E.tag())
+        '<tag/>'
+        >>> ET.tostring(E.tag("text"))
+        '<tag>text</tag>'
+        >>> ET.tostring(E.tag(E.subtag("text"), "tail"))
+        '<tag><subtag>text</subtag>tail</tag>'
+
+    Here's a somewhat larger example; this shows how to generate HTML
+    documents, using a mix of prepared factory functions for inline elements,
+    nested ``E.tag`` calls, and embedded XHTML fragments::
+
+        # some common inline elements
+        A = E.a
+        I = E.i
+        B = E.b
+
+        def CLASS(v):
+            # helper function, 'class' is a reserved word
+            return {'class': v}
+
+        page = (
+            E.html(
+                E.head(
+                    E.title("This is a sample document")
+                ),
+                E.body(
+                    E.h1("Hello!", CLASS("title")),
+                    E.p("This is a paragraph with ", B("bold"), " text in it!"),
+                    E.p("This is another paragraph, with a ",
+                        A("link", href="http://www.python.org"), "."),
+                    E.p("Here are some reservered characters: <spam&egg>."),
+                    ET.XML("<p>And finally, here is an embedded XHTML fragment.</p>"),
+                )
+            )
+        )
+
+        print ET.tostring(page)
+
+    Here's a prettyprinted version of the output from the above script::
+
+        <html>
+          <head>
+            <title>This is a sample document</title>
+          </head>
+          <body>
+            <h1 class="title">Hello!</h1>
+            <p>This is a paragraph with <b>bold</b> text in it!</p>
+            <p>This is another paragraph, with <a href="http://www.python.org">link</a>.</p>
+            <p>Here are some reservered characters: &lt;spam&amp;egg&gt;.</p>
+            <p>And finally, here is an embedded XHTML fragment.</p>
+          </body>
+        </html>
+    """
+
+    def __init__(self, typemap=None):
+	# initialize type map for this element factory
+
+	if typemap:
+	    typemap = typemap.copy()
+	else:
+	    typemap = {}
+	
+	def add_text(elem, item):
+	    if len(elem):
+		elem[-1].tail = (elem[-1].tail or "") + item
+	    else:
+		elem.text = (elem.text or "") + item
+	typemap[str] = typemap[unicode] = add_text
+
+	def add_dict(elem, item):
+	    attrib = elem.attrib
+	    for k, v in item.items():
+		if isinstance(v, basestring):
+		    attrib[k] = v
+		else:
+		    attrib[k] = typemap[type(v)](None, v)
+	typemap[dict] = add_dict
+
+	def add_elem(elem, item):
+	    elem.append(item)
+	t = type(ET.Element("tag"))
+	if t is not type(_C()):
+	    typemap[t] = add_elem
+
+	self._typemap = typemap
+
+	# print typemap
+
+    def __call__(self, tag, *children, **attrib):
+	get = self._typemap.get
+
+        elem = ET.Element(tag)
+	if attrib:
+	    get(dict)(elem, attrib)
+
+        for item in children:
+            if callable(item):
+                item = item()
+	    t = get(type(item))
+	    if t is None:
+		if ET.iselement(item):
+		    elem.append(item)
+		    continue
+		raise TypeError("bad argument type: %r" % item)
+	    else:
+		v = t(elem, item)
+		if v:
+		    get(type(v))(elem, v)
+
+        return elem
+
+    def __getattr__(self, tag):
+        return partial(self, tag)
+
+# create factory object
+E = ElementMaker()

Added: lxml/trunk/src/lxml/htmlbuilder.py
==============================================================================
--- (empty file)
+++ lxml/trunk/src/lxml/htmlbuilder.py	Sun Feb 25 14:59:29 2007
@@ -0,0 +1,125 @@
+"""
+HTML specialisation of ``builder.py`` by Fredrik Lundh
+
+Usage::
+
+    >>> from lxml.htmlbuilder import *
+    >>> html = HTML(
+    ...            HEAD( TITLE("Hello World") ),
+    ...            BODY( CLASS("main"),
+    ...                  H1("Hello World !")
+    ...            )
+    ...        )
+
+    >>> import lxml.etree
+    >>> print lxml.etree.tostring(html, pretty_print=True)
+    <html>
+      <head>
+        <title>Hello World</title>
+      </head>
+      <body class="main">
+        <h1>Hello World !</h1>
+      </body>
+    </html>
+
+"""
+
+from builder import E
+
+# elements
+A = E.a # anchor
+ABBR = E.abbr # abbreviated form (e.g., WWW, HTTP, etc.)
+ACRONYM = E.acronym # 
+ADDRESS = E.address # information on author
+APPLET = E.applet # Java applet (DEPRECATED)
+AREA = E.area # client-side image map area
+B = E.b # bold text style
+BASE = E.base # document base URI
+BASEFONT = E.basefont # base font size (DEPRECATED)
+BDO = E.bdo # I18N BiDi over-ride
+BIG = E.big # large text style
+BLOCKQUOTE = E.blockquote # long quotation
+BODY = E.body # document body
+BR = E.br # forced line break
+BUTTON = E.button # push button
+CAPTION = E.caption # table caption
+CENTER = E.center # shorthand for DIV align=center (DEPRECATED)
+CITE = E.cite # citation
+CODE = E.code # computer code fragment
+COL = E.col # table column
+COLGROUP = E.colgroup # table column group
+DD = E.dd # definition description
+DEL = getattr(E, 'del') # deleted text
+DFN = E.dfn # instance definition
+DIR = E.dir # directory list (DEPRECATED)
+DIV = E.div # generic language/style container
+DL = E.dl # definition list
+DT = E.dt # definition term
+EM = E.em # emphasis
+FIELDSET = E.fieldset # form control group
+FONT = E.font # local change to font (DEPRECATED)
+FORM = E.form # interactive form
+FRAME = E.frame # subwindow
+FRAMESET = E.frameset # window subdivision
+H1 = E.h1 # heading
+H2 = E.h2 # heading
+H3 = E.h3 # heading
+H4 = E.h4 # heading
+H5 = E.h5 # heading
+H6 = E.h6 # heading
+HEAD = E.head # document head
+HR = E.hr # horizontal rule
+HTML = E.html # document root element
+I = E.i # italic text style
+IFRAME = E.iframe # inline subwindow
+IMG = E.img # Embedded image
+INPUT = E.input # form control
+INS = E.ins # inserted text
+ISINDEX = E.isindex # single line prompt (DEPRECATED)
+KBD = E.kbd # text to be entered by the user
+LABEL = E.label # form field label text
+LEGEND = E.legend # fieldset legend
+LI = E.li # list item
+LINK = E.link # a media-independent link
+MAP = E.map # client-side image map
+MENU = E.menu # menu list (DEPRECATED)
+META = E.meta # generic metainformation
+NOFRAMES = E.noframes # alternate content container for non frame-based rendering
+NOSCRIPT = E.noscript # alternate content container for non script-based rendering
+OBJECT = E.object # generic embedded object
+OL = E.ol # ordered list
+OPTGROUP = E.optgroup # option group
+OPTION = E.option # selectable choice
+P = E.p # paragraph
+PARAM = E.param # named property value
+PRE = E.pre # preformatted text
+Q = E.q # short inline quotation
+S = E.s # strike-through text style (DEPRECATED)
+SAMP = E.samp # sample program output, scripts, etc.
+SCRIPT = E.script # script statements
+SELECT = E.select # option selector
+SMALL = E.small # small text style
+SPAN = E.span # generic language/style container
+STRIKE = E.strike # strike-through text (DEPRECATED)
+STRONG = E.strong # strong emphasis
+STYLE = E.style # style info
+SUB = E.sub # subscript
+SUP = E.sup # superscript
+TABLE = E.table # 
+TBODY = E.tbody # table body
+TD = E.td # table data cell
+TEXTAREA = E.textarea # multi-line text field
+TFOOT = E.tfoot # table footer
+TH = E.th # table header cell
+THEAD = E.thead # table header
+TITLE = E.title # document title
+TR = E.tr # table row
+TT = E.tt # teletype or monospaced text style
+U = E.u # underlined text style (DEPRECATED)
+UL = E.ul # unordered list
+VAR = E.var # instance of a variable or program argument
+
+# attributes (only reserved words are included here)
+ATTR = dict
+def CLASS(v): return {'class': v}
+def FOR(v): return {'for': v}


More information about the lxml-checkins mailing list