2
Kind of like htmlgen, only much simpler. The only important symbol
3
that is exported is ``html``.
5
This builds ElementTree nodes, but with some extra useful methods.
6
(Open issue: should it use ``ElementTree`` more, and the raw
7
``Element`` stuff less?)
9
You create tags with attribute access. I.e., the ``A`` anchor tag is
10
``html.a``. The attributes of the HTML tag are done with keyword
11
arguments. The contents of the tag are the non-keyword arguments
12
(concatenated). You can also use the special ``c`` keyword, passing a
13
list, tuple, or single tag, and it will make up the contents (this is
14
useful because keywords have to come after all non-keyword arguments,
15
which is non-intuitive). Or you can chain them, adding the keywords
16
with one call, then the body with a second call, like::
18
>>> print html.a(href='http://yahoo.com')('<Yahoo>')
19
<a href=\"http://yahoo.com\"><Yahoo></a>
21
Note that strings will be quoted; only tags given explicitly will
24
If the value of an attribute is None, then no attribute
27
>>> print html.a(href='http://www.yahoo.com', name=None,
29
<a href=\"http://www.yahoo.com\">Click Here</a>
31
If the value is None, then the empty string is used. Otherwise str()
32
is called on the value.
34
``html`` can also be called, and it will produce a special list from
35
its arguments, which adds a ``__str__`` method that does ``html.str``
36
(which handles quoting, flattening these lists recursively, and using
39
``html.comment`` will generate an HTML comment, like
40
``html.comment('comment text')`` -- note that it cannot take keyword
41
arguments (because they wouldn't mean anything).
46
... html.head(html.title(\"Page Title\")),
48
... bgcolor='#000066',
50
... c=[html.h1('Page Title'),
51
... html.p('Hello world!')],
53
<html><head><title>Page Title</title></head><body bgcolor=\"#000066\" text=\"#ffffff\"><h1>Page Title</h1><p>Hello world!</p></body></html>
54
>>> print html.a(href='#top')('return to top')
55
<a href=\"#top\">return to top</a>
59
from __future__ import generators
63
import xml.etree.ElementTree as ET
65
import elementtree.ElementTree as ET
67
default_encoding = 'utf-8'
71
def __getattr__(self, attr):
72
if attr.startswith('_'):
75
if attr.endswith('_'):
77
if attr.find('__') != -1:
78
attr = attr.replace('__', ':')
80
return Element(ET.Comment, {})
82
return Element(attr, {})
84
def __call__(self, *args):
85
return ElementList(args)
90
return escape(unicode(arg).encode(default_encoding), 1)
92
def str(self, arg, encoding=None):
93
if isinstance(arg, str):
97
elif isinstance(arg, unicode):
98
return arg.encode(default_encoding)
99
elif isinstance(arg, (list, tuple)):
100
return ''.join(map(self.str, arg))
101
elif isinstance(arg, Element):
104
return unicode(arg).encode(default_encoding)
108
class Element(ET._ElementInterface):
110
def __call__(self, *args, **kw):
111
el = self.__class__(self.tag, self.attrib)
115
"You may either provide positional arguments or a "
116
"'c' keyword argument, but not both")
119
if not isinstance(args, (list, tuple)):
121
for name, value in kw.items():
125
kw[name] = unicode(value)
126
if name.endswith('_'):
127
kw[name[:-1]] = value
129
if name.find('__') != -1:
130
new_name = name.replace('__', ':')
136
for item in self.getchildren():
139
for arg in flatten(args):
142
if not ET.iselement(arg):
145
el.text = unicode(arg)
147
el.text += unicode(arg)
149
if last.tail is None:
150
last.tail = unicode(arg)
152
last.tail += unicode(arg)
159
return ET.tostring(self, default_encoding)
161
def __unicode__(self):
163
return str(self).decode(default_encoding)
167
if len(content) > 25:
168
content = repr(content[:25]) + '...'
170
content = repr(content)
171
return '<Element %r>' % content
173
class ElementList(list):
176
return html.str(self)
179
return 'ElementList(%s)' % list.__repr__(self)
183
if isinstance(item, (list, tuple)):
184
for sub in flatten(item):