cmlenz@241: .. -*- mode: rst; encoding: utf-8 -*- cmlenz@241: cmlenz@241: ============================= cmlenz@241: Genshi Text Template Language cmlenz@241: ============================= cmlenz@241: cmlenz@241: In addition to the XML-based template language, Genshi provides a simple cmlenz@241: text-based template language, intended for basic plain text generation needs. cmlenz@241: The language is similar to Cheetah_ or Velocity_. cmlenz@241: cmlenz@241: .. _cheetah: http://cheetahtemplate.org/ cmlenz@241: .. _velocity: http://jakarta.apache.org/velocity/ cmlenz@241: cmlenz@241: This document describes the template language and will be most useful as cmlenz@241: reference to those developing Genshi text templates. Templates are XML files of some cmlenz@241: kind (such as XHTML) that include processing directives_ (elements or cmlenz@241: attributes identified by a separate namespace) that affect how the template is cmlenz@241: rendered, and template expressions_ that are dynamically substituted by cmlenz@241: variable data. cmlenz@241: cmlenz@241: cmlenz@241: .. contents:: Contents cmlenz@241: :depth: 3 cmlenz@241: .. sectnum:: cmlenz@241: cmlenz@241: ---------- cmlenz@241: Python API cmlenz@241: ---------- cmlenz@241: cmlenz@241: The Python code required for templating with Genshi is generally based on the cmlenz@241: following pattern: cmlenz@241: cmlenz@244: * Attain a ``TextTemplate`` object from a string or file object containing the cmlenz@241: template source. This can either be done directly, or through a cmlenz@241: ``TemplateLoader`` instance. cmlenz@241: * Call the ``generate()`` method of the template, passing any data that should cmlenz@241: be made available to the template as keyword arguments. cmlenz@241: * Serialize the resulting stream using its ``render()`` method. cmlenz@241: cmlenz@241: For example:: cmlenz@241: cmlenz@241: from genshi.template import TextTemplate cmlenz@241: cmlenz@241: tmpl = TextTemplate('$title') cmlenz@241: stream = tmpl.generate(title='Hello, world!') cmlenz@241: print stream.render('text') cmlenz@241: cmlenz@241: That code would produce the following output:: cmlenz@241: cmlenz@241: Hello, world! cmlenz@241: cmlenz@241: Using a template loader provides the advantage that “compiled” templates are cmlenz@241: automatically cached, and only parsed again when the template file changes:: cmlenz@241: cmlenz@241: from genshi.template import TemplateLoader cmlenz@241: cmlenz@241: loader = TemplateLoader([templates_dir]) cmlenz@241: tmpl = loader.load('test.txt' cls=TextTemplate) cmlenz@241: stream = tmpl.generate(title='Hello, world!') cmlenz@241: print stream.render('text') cmlenz@241: cmlenz@241: cmlenz@241: .. _`expressions`: cmlenz@241: cmlenz@241: -------------------- cmlenz@241: Template Expressions cmlenz@241: -------------------- cmlenz@241: cmlenz@244: Python_ expressions can be used in text and as arguments to directives_. An expression is substituted with the result of its evaluation against the cmlenz@244: template data. Expressions need to prefixed with a dollar sign (``$``) and cmlenz@244: usually enclosed in curly braces (``{…}``). cmlenz@241: cmlenz@241: .. _python: http://www.python.org/ cmlenz@241: cmlenz@394: If the expression starts with a letter and contains only letters, digits, dots, cmlenz@394: and underscores, the curly braces may be omitted. In all other cases, the cmlenz@394: braces are required so that the template processor knows where the expression cmlenz@394: ends:: cmlenz@241: cmlenz@241: >>> from genshi.template import TextTemplate cmlenz@241: >>> tmpl = TextTemplate('${items[0].capitalize()} item') cmlenz@241: >>> print tmpl.generate(items=['first', 'second']) cmlenz@241: First item cmlenz@241: cmlenz@241: Expressions support the full power of Python. In addition, it is possible to cmlenz@241: access items in a dictionary using “dotted notation” (i.e. as if they were cmlenz@241: attributes), and vice-versa (i.e. access attributes as if they were items in cmlenz@241: a dictionary):: cmlenz@241: cmlenz@241: >>> from genshi.template import TextTemplate cmlenz@241: >>> tmpl = TextTemplate('${dict.foo}') cmlenz@241: >>> print tmpl.generate(dict={'foo': 'bar'}) cmlenz@241: bar cmlenz@241: cmlenz@429: Because there are two ways to access either attributes or items, expressions cmlenz@429: do not raise the standard ``AttributeError`` or ``IndexError`` exceptions, but cmlenz@429: rather an exception of the type ``UndefinedError``. The same kind of error is cmlenz@429: raised when you try to access a top-level variable that is not in the context cmlenz@429: data. cmlenz@244: cmlenz@429: Built-in Functions & Types cmlenz@429: ========================== cmlenz@244: cmlenz@429: The following functions and types are available by default in template code, in cmlenz@429: addition to the standard built-ins that are available to all Python code. cmlenz@429: cmlenz@429: ``defined(name)`` cmlenz@429: ----------------- cmlenz@429: cmlenz@429: This function determines whether a variable of the specified name exists in cmlenz@429: the context data, and returns ``True`` if it does. cmlenz@429: cmlenz@429: ``value_of(name, default=None)`` cmlenz@429: -------------------------------- cmlenz@429: cmlenz@429: This function returns the value of the variable with the specified name if cmlenz@429: such a variable is defined, and returns the value of the ``default`` cmlenz@429: parameter if no such variable is defined. cmlenz@429: cmlenz@429: ``Markup(text)`` cmlenz@429: ---------------- cmlenz@429: cmlenz@429: The ``Markup`` type marks a given string as being safe for inclusion in markup, cmlenz@429: meaning it will *not* be escaped in the serialization stage. Use this with care, cmlenz@429: as not escaping a user-provided string may allow malicious users to open your cmlenz@429: web site to cross-site scripting attacks. cmlenz@244: cmlenz@241: cmlenz@241: .. _`directives`: cmlenz@241: cmlenz@241: ------------------- cmlenz@241: Template Directives cmlenz@241: ------------------- cmlenz@241: cmlenz@354: Directives are lines starting with a ``#`` character followed immediately by cmlenz@354: the directive name. They can affect how the template is rendered in a number of cmlenz@244: ways: Genshi provides directives for conditionals and looping, among others. cmlenz@241: cmlenz@241: Directives must be on separate lines, and the ``#`` character must be be the cmlenz@241: first non-whitespace character on that line. Each directive must be “closed” cmlenz@246: using a ``#end`` marker. You can add after the ``#end`` marker, for example to cmlenz@246: document which directive is being closed, or even the expression associated with cmlenz@246: that directive. Any text after ``#end`` (but on the same line) is ignored, cmlenz@246: and effectively treated as a comment. cmlenz@241: cmlenz@244: If you want to include a literal ``#`` in the output, you need to escape it cmlenz@244: by prepending a backslash character (``\``). Note that this is **not** required cmlenz@244: if the ``#`` isn't immediately followed by a letter, or it isn't the first cmlenz@244: non-whitespace character on the line. cmlenz@244: cmlenz@241: cmlenz@241: Conditional Sections cmlenz@241: ==================== cmlenz@241: cmlenz@241: .. _`#if`: cmlenz@241: cmlenz@241: ``#if`` cmlenz@241: --------- cmlenz@241: cmlenz@241: The content is only rendered if the expression evaluates to a truth value:: cmlenz@241: cmlenz@241: #if foo cmlenz@241: ${bar} cmlenz@241: #end cmlenz@241: cmlenz@241: Given the data ``foo=True`` and ``bar='Hello'`` in the template context, this cmlenz@241: would produce:: cmlenz@241: cmlenz@241: Hello cmlenz@241: cmlenz@241: cmlenz@241: .. _`#choose`: cmlenz@241: .. _`#when`: cmlenz@241: .. _`#otherwise`: cmlenz@241: cmlenz@241: ``#choose`` cmlenz@241: ------------- cmlenz@241: cmlenz@241: The ``#choose`` directive, in combination with the directives ``#when`` and cmlenz@241: ``#otherwise`` provides advanced contional processing for rendering one of cmlenz@241: several alternatives. The first matching ``#when`` branch is rendered, or, if cmlenz@241: no ``#when`` branch matches, the ``#otherwise`` branch is be rendered. cmlenz@241: cmlenz@241: If the ``#choose`` directive has no argument the nested ``#when`` directives cmlenz@241: will be tested for truth:: cmlenz@241: cmlenz@241: The answer is: cmlenz@241: #choose cmlenz@241: #when 0 == 1 cmlenz@241: 0 cmlenz@241: #end cmlenz@241: #when 1 == 1 cmlenz@241: 1 cmlenz@241: #end cmlenz@241: #otherwise cmlenz@241: 2 cmlenz@241: #end cmlenz@241: #end cmlenz@241: cmlenz@241: This would produce the following output:: cmlenz@241: cmlenz@241: The answer is: cmlenz@241: 1 cmlenz@241: cmlenz@241: If the ``#choose`` does have an argument, the nested ``#when`` directives will cmlenz@241: be tested for equality to the parent ``#choose`` value:: cmlenz@241: cmlenz@241: The answer is: cmlenz@241: #choose 1 cmlenz@241: #when 0 cmlenz@241: 0 cmlenz@241: #end cmlenz@241: #when 1 cmlenz@241: 1 cmlenz@241: #end cmlenz@241: #otherwise cmlenz@241: 2 cmlenz@241: #end cmlenz@241: #end cmlenz@241: cmlenz@241: This would produce the following output:: cmlenz@241: cmlenz@241: The answer is: cmlenz@241: 1 cmlenz@241: cmlenz@241: cmlenz@241: Looping cmlenz@241: ======= cmlenz@241: cmlenz@241: .. _`#for`: cmlenz@241: cmlenz@241: ``#for`` cmlenz@241: ---------- cmlenz@241: cmlenz@241: The content is repeated for every item in an iterable:: cmlenz@241: cmlenz@241: Your items: cmlenz@241: #for item in items cmlenz@241: * ${item} cmlenz@241: #end cmlenz@241: cmlenz@241: Given ``items=[1, 2, 3]`` in the context data, this would produce:: cmlenz@241: cmlenz@241: Your items cmlenz@241: * 1 cmlenz@241: * 2 cmlenz@241: * 3 cmlenz@241: cmlenz@241: cmlenz@241: Snippet Reuse cmlenz@241: ============= cmlenz@241: cmlenz@241: .. _`#def`: cmlenz@241: .. _`macros`: cmlenz@241: cmlenz@241: ``#def`` cmlenz@241: ---------- cmlenz@241: cmlenz@241: The ``#def`` directive can be used to create macros, i.e. snippets of template cmlenz@241: text that have a name and optionally some parameters, and that can be inserted cmlenz@241: in other places:: cmlenz@241: cmlenz@241: #def greeting(name) cmlenz@241: Hello, ${name}! cmlenz@241: #end cmlenz@241: ${greeting('world')} cmlenz@241: ${greeting('everyone else')} cmlenz@241: cmlenz@241: The above would be rendered to:: cmlenz@241: cmlenz@241: Hello, world! cmlenz@241: Hello, everyone else! cmlenz@241: cmlenz@241: If a macro doesn't require parameters, it can be defined as well as called cmlenz@241: without the parenthesis. For example:: cmlenz@241: cmlenz@241: #def greeting cmlenz@241: Hello, world! cmlenz@241: #end cmlenz@241: ${greeting} cmlenz@241: cmlenz@241: The above would be rendered to:: cmlenz@241: cmlenz@241: Hello, world! cmlenz@241: cmlenz@241: cmlenz@241: Variable Binding cmlenz@241: ================ cmlenz@241: cmlenz@241: .. _`#with`: cmlenz@241: cmlenz@241: ``#with`` cmlenz@241: ----------- cmlenz@241: cmlenz@241: The ``#with`` directive lets you assign expressions to variables, which can cmlenz@241: be used to make expressions inside the directive less verbose and more cmlenz@241: efficient. For example, if you need use the expression ``author.posts`` more cmlenz@241: than once, and that actually results in a database query, assigning the results cmlenz@241: to a variable using this directive would probably help. cmlenz@241: cmlenz@241: For example:: cmlenz@241: cmlenz@241: Magic numbers! cmlenz@241: #with y=7; z=x+10 cmlenz@241: $x $y $z cmlenz@241: #end cmlenz@241: cmlenz@241: Given ``x=42`` in the context data, this would produce:: cmlenz@241: cmlenz@241: Magic numbers! cmlenz@241: 42 7 52 cmlenz@241: cmlenz@241: Note that if a variable of the same name already existed outside of the scope cmlenz@241: of the ``#with`` directive, it will **not** be overwritten. Instead, it will cmlenz@241: have the same value it had prior to the ``#with`` assignment. Effectively, cmlenz@241: this means that variables are immutable in Genshi. cmlenz@241: cmlenz@241: cmlenz@241: .. _comments: cmlenz@241: cmlenz@241: -------- cmlenz@241: Comments cmlenz@241: -------- cmlenz@241: cmlenz@241: Lines where the first non-whitespace characters are ``##`` are removed from cmlenz@241: the output, and can thus be used for comments. This can be escaped using a cmlenz@241: backslash.