Mercurial > genshi > mirror
diff doc/text-templates.txt @ 241:4d81439bc097 trunk
* Added basic documentation for the text-based template language.
* Directives in text templates are now closed with a simple `#end` line instead of the longer `#end<name>`.
author | cmlenz |
---|---|
date | Wed, 13 Sep 2006 14:52:58 +0000 |
parents | |
children | fa07ab5a7e53 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/doc/text-templates.txt @@ -0,0 +1,292 @@ +.. -*- mode: rst; encoding: utf-8 -*- + +============================= +Genshi Text Template Language +============================= + +In addition to the XML-based template language, Genshi provides a simple +text-based template language, intended for basic plain text generation needs. +The language is similar to Cheetah_ or Velocity_. + +.. _cheetah: http://cheetahtemplate.org/ +.. _velocity: http://jakarta.apache.org/velocity/ + +This document describes the template language and will be most useful as +reference to those developing Genshi text templates. Templates are XML files of some +kind (such as XHTML) that include processing directives_ (elements or +attributes identified by a separate namespace) that affect how the template is +rendered, and template expressions_ that are dynamically substituted by +variable data. + + +.. contents:: Contents + :depth: 3 +.. sectnum:: + +---------- +Python API +---------- + +The Python code required for templating with Genshi is generally based on the +following pattern: + +* Attain a ``Template`` object from a string or file object containing the + template source. This can either be done directly, or through a + ``TemplateLoader`` instance. +* Call the ``generate()`` method of the template, passing any data that should + be made available to the template as keyword arguments. +* Serialize the resulting stream using its ``render()`` method. + +For example:: + + from genshi.template import TextTemplate + + tmpl = TextTemplate('$title') + stream = tmpl.generate(title='Hello, world!') + print stream.render('text') + +That code would produce the following output:: + + Hello, world! + +Using a template loader provides the advantage that “compiled” templates are +automatically cached, and only parsed again when the template file changes:: + + from genshi.template import TemplateLoader + + loader = TemplateLoader([templates_dir]) + tmpl = loader.load('test.txt' cls=TextTemplate) + stream = tmpl.generate(title='Hello, world!') + print stream.render('text') + + +.. _`expressions`: + +-------------------- +Template Expressions +-------------------- + +Python_ expressions can be used in text and attribute values. An expression is +substituted with the result of its evaluation against the template data. +Expressions need to prefixed with a dollar sign (``$``) and usually enclosed in +curly braces (``{…}``). + +.. _python: http://www.python.org/ + +If the expression starts with a letter and contains only letters and digits, +the curly braces may be omitted. In all other cases, the braces are required +so that the template processors knows where the expression ends:: + + >>> from genshi.template import TextTemplate + >>> tmpl = TextTemplate('${items[0].capitalize()} item') + >>> print tmpl.generate(items=['first', 'second']) + First item + +Expressions support the full power of Python. In addition, it is possible to +access items in a dictionary using “dotted notation” (i.e. as if they were +attributes), and vice-versa (i.e. access attributes as if they were items in +a dictionary):: + + >>> from genshi.template import TextTemplate + >>> tmpl = TextTemplate('${dict.foo}') + >>> print tmpl.generate(dict={'foo': 'bar'}) + bar + + +.. _`directives`: + +------------------- +Template Directives +------------------- + +Directives are lines starting with a ``#`` character followed by the directive +name. They can affect how the template is rendered in a number of ways: Genshi +provides directives for conditionals and looping, among others. + +For example:: + + #if foo + Bar + #end + +Directives must be on separate lines, and the ``#`` character must be be the +first non-whitespace character on that line. Each directive must be “closed” +using a ``#end`` marker. + + +Conditional Sections +==================== + +.. _`#if`: + +``#if`` +--------- + +The content is only rendered if the expression evaluates to a truth value:: + + #if foo + ${bar} + #end + +Given the data ``foo=True`` and ``bar='Hello'`` in the template context, this +would produce:: + + Hello + + +.. _`#choose`: +.. _`#when`: +.. _`#otherwise`: + +``#choose`` +------------- + +The ``#choose`` directive, in combination with the directives ``#when`` and +``#otherwise`` provides advanced contional processing for rendering one of +several alternatives. The first matching ``#when`` branch is rendered, or, if +no ``#when`` branch matches, the ``#otherwise`` branch is be rendered. + +If the ``#choose`` directive has no argument the nested ``#when`` directives +will be tested for truth:: + + The answer is: + #choose + #when 0 == 1 + 0 + #end + #when 1 == 1 + 1 + #end + #otherwise + 2 + #end + #end + +This would produce the following output:: + + The answer is: + 1 + +If the ``#choose`` does have an argument, the nested ``#when`` directives will +be tested for equality to the parent ``#choose`` value:: + + The answer is: + #choose 1 + #when 0 + 0 + #end + #when 1 + 1 + #end + #otherwise + 2 + #end + #end + +This would produce the following output:: + + The answer is: + 1 + + +Looping +======= + +.. _`#for`: + +``#for`` +---------- + +The content is repeated for every item in an iterable:: + + Your items: + #for item in items + * ${item} + #end + +Given ``items=[1, 2, 3]`` in the context data, this would produce:: + + Your items + * 1 + * 2 + * 3 + + +Snippet Reuse +============= + +.. _`#def`: +.. _`macros`: + +``#def`` +---------- + +The ``#def`` directive can be used to create macros, i.e. snippets of template +text that have a name and optionally some parameters, and that can be inserted +in other places:: + + #def greeting(name) + Hello, ${name}! + #end + ${greeting('world')} + ${greeting('everyone else')} + +The above would be rendered to:: + + Hello, world! + Hello, everyone else! + +If a macro doesn't require parameters, it can be defined as well as called +without the parenthesis. For example:: + + #def greeting + Hello, world! + #end + ${greeting} + +The above would be rendered to:: + + Hello, world! + + +Variable Binding +================ + +.. _`#with`: + +``#with`` +----------- + +The ``#with`` directive lets you assign expressions to variables, which can +be used to make expressions inside the directive less verbose and more +efficient. For example, if you need use the expression ``author.posts`` more +than once, and that actually results in a database query, assigning the results +to a variable using this directive would probably help. + +For example:: + + Magic numbers! + #with y=7; z=x+10 + $x $y $z + #end + +Given ``x=42`` in the context data, this would produce:: + + Magic numbers! + 42 7 52 + +Note that if a variable of the same name already existed outside of the scope +of the ``#with`` directive, it will **not** be overwritten. Instead, it will +have the same value it had prior to the ``#with`` assignment. Effectively, +this means that variables are immutable in Genshi. + + +.. _comments: + +-------- +Comments +-------- + +Lines where the first non-whitespace characters are ``##`` are removed from +the output, and can thus be used for comments. This can be escaped using a +backslash.