HTMLTemplate Frequently Asked Questions
(C) 2004 HAS

----------------------------------------------------------------------
Questions about HTML templates

Q. What types of markup does HTMLTemplate accept?

A. 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 Manual.txt, Known Issues.


Q. Can HTMLTemplate be used for non-markup based templating?

A. It can, though it isn't designed for it; use texttemplate module instead.


Q. Does HTMLTemplate modify a template's original HTML markup at all?

A. Slightly: all tag attributes will be double- or single-quoted (a side-effect of using Python's HTMLParser module to parse the template).


Q. Do HTML templates need to be complete HTML documents with a single root element, or can HTMLTemplate handle arbitrary fragments of HTML too?

A. 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.


Q. Does HTMLTemplate support caching and/or pickling of compiled templates?

A. 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.


Q. Can HTMLTemplate use 'id' attributes or namespace-based attributes to indicate template nodes, e.g. for compatibility with WYSIWYG HTML editors?

A. 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.


Q. How does HTMLTemplate fit into the popular MVC (Model-View-Controller) application design pattern?

A. 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

Q. Is it possible to modify just part of an element's content; for example, replacing only the 'XXXX' part of '<title>Hello XXXX</title>'?

A. 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)


Q. Can the Repeater class's repeat() method only iterate over lists, or can it work with any kind of iterable object?

A. Any object that supports iteration is fine.


Q. I'd like to use a Repeater without having to create a list of values to iterate over first. Is this possible?

A. 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()


Q. I'd like to render a table with alternately coloured rows. How can I do this?

A. Quite easily. See the Examples/Demo5_AlternatingRowColors.py script for a sample solution.


Q. 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?

A. 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 each render() 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:

	template = Template(renderTemplate, html)
	template.navbar.repeat(renderNavbar, links) # pre-render navbar

Note that calling the navbar node's 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's repeat() method again. (See the HTMLCalendar module at <http://freespace.virgin.net/hamish.sanderson/htmlcalendar.html> for a working demonstration of this technique.)


Q. How can I dynamically add HTML comments/directives/processing instructions to a rendered page?

A. 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).


----------------------------------------------------------------------
Miscellaneous questions

Q. How did HTMLTemplate originate?

A. HTMLTemplate is actually a complete redesign of a much larger, more complex templating framework (itself a replacement to a more traditional and almost entirely abominable traditional "code-in-markup" templating system) that was originally partly inspired by the Zope Page Templates system. While this earlier system also combined directive-tagged HTML templates and native Controller code with some success (essentially just an extension of the ZPT philosophy of moving non-trivial program logic out of HTML templates and into native code), its multi-KLOC "all batteries included" kitchen-sink design was painful to maintain, imposed a steep learning curve on newcomers and proved awkward and inflexible in use. HTMLTemplate retains and refines its predecessor's core functionality while avoiding all the unnecessary bloat and "convenience [mis]features", resulting in a much smaller, better focussed API and compact, easy-to-manage codebase. A subsequent port to Python has seen both API and codebase tightened even further, with the finished result clocking in at approximately 350 lines of code and under a dozen public properties and methods, beating far larger, more complex templating systems in power, flexibility, reliability and ease of use.


Q. Is HTMLTemplate "finished"?

A. Yes. Unlike most templating systems, which tend to sprout new features over time, HTMLTemplate began life with a simple, well-defined, and more or less complete featureset and has largely remained that way. The Python version has spent six or so months between its first and final releases quietly cleaning and finessing the codebase and API until stable. [2004-06-16 -- Update: Graham Dumpleton reports that HTMLTemplate's current API is poorly suited to event-driven programming. A revised API is being worked on, though the resulting module may be released under a different name to avoid backwards-compatibility issues.]


Q. So no new features at all then?

A. No new features are planned for this distribution of HTMLTemplate. HTMLTemplate follows traditional Unix design philosophy and is intended to be compact, focussed and complete. Future improvements to documentation, tutorials, FAQ and examples may be made where user feedback or demand indicates the need to do so. Additional HTMLTemplate-related functionality may be released in future, though as independent modules not coupled to HTMLTemplate itself. For example, a module that provides functions for loading and compiling template HTML and controller modules stored on disk may be useful to some users, and could easily be implemented if there's demand.


Q. What about starting new development branches?

A. This is certainly an option: third-parties are certainly welcome to start new development branches to add their own modifications and features. I've done this a couple times myself to create a plain text templating module, texttemplate (currently in need of updating), and an experimental, non backwards-compatible fork with improved support for introspection and event-driven execution (currently unfinished and unreleased due to other commitments, unfortunately; interested parties can email me for a copy).


Q. Now it's complete, what will you do next?

A. Why, the same thing we do every night, Pinky: "Try to Take Over the World!!" :)

