Introducing the Proton Template Engine

Tuesday, 20 January, 2009

I haven’t come across many (any?) templating engines for Python 3, so it seemed like a good idea to update my own attempt, and then release as an open source (LGPL) project.

Proton is a simple, “code-less” engine for xml/xhtml templates. Code-less, because it uses 3 types of ID (attribute) in a template file, rather than snippets of code — this moves the complexity out of the template and into the application (where I think it belongs).

The following template demonstrates basic use of the 3 IDs:

<html>
<head>
<title eid="title">PAGE TITLE</title>
</head>
<body>
    <h1 eid="title">PAGE TITLE</h1>

    <p><a eid="link" aid="link" href="">LINK ITEM</a></p>

    <ul>
        <li rid="list-item" eid="list-item">LIST ITEMS</li>
    </ul>
</body>
</html>

The attribute “eid” is used to change the value of an element, or hide the element. “aid” is used to change the value of an attribute, and “rid” is used for repeating elements. This might seem a bit simplistic, but it covers the fundamentals of most templating tasks.

The following code demonstrates the use of the template:


tmp = Templates()['test.xhtml']

tmp.setelement('title', 'An Xhtml Page', '*')
tmp.setelement('link', 'This is a link to Google')
tmp.setattribute('link', 'href', 'http://www.google.com')

tmp.repeat('list-item', 5)
for x in range(0, 5):
    tmp.setelement('list-item', 'test%s' % x, x)

print(str(tmp))

I used an earlier version of Proton for my own (rather ill-fated) project; a web-based system for timesheet and invoice management, so it has been tested in some relatively complicated scenarios — however, I am keen to hear where it falls down. i.e. complex pages where using 3 attributes just doesn’t cut it.

4 Responses to “Introducing the Proton Template Engine”

  1. Paul says:

    Why does the <a> require both an ‘eid’ and an ‘aid’? I’m curious why can’t you use eid for both purposes.

    In many sistuations, the element will also have an ‘id’ attribute. Does that mean you will end up having three ‘id’ attributes? That’s going to be a bit annoying isn’t it?

  2. jrbriggs says:

    Flexibility, basically. I used to have a good example of this, but I’ve forgotten it, so here’s a completely contrived example. Suppose you have 2 templates, one which is plain xml and one which is xhtml. The input to both is the same, so you should be able to use the same code to populate/render output…

    Plain xml template:

    <list>
    <item id=”" rid=”list” aid=”listid” eid=”listval”></item>
    </list>

    Final output:

    <list>
    <item id=”1″>my item 1</item>
    <item id=”2″>my item 2</item>
    </list>

    Xhtml template:

    <table>
    <tr rid=”list”>
    <td>ID</td>
    <td eid=”listid”></td>
    <td>VALUE</td>
    <td eid=”listval”></td>
    </tr>
    </table>

    Final output:

    <table>
    <tr>
    <td>ID</td>
    <td>1</td>
    <td>VALUE</td>
    <td>my item 1</td>
    </tr>
    <tr>
    <td>ID</td>
    <td>2</td>
    <td>VALUE</td>
    <td>my item 2</td>
    </tr>
    </table>

    Without separating the setting of attribute values from element values, you wouldn’t be able to use the same code for both the above templates — or at the very least, you’d have to add logic to the code which is ‘aware’ of the content of the templates (which I’d like to avoid).

    PS. You could end up with 4 ‘id’ attributes on an element: id, eid, rid, aid. The latter 3 are stripped on output, but in any case, it’s no more annoying than your average JSF monstrosity… or other templating systems with screeds of code. IMHO of course. ;-)

  3. Paul says:

    If I understand your post correctly, the code would be different for each template anyway. The XML example would require a setelement() and a setattribute() call, while the XHTML example requires two setelement() calls.

  4. jrbriggs says:

    You understand correctly, but the same code can be used for both templates. Assuming either template has been loaded, this will work:

    
    tmp.repeat('list', 2)
    for x in range(1, 3):
        tmp.setelement('listid', str(x), x)
        tmp.setattribute('listid', 'id', str(x), x)
        tmp.setelement('listval', 'my item %s' % x, x)
    

    The engine won’t add an attribute where one doesn’t already exist in the template — so the setattribute call won’t affect the xhtml. I’ve added an example with assertions to source control if you’re interested in taking a look:
    http://proton-te.googlecode.com/hg/python/test/twotemplates.py

Leave a Reply