diff doc/templates.txt @ 500:0742f421caba experimental-inline

Merged revisions 487-603 via svnmerge from http://svn.edgewall.org/repos/genshi/trunk
author cmlenz
date Fri, 01 Jun 2007 17:21:47 +0000
parents
children 1837f39efd6f
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/doc/templates.txt
@@ -0,0 +1,346 @@
+.. -*- mode: rst; encoding: utf-8 -*-
+
+========================
+Genshi Templating Basics
+========================
+
+Genshi provides a template engine that can be used for generating either
+markup (such as HTML_ or XML_) or plain text. While both share some of the
+syntax (and much of the underlying implementation) they are essentially
+separate languages.
+
+.. _html: http://www.w3.org/html/
+.. _xml: http://www.w3.org/XML/
+
+This document describes the common parts of the template engine and will be most
+useful as reference to those developing Genshi templates. Templates are XML or
+plain text files that include processing directives_ that affect how the
+template is rendered, and template expressions_ that are dynamically substituted
+by variable data.
+
+
+.. contents:: Contents
+   :depth: 3
+.. sectnum::
+
+--------
+Synopsis
+--------
+
+A Genshi *markup template* is a well-formed XML document with embedded Python
+used for control flow and variable substitution. Markup templates should be
+used to generate any kind of HTML or XML output, as they provide many advantages
+over simple text-based templates (such as automatic escaping of strings).
+
+The following illustrates a very basic Genshi markup template::
+
+  <?python
+    title = "A Genshi Template"
+    fruits = ["apple", "orange", "kiwi"]
+  ?>
+  <html xmlns:py="http://genshi.edgewall.org/">
+    <head>
+      <title py:content="title">This is replaced.</title>
+    </head>
+
+    <body>
+      <p>These are some of my favorite fruits:</p>
+      <ul>
+        <li py:for="fruit in fruits">
+          I like ${fruit}s
+        </li>
+      </ul>
+    </body>
+  </html>
+
+This example shows:
+
+(a) a Python code block, using a processing instruction
+(b) the Genshi namespace declaration
+(c) usage of templates directives (``py:content`` and ``py:for``)
+(d) an inline Python expression (``${fruit}``).
+
+The template would generate output similar to this::
+
+  <html>
+    <head>
+      <title>A Genshi Template</title>
+    </head>
+
+    <body>
+      <p>These are some of my favorite fruits:</p>
+      <ul>
+        <li>I like apples</li>
+        <li>I like oranges</li>
+        <li>I like kiwis</li>
+      </ul>
+    </body>
+  </html>
+
+A *text template* is a simple plain text document that can also contain embedded
+Python code. Text templates can be used to generate simple *non-markup* text
+formats, such as the body of an plain text email. For example::
+
+  Dear $name,
+  
+  These are some of my favorite fruits:
+  #for fruit in fruits
+   * $fruit
+  #end
+
+
+----------
+Python API
+----------
+
+The Python code required for templating with Genshi is generally based on the
+following pattern:
+
+* Attain a ``MarkupTemplate`` or ``TextTemplate`` object from a string or
+  file-like 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 MarkupTemplate
+  >>> tmpl = MarkupTemplate('<h1>Hello, $name!</h1>')
+  >>> stream = tmpl.generate(name='world')
+  >>> print stream.render()
+  <h1>Hello, world!</h1>
+
+Using a text template is similar::
+
+  >>> from genshi.template import TextTemplate
+  >>> tmpl = TextTemplate('Hello, $name!')
+  >>> stream = tmpl.generate(name='world')
+  >>> print stream.render()
+  Hello, world!
+
+.. note:: See the Serialization_ section of the `Markup Streams`_ page for
+          information on configuring template output options.
+
+.. _serialization: streams.html#serialization
+.. _`Markup Streams`: streams.html
+
+Using a template loader provides the advantage that “compiled” templates are
+automatically cached, and only parsed again when the template file changes. In
+addition, it enables the use of a *template search path*, allowing template
+directories to be spread across different file-system locations. Using a
+template loader would generally look as follows::
+
+  from genshi.template import TemplateLoader
+  loader = TemplateLoader([templates_dir1, templates_dir2])
+  tmpl = loader.load('test.html')
+  stream = tmpl.generate(title='Hello, world!')
+  print stream.render()
+
+See the `API documentation <api/index.html>`_ for details on using Genshi via
+the Python API.
+
+
+.. _`expressions`:
+
+------------------------------------
+Template Expressions and Code Blocks
+------------------------------------
+
+Python_ expressions can be used in text and directive arguments. An expression
+is substituted with the result of its evaluation against the template data.
+Expressions in text (which includes the values of non-directive attributes) 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, digits, dots,
+and underscores, the curly braces may be omitted. In all other cases, the
+braces are required so that the template processor knows where the expression
+ends::
+
+  >>> from genshi.template import MarkupTemplate
+  >>> tmpl = MarkupTemplate('<em>${items[0].capitalize()} item</em>')
+  >>> print tmpl.generate(items=['first', 'second'])
+  <em>First item</em>
+
+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 MarkupTemplate
+  >>> tmpl = MarkupTemplate('<em>${dict.foo}</em>')
+  >>> print tmpl.generate(dict={'foo': 'bar'})
+  <em>bar</em>
+
+Because there are two ways to access either attributes or items, expressions
+do not raise the standard ``AttributeError`` or ``IndexError`` exceptions, but
+rather an exception of the type ``UndefinedError``. The same kind of error is
+raised when you try to use a top-level variable that is not in the context data.
+See `Error Handling`_ below for details on how such errors are handled.
+
+
+.. _`code blocks`:
+
+Code Blocks
+===========
+
+XML templates also support full Python code blocks using the ``<?python ?>``
+processing instruction::
+
+  <div>
+    <?python
+        from genshi.builder import tag
+        def greeting(name):
+            return tag.b('Hello, %s!' % name') ?>
+    ${greeting('world')}
+  </div>
+
+This will produce the following output::
+
+  <div>
+    <b>Hello, world!</b>
+  </div>
+
+Code blocks can import modules, define classes and functions, and basically do
+anything you can do in normal Python code. What code blocks can *not* do is to
+produce content that is included directly in the generated page.
+
+.. note:: Using the ``print`` statement will print to the standard output
+          stream, just as it does for other Python code in your application.
+
+Unlike expressions, Python code in ``<?python ?>`` processing instructions can
+not use item and attribute access in an interchangeable manner. That means that
+“dotted notation” is always attribute access, and vice-versa.
+
+The support for Python code blocks in templates is not supposed to encourage
+mixing application code into templates, which is generally considered bad
+design. If you're using many code blocks, that may be a sign that you should
+move such code into separate Python modules.
+
+.. note:: Code blocks are not currently supported in text templates.
+
+
+.. _`error handling`:
+
+Error Handling
+==============
+
+By default, Genshi allows you to access variables that are not defined, without
+raising a ``NameError`` exception as regular Python code would::
+
+  >>> from genshi.template import MarkupTemplate
+  >>> tmpl = MarkupTemplate('<p>${doh}</p>')
+  >>> print tmpl.generate().render('xhtml')
+  <p></p>
+
+You *will* however get an exception if you try to call an undefined variable, or
+do anything else with it, such as accessing its attributes::
+
+  >>> from genshi.template import MarkupTemplate
+  >>> tmpl = MarkupTemplate('<p>${doh.oops}</p>')
+  >>> print tmpl.generate().render('xhtml')
+  Traceback (most recent call last):
+    ...
+  UndefinedError: "doh" not defined
+
+If you need to know whether a variable is defined, you can check its type
+against the ``Undefined`` class, for example in a conditional directive::
+
+  >>> from genshi.template import MarkupTemplate
+  >>> tmpl = MarkupTemplate('<p>${type(doh) is not Undefined}</p>')
+  >>> print tmpl.generate().render('xhtml')
+  <p>False</p>
+
+Alternatively, the built-in functions defined_ or value_of_ can be used in this
+case.
+
+Strict Mode
+-----------
+
+In addition to the default "lenient" error handling, Genshi lets you use a less
+forgiving mode if you prefer errors blowing up loudly instead of being ignored
+silently.
+
+This mode can be chosen by passing the ``lookup='strict'`` keyword argument to
+the template initializer, or by passing the ``variable_lookup='strict'`` keyword
+argument to the ``TemplateLoader`` initializer::
+
+  >>> from genshi.template import MarkupTemplate
+  >>> tmpl = MarkupTemplate('<p>${doh}</p>', lookup='strict')
+  >>> print tmpl.generate().render('xhtml')
+  Traceback (most recent call last):
+    ...
+  UndefinedError: "doh" not defined
+
+When using strict mode, any reference to an undefined variable, as well as
+trying to access an non-existing item or attribute of an object, will cause an
+``UndefinedError`` to be raised immediately.
+
+.. note:: While this mode is currently not the default, it may be promoted to
+          the default in future versions of Genshi. In general, the default
+          lenient error handling mode can be considered dangerous as it silently
+          ignores typos.
+
+Custom Modes
+------------
+
+In addition to the built-in "lenient" and "strict" modes, it is also possible to
+use a custom error handling mode. For example, you could use lenient error
+handling in a production environment, while also logging a warning when an
+undefined variable is referenced.
+
+See the API documentation of the ``genshi.template.eval`` module for details.
+
+
+Built-in Functions & Types
+==========================
+
+The following functions and types are available by default in template code, in
+addition to the standard built-ins that are available to all Python code.
+
+.. _`defined`:
+
+``defined(name)``
+-----------------
+This function determines whether a variable of the specified name exists in
+the context data, and returns ``True`` if it does.
+ 
+.. _`value_of`:
+
+``value_of(name, default=None)``
+--------------------------------
+This function returns the value of the variable with the specified name if
+such a variable is defined, and returns the value of the ``default``
+parameter if no such variable is defined.
+
+.. _`Markup`:
+
+``Markup(text)``
+----------------
+The ``Markup`` type marks a given string as being safe for inclusion in markup,
+meaning it will *not* be escaped in the serialization stage. Use this with care,
+as not escaping a user-provided string may allow malicious users to open your
+web site to cross-site scripting attacks.
+
+.. _`Undefined`:
+
+``Undefined``
+----------------
+The ``Undefined`` type can be used to check whether a reference variable is
+defined, as explained in `error handling`_.
+
+
+.. _`directives`:
+
+-------------------
+Template Directives
+-------------------
+
+Directives provide control flow functionality for templates, such as conditions
+or iteration. As the syntax for directives depends on whether you're using
+markup or text templates, refer to the
+`XML Template Language <xml-templates.html>`_ or
+`Text Template Language <text-templates.html>`_ pages for information.
Copyright (C) 2012-2017 Edgewall Software