Questions about HTML templates
What types of markup does HTMLTemplate accept?
HTML - as long as elements are closed as-per XML/XHTML standards - and XHTML are both supported. XML templating is possible, but limited by Python's HTMLParser module to lowercase tag and attribute names; see the doc/ISSUES
file.
Can HTMLTemplate be used for non-markup based templating?
It can, though it isn't designed for it; use texttemplate module instead.
Does HTMLTemplate modify a template's original HTML markup at all?
Slightly: all tag attributes will be double- or single-quoted (a side-effect of using Python's HTMLParser module to parse the template).
Do HTML templates need to be complete HTML documents with a single root element, or can HTMLTemplate handle arbitrary fragments of HTML too?
Both are fine. HTMLTemplate doesn't require a template be a complete HTML document, nor even that it has a single root element as some templating engines may do.
Does HTMLTemplate support caching and/or pickling of compiled templates?
No. The template parser is very fast and templates generally only need to be compiled once as Template objects are reusable, so no caching system is necessary.
Can HTMLTemplate use id
attributes or namespace-based attributes to indicate template nodes, e.g. for compatibility with WYSIWYG HTML editors?
Yes, you can specify an alternate attribute name via the Template constructor; for example: Template(callback, html, attribute='id')
or Template(callback, html, attribute='tpl:node')
. If using an existing HTML attributes such as id
, note that only id
attributes containing compiler directives will be removed by HTMLTemplate; other id
attributes will conveniently be left intact.
How does HTMLTemplate fit into the popular MVC (Model-View-Controller) application design pattern?
HTMLTemplate's design is strongly influenced by the MVC pattern commonly used in desktop application design, where the Controller is a bridge between Model and View. (Note this is Apple Computer's popular definition of the MVC pattern, as opposed to the original PARC/Smalltalk definition.) A directive-tagged HTML template and Python control code corresponds closely to the View and Controller layers of this pattern: the HTMLTemplate compiler performs a similar role to Apple's Interface Builder in constructing the View layer as a live object model, while the Python control code that manipulates this object model at rendering time forms the Controller layer.
Questions about manipulating Template object models
Is it possible to modify just part of an element's content; for example, replacing only the 'XXXX' part of <title>Hello XXXX</title>
?
Yes. There's at least a couple of ways this can be done:
- Instead of converting the entire
<title>
tag into a template node, wrap the part of its content you want to modify in a<span node="-con:foo">...</span>
element. (The resulting template may not always be valid HTML, but rendered pages will be.) - Convert the
<title>
tag to a template node and have your script modify its existing content rather than replace it completely; for example:node.title.content = node.title.content.replace('XXXX', s)
Can the Repeater
class's repeat
method only iterate over lists, or can it work with any kind of iterable object?
Any object that supports iteration is fine.
I'd like to use a Repeater
without having to create a list of values to iterate over first. Is this possible?
Yes. If you know in advance how many times you want to repeat it, just use Python's built-in xrange
function; for example: node.foo.repeat(callback, xrange(n), *args)
. If you don't know, or want to stop repeating from within the callback function, this can be done as follows:
class FakeIterator:
"""Fake iterable object; passes itself as each 'item'.
Call its stop() method to stop iteration.
"""
def __init__(self):
self._stop = False
def stop(self):
self._stop = True
def __iter__(self):
return self
def next(self):
if self._stop:
raise StopIteration
else:
return self
def renderFoo(node, *args):
node.bar.repeat(renderBar, FakeIterator(), *args)
def renderBar(node, item, *args):
...
if shouldStop:
item.stop()
I'd like to render a table with alternately coloured rows. How can I do this?
Quite easily. See the sample/Demo5_AlternatingRowColors.py
script for a sample solution.
I'd like to render a large number of pages, all sharing the same navigation bar. For efficiency, I'd like to render this navigation bar only once rather than re-generating it for every page. Is this possible?
Yes. There are various ways to do this:
- Construct the page from two separate templates. Create one template for the page and another for the navigation bar. Add a placeholder node in the page template to hold the rendered navigation bar, e.g.
<div node="-con:navbar">...</div>
. Render the navigation bar template to HTML first, then pass the the result to the main template as an argument to eachrender()
call for it to insert into the placeholder node as raw markup:node.navbar.raw = navbarhtml
. - Construct the page from a single template. Before calling the template's
render()
method to generate the finished pages, pre-generate the template's navbar section:
Note that calling the navbar node'stemplate = Template(render_template, html) template.navbar.repeat(render_navbar, links) # pre-render navbar
repeat
method will always replace any previously generated content for that node, so you don't need to compile a fresh template if you want to replace this pre-rendered navbar later; just call the navbar node'srepeat
method again. (See the HTMLCalendar module for a working demonstration of this technique.)
How can I dynamically add HTML comments/directives/processing instructions to a rendered page?
HTMLTemplate doesn't support these HTML constructs as first-class nodes as this is rarely useful, but the relevant markup can be inserted easily enough via placeholder elements such as <div node="-con:mycomment"></div>
using code like: node.mycomment.raw = '<!-- %s -->' % commentstr
. Remember to perform any necessary validation on the content being inserted yourself (e.g. checking that commentstr
doesn't contain '--', which is invalid within a comment according to HTML/SGML rules).