Ian Bicking: the old part of his blog

Opening up templates

I'm excited to see Kevin's work on template plugins, and that the TurboGears plugin system is fully extracted into a generic plugin for templates. I think this will be an easy ad hoc standard to start supporting elsewhere. It should encompass all the "normal" templating languages that just take a bunch of variables (something like meld3 probably won't work with this, though). I doubt code can be very well neutral with respect to the template language it is feeding. Kid and Cheetah can have arbitrary Python to munge the data in them. ZPT can have Python expressions, but not statements or functions. Django and ClearSilver need data structures that require very little processing in the template, as they don't have generic expressions at all. So you can't exactly be neutral. But still this is an important step forward.

One of the big issues in making little apps is how to make them fit into a larger site. It's mostly fine if the internals of the pages are written by different templating languages. Standard conventions for CSS classes would be a tremendous boon, but a little sloppiness isn't that big a deal. But you still need an application that is well-wrapped in some template for your site. Each application may have a way to give a site template, but if they are all using different templating languages that means a lot of duplication. (And even if they are using the same templating language, some standard way to override templates is still needed, or else you have a mess of things to manage).

So... what to do...

I like HTTP, so I naturally go that direction for interoperability. Server-side includes provide a simple, relatively language-neutral way to handle templating. But they work textually, not based on markup, and there's lots of issues with the typical implementations. XSL applies well here, of course. I haven't used XSL for years, but my brief experiments with it left me so disheartened I simply can't imagine it being useful for templating.

But more primitive templating is quite possible. One of the interesting ideas I've seen (and I'm sure there's others -- if you have one, then do comment) is HTML overlays. This can be implemented on the client-side in Javascript, but of course it could be implemented as a filter easily enough as well.

Then applications would each take a site_template configuration parameter, and maybe a Javascript parameter if client-side overlays were going to be used (presumably any filter would simply notice the overlay and implement it). Then the application would put this in the head:

<link rel="overlay" type="text/x-im-not-sure"
 href="/configured-template-location" />

Actually I now think the type should be configurable too, allowing for other kinds of templates than just this implementation of overlays. Also overlays don't seem to have a way to pull in content, they only allow content to be pushed into them.

Obviously the Javascript can be applied to any site. A server-side filter could also be easily(ish) written in C as an Apache filter, or as libraries in a variety of frameworks and languages.

Created 07 Jan '06

Comments:

FYI. In respect of filters in Apache, there is an intention of making some improvements to mod_python's support of filters and also its interaction with mod_include (SSI) filter module.

http://issues.apache.org/jira/browse/MODPYTHON-103

http://issues.apache.org/jira/browse/MODPYTHON-104

In terms of server side includes, the intention is to allow Python code to be usable within a file passed through mod_include, much like how it can already be done with mod_perl. This would be more efficient than the current need to use "include virtual".

One could also explore whether a means could be provided of allowing whole new element tags to be defined where the callouts are implemented and processed within the context of mod_python.

From what I have seen at the moment, people using mod_python don't tend to use filters much at all. This is possibly partly because of mod_python's inability to dynamically register filters, or more likely because there isn't a good appreciation of how Apache filters could be used. But then, at the moment, some parts of mod_python don't even play nice with predefined filters like CONTENT_LENGTH.

http://issues.apache.org/jira/browse/MODPYTHON-107
# Graham Dumpleton

Hi Ian,

Long time reader, first time poster (now I feel like I'm on radio call in show).

I agree that app developer can't really remain neutral as far as templating engines are concerned. However, toolkits and frameworks, like CherryPy and TurboGears, that want to intentionally remain neutral (or at least flexible) as far as templating languages go really stand to benefit from this plugin system. Plus, since there are so many "normal" templating languages, it is handy to have a common means of getting at their functionality. Since we've got a bazillion template languages in Python, we might as well put them to good use ;-)

Christian

# Christian Wyglendowski

Actually, I use XSLT for all my templating needs, and I love it. It's a standard, and it makes sure that there's also nice XML which I can use for other purposed or interesting REST-style interaction, and it forces me to keep the code and the templates very strictly separated.

See also http://manuzhai.nl/weblog/comments/the-power-of-xslt/

# Manuzhai

I'll add another vote for using xslt for server-side and client-side templating.

Though I recognize that it's not for everyone. To that end, I've been working on generating xsl templates using a ZPT like syntax.

I'll say "ZPT like" because there are some extensions that aren't available in ZPT.

I don't have anything to release yet, but it's an extension of the bitflux stuff

http://wiki.bitflux.org/Templates_TAL_Example

I have metal working, but it's a two step process to "compile" a set of .zpt files into an .xsl file.

The resulting .xsl file is then used on the server-side to render the html, or sent to the client so it can do it's own rendering. I use a Paste filter to generate .xsl files in-the-fly and cache them. And, another Paste filter to sniff client capabilities and determine if .xsl should be sent back to the client, or wether transformation should be done on the server.

I look at client-side XSLT rendering as very important. In a way, it can be a form of edge-side includes (ESI) http://www.esi.org/

This is done through the use of the document() xslt function on the client. For example, this fragment uses a relative path to retrieve an XML document from the server and set it's root element in a variable:

<div tal:define="order document(concat('/orders/', $order_number, '.xml'))/ROOT)">

Regarding context.. XSL expects XML as input, so the context is passed to the template as XML. So, it must be pre-rendered that way by the web request handler. The downside of course is that the templating engine cannot call python objects for dynamic rendering. The upside to that is that anything rendered dynamically this way probably should be exposed using a REST style interface. Then that data can be retrieved by the client directly, not just rendered on the server (as the above example shows).

Here's an example fragment of a tal:repeat traversing the first 24 elements of an invoice:

<tr tal:repeat="li $order/OE0500[24 > position()]" tal:sort="PICSEQ ascending"
        tal:attributes="class concat('R',position() mod 2)">
        <td tal:content="$li/ITEM" />
        <td tal:content="$li/LINENUM" />
        <td tal:content="$li/DESC"/>
        <td tal:content="$li/QTYORDERED" />
        <td><div class="button">BO</div></td>
</tr>

And here's the example fragment of resulting .xsl (copied out of IE so not well formatted):

<xslout:for-each select="$order/OE0500[24 > position()]">
    <xslout:sort select="PICSEQ" order="ascending" /> 
    <xslout:variable name="li" select="." /> 
    <tr>
        <xslout:attribute name="class">
        <xslout:value-of select="concat('R',position() mod 2)" /> 
        </xslout:attribute>
        <td>
        <xslout:value-of select="$li/ITEM" /> 
        </td>
        <td>
        <xslout:value-of select="$li/LINENUM" /> 
        </td>
        <td>
        <xslout:value-of select="$li/DESC" /> 
        </td>
        <td>
        <xslout:value-of select="$li/QTYORDERED" /> 
        </td>
        <td>
        <div class="button">BO</div> 
        </td>
    </tr>
</xslout:for-each>

The 'li' placeholder variable is not necessary, but that's what the bitflux guys came up with, so I stuck with it.

This thing diverges from ZPT in a number of ways (like a sort option for tal:repeat).

Also, there's a way of creating "macros" that can receive arguments. That is, something like metal:define, but it doesn't repeat the macro contents in the output file. It's more for defining xsl templates.

So, I guess it's a frankenstein templating language. I still need to integrate with existing .xsl files (via xsl:includes or imports), but I like the ease of ZPT.

I should spend more time working on it so I can get some feedback. It's definately a niche thing.

However I still think for my clients, XSLT and XML is just too handy to pass up.

I can take "client-side" .xsl scraps and re-use them in Apache FOP.. its great.

# Brad Clements