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:

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, '&nbsp;%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 &lt; Foo" src="http://www.foo.com/boo.jpg" height="300" />
      <span><a href="http://www.foo.com" title="Bar &lt; Foo">#</a>&nbsp;Bar &lt; Foo. 2003-08-06</span>
    </div>
    
    <div class="image">
      <img width="400" alt="Baz &gt; Bar" src="http://www.baz.com/baa.jpg" height="300" />
      <span><a href="http://www.baz.com" title="Baz &gt; Bar">#</a>&nbsp;Baz &gt; 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.