Deex: an XHTML generator
What is it?
Deex is a little Python
module that uses nested function lists to render sequences of XHTML tags. To
use Deex you only need to import a couple of functions: render
wich takes a tree of nested functions and render the corresponding XHTML markup
and curry (see reference
curry implementation and related discussion), used to bind parameter values to functions.
Download the latest version of deex.
Return values for functions
Every nested function always must to return a list or a tuple of values. Such values can be be:
- A dictionary, used to express tag attributes using a sequence of key-value pairs. If a dictionary is present it must be the fist element of the list or tuple.
- A function, that will be then called by Deex.
- A string.
- Another list or tuple. Deex will iterate over it.
See the examples below for further details.
Examples
Here are a couple of examples to let you start playing around with Deex.
Note: actually produced markup is not so pretty, i've slightly edited the examples to make them more clear. Eventually i'll come up with an improved version soon.
Photo gallery
from deex import render, curry
from cgi import escape
# let's pretent we picked those values from a database query
photos = [{'title':'Bar < Foo', 'uri':'http://www.foo.com/boo.jpg', 'date':'2003-08-06'},
{'title':'Baz > Bar', 'uri':'http://www.baz.com/baa.jpg', 'date':'2003-03-01'}]
def div():
def h2():
return {'id':'gallery'}, 'Photo Gallery'
def h3():
return 'Recently published', # always remember to return a list or a tuple
def div(photo):
def img():
return {'width':'400', 'height':'300', 'alt':photo['title'], 'src':photo['uri']},
def span():
def a():
return {'href':photo['uri'], 'title':photo['title']}, '#'
return a, ' %s. %s' % (escape(photo['title']), photo['date'])
return {'class':'image'}, img, span
return h2, h3, [curry(div, photo) for photo in photos]
print render(div)
The above code fragment will produce the XHTML markup:
<div>
<h2 id="gallery">Photo Gallery</h2>
<h3>Recently published</h3>
<div class="image">
<img width="400" alt="Bar < Foo" src="http://www.foo.com/boo.jpg" height="300" />
<span><a href="http://www.foo.com" title="Bar < Foo">#</a> Bar < Foo. 2003-08-06</span>
</div>
<div class="image">
<img width="400" alt="Baz > Bar" src="http://www.baz.com/baa.jpg" height="300" />
<span><a href="http://www.baz.com" title="Baz > Bar">#</a> Baz > Bar. 2003-03-01</span>
</div>
</div>
Note: while Deex correctly escapes attributes values, it's responsibility of the caller to proper escape tag content. This way caller can freely mix inline markup with normal text without define a function for every nested XHTML tag.
Table generation
from datetime import date
from deex import render, curry
# let's pretent we picked those values from a database query
users = (True, 'joe99', 'John Doe', date(2003,1,1)),
(False, 'betty11', 'Betty Ford', date(2001,3,1))
def table():
headers = 'enabled', 'login', 'full name', 'registered on'
def thead():
def tr():
def th(header):
return header
return [curry(th, header) for header in headers]
return tr,
def tbody():
def tr(user):
def td(field): # first vanilla TD
return '%s' % str(field),
def td_a(field): # second, hyperlinked TD
def a():
return {'href':'http://example.org/staff/%s' % field}, '%s' % field
return a,
# here we opt to render an hyperlink for the "login" cell
return [curry(f, user[index]) for index, f in enumerate((td, td_a, td, td))]
return [curry(tr, user) for user in users]
def tfoot():
return '',
return {'id':'users'}, thead, tbody, tfoot
print render(table)
The above code fragment will produce the XHTML markup:
<table id="users">
<thead>
<tr>
<th>enabled</th>
<th>login</th>
<th>full name</th>
<th>registered on</th>
</tr>
</thead>
<tbody>
<tr>
<td>True</td>
<td><a href="http://example.org/staff/joe99">joe99</a></td>
<td>John Doe</td>
<td>2003-01-01</td>
</tr>
<tr>
<td>False</td>
<td><a href="http://example.org/staff/betty11">betty11</a></td>
<td>Betty Ford</td>
<td>2001-03-01</td>
</tr>
</tbody>
<tfoot>
</tfoot>
</table>
Note: see how ne need to name td and td_a
to uniquely identify the two functions. Deex does not force you to come up with
significative names for duplicated functions, i could have chosen to name them
td_1 and td_2 since Deex simply ignores everything after
the first underscore.
License
Deex is released under the GNU General Public License.
— Andrea Peltrin, December 2003.