TemplateParser » History » Version 12
Version 11 (Elmer de Looff, 2012-02-10 14:50) → Version 12/56 (Elmer de Looff, 2012-02-10 15:03)
h1. TemplateParser
The µWeb TemplateParser is a in-house developed templating engine that provides tag replacement, tag-functions and template control functions. This document will describe the following:
* The [[TemplateParser#template|Template class]], used to parse the templating language
* The [[TemplateParser#parser|Parser class]], which provides template loading and caching
* [[TemplateParser#using|Using TemplateParser]] inside a µWeb PageMaker
* [[TemplateParser#syntax|Template syntax]], an overview of the language's constructs and behaviors
First though, to help with understanding the TemplateParser, a minimal size template document:
<pre><code class="html">
Hello [title] [name]
</code></pre>
The above document contains two simple template tags. These tags are delimited by square brackets, and they will be replaced by the named argument provided during parsing. If this name is not present, then the literal presentation of the tag will remain in the output.
h1(#template). Template class
The @Template@ class provides the interface for pre-parsing templates, loading them from files and parsing single templates to completion. During pre-parsing, constructs such as loops and conditional statements are converted to @TemplateLoop@ and @TemplateConditional@ objects, and their scopes nested appropriately in the @Template@. Tags are replaced by @TemplateTag@ instances, and text is captured in @TemplateText@. All of these provide @Parse@ methods, which together result in the combined parsed template output.
h2. Creating a template
A template is created simple by providing a string input to the @Template@'s constructor. This will return a valid Template instance (or raise an error if there is a problem with the [[TemplateParser#syntax|syntax]]:
<pre><code class="python">
import templateparser
>>> template = templateparser.Template('Hello [title] [name]')
>>> template
Template([TemplateText('Hello '), TemplateTag('[title]'), TemplateText(' '), TemplateTag('[name]')])
</code></pre>
Above can be seen the various parts of the template, which will be combined to output once parsed.
h2. Loading a template from file
The @Template@ class provides a @classmethod@ called @FromFile@, which loads the template at the path.
Loading a template named @example.utp@ from the current working directory:
<pre><code class="python">
import templateparser
>>> template = templateparser.Template.FromFile('example.utp')
>>> template
Template([TemplateText('Hello '), TemplateTag('[title]'), TemplateText(' '), TemplateTag('[name]')])
</code></pre>
h2. Parsing a template
Parsing a template can be done by calling the @Template@'s @Parse@ method. The keyword arguments provided to this call will from the replacement mapping for the template. In the following example, we will provide one such keyword, and leave the other undefined to show the (basic) behavior of the @Template.Parse@ method.
<pre><code class="python">
import templateparser
>>> template = templateparser.Template('Hello [title] [name]')
>>> template.Parse(title='sir')
'Hello sir [name]'
</code></pre>
h1(#parser). Parser class
The @Parser@ class provides simple management of multiple @Template@ objects. It is mainly used to load templates from disk. When initiating a @Parser@, the first argument provides the search path from where templates should be loaded (the default is the current working directory). An optional second argument can be provided to preload the template cache: a mapping of names and @Template@ objects.
h2. Loading templates
Creating a parser object, and loading the 'example.utp' template from the 'templates' directory works like this:
<pre><code class="python">
import templateparser
>>> # This sets the 'templates' directory as the search path for AddTemplate
>>> parser = templateparser.Parser('templates')
>>> # Loads the 'templates/example.utp' and stores it as 'example.utp':
>>> template = parser.AddTemplate('example.utp')
>>> template.Parse(title='mister', name='Bob Dobalina')
'Hello mister Bob Dobalina'
</code></pre>
The @AddTemplate@ method takes a second optional argument, which allows us to give the template a different name in the cache, which we will now explain.
h2. Template cache and auto-loading
The @Parser@ object behaves like a slightly modified dictionary to achieve this. Retrieving keys yields the associated template. Keys that are not present in the cache are _automatically_ retrieved from the filesystem:
<pre><code class="python">
import templateparser
>>> parser = templateparser.Parser('templates')
>>> parser
Parser({}) # The parser is empty (has no cached templates)
>>> # Automatically loads the named template from the 'templates' directory:
>>> parser['example.utp'].Parse(title='mister', name='Bob Dobalina')
'Hello mister Bob Dobalina'
>>> parser
Parser({'example.utp': Template([TemplateText('Hello '), TemplateTag('[title]'),
TemplateText(' '), TemplateTag('[name]')])})
</code></pre>
If these cannot be found, @TemplateReadError@ is raised:
<pre><code class="python">
import templateparser
>>> parser = templateparser.Parser('templates')
>>> parser['bad_template.utp'].Parse(failure='imminent')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/var/lib/underdark/libs/uweb/templateparser.py", line 147, in __getitem__
self.AddTemplate(template)
File "/var/lib/underdark/libs/uweb/templateparser.py", line 171, in AddTemplate
raise TemplateReadError('Could not load template %r' % template_path)
underdark.libs.uweb.templateparser.TemplateReadError: Could not load template 'templates/bad_template.utp'
</code></pre>
h2. @Parse@ and @ParseString@
For convencience and consistency, the @Parser@ comes with two handy methods to provide parsing of @Template@ objects, one from its cache, one from raw template strings. It is recommended to use these over the previously shown direct key-based access:
<pre><code class="python">
import templateparser
>>> parser = templateparser.Parser('templates')
>>> parser.Parse('example.utp', title='mister', name='Bob Dobalina')
'Hello mister Bob Dobalina'
>>> parser.ParseString('Hello [title] [name]', title='mister', name='Bob Dobalina')
'Hello mister Bob Dobalina'</code></pre>
h1(#using). Using TemplateParser inside µWeb
Within the default µWeb @PageMaker@, there is a @parser@ property, which provides a [[TemplateParser#parser|Parser]] object. The class constant @TEMPLATE_DIR@ provides the template search directory. The default template directory is @'templates'@. *N.B.* This path is relative to the file that contains the PageMaker class.
An example of TemplateParser to create a complete response:
<pre><code class="python">
from underdark.libs import uweb
import time
class PageMaker(uweb.PageMaker):
def VersionPage(self):
return self.parser.Parse(
'version.utp', year=time.strftime('%Y'), version=uweb.__version__)
</code></pre>
The example template for the above file could look something like this:
<pre><code class="html">
<!DOCTYPE html>
<html>
<head>
<title>µWeb version info</title>
</head>
<body>
<p>µWeb version [version] - Copyright 2010-[year] Underdark</p>
</body>
</html>
</code></pre>
h1(#syntax). Templating language syntax
The templating syntax is relatively limited, but with the limited syntax it provides a flexible and rich system to create templates. Covered in these examples are:
* Simple tags (used in various examples above)
* Tag indexing
* Tag functions
* Template language constructs
All examples will consist of three parts:
# The example template
# The python invocation string (the template will be named 'example.utp')
# The resulting output (as source, not as parsed HTML)
h2. Simple tags
This is an example for the most basic form of template tags. The tag is enclosed by square brackets as such: @[tag]@. Tags that match a provided argument to the Parse call get replaced. If there is no argument that matches the tag name, it is returned in the output verbatim. This is also demonstrated in the below example
The example below is a repeat of the example how to use TemplateParser inside µWeb, and shows the template result:
<pre><code class="html">
<!DOCTYPE html>
<html>
<head>
<title>µWeb version info</title>
</head>
<body>
<p>µWeb version [version] - Copyright 2010-[year] Underdark</p>
<p>
This [paragraph] is not replaced because there is no
paragraph argument provided to the parser.
</p>
</body>
</html>
</code></pre>
<pre><code class="python">
>>> parser.Parse('version.utp', year=time.strftime('%Y'), version=uweb.__version__)
</code></pre>
<pre><code class="html">
<!DOCTYPE html>
<html>
<head>
<title>µWeb version info</title>
</head>
<body>
<p>µWeb version 0.11 - Copyright 2010-212 Underdark</p>
<p>
This [paragraph] is not replaced because there is no
paragraph argument provided to the parser.
</p>
</body>
</html>
</code></pre>
h2. Tag indexing
h2. Tag functions
h3. Default html escaping
h3. Adding custom functions
h2. For loops
h2. Inlining templates
h2. Conditional statements
h2. Template unicode handling
Any @unicode@ object found while parsing, will automatically be encoded to UTF-8:
<pre><code class="python">
>>> template = 'Underdark [love] [app]'
>>> output = parser.ParseString(template, love=u'\u2665', app=u'\N{micro sign}Web')
>>> output
'Underdark Underdark \xe2\x99\xa5 \xc2\xb5Web' \xc2\xb5Web # The output in its raw UTF-8 representation
>>> output.decode('UTF8')
u'Underdark \u2665 \xb5Web' # The output converted to a Unicode object
>>> print output
Underdark ♥ µWeb # Printing the output in an UTF-8 environment
</code></pre>
The µWeb TemplateParser is a in-house developed templating engine that provides tag replacement, tag-functions and template control functions. This document will describe the following:
* The [[TemplateParser#template|Template class]], used to parse the templating language
* The [[TemplateParser#parser|Parser class]], which provides template loading and caching
* [[TemplateParser#using|Using TemplateParser]] inside a µWeb PageMaker
* [[TemplateParser#syntax|Template syntax]], an overview of the language's constructs and behaviors
First though, to help with understanding the TemplateParser, a minimal size template document:
<pre><code class="html">
Hello [title] [name]
</code></pre>
The above document contains two simple template tags. These tags are delimited by square brackets, and they will be replaced by the named argument provided during parsing. If this name is not present, then the literal presentation of the tag will remain in the output.
h1(#template). Template class
The @Template@ class provides the interface for pre-parsing templates, loading them from files and parsing single templates to completion. During pre-parsing, constructs such as loops and conditional statements are converted to @TemplateLoop@ and @TemplateConditional@ objects, and their scopes nested appropriately in the @Template@. Tags are replaced by @TemplateTag@ instances, and text is captured in @TemplateText@. All of these provide @Parse@ methods, which together result in the combined parsed template output.
h2. Creating a template
A template is created simple by providing a string input to the @Template@'s constructor. This will return a valid Template instance (or raise an error if there is a problem with the [[TemplateParser#syntax|syntax]]:
<pre><code class="python">
import templateparser
>>> template = templateparser.Template('Hello [title] [name]')
>>> template
Template([TemplateText('Hello '), TemplateTag('[title]'), TemplateText(' '), TemplateTag('[name]')])
</code></pre>
Above can be seen the various parts of the template, which will be combined to output once parsed.
h2. Loading a template from file
The @Template@ class provides a @classmethod@ called @FromFile@, which loads the template at the path.
Loading a template named @example.utp@ from the current working directory:
<pre><code class="python">
import templateparser
>>> template = templateparser.Template.FromFile('example.utp')
>>> template
Template([TemplateText('Hello '), TemplateTag('[title]'), TemplateText(' '), TemplateTag('[name]')])
</code></pre>
h2. Parsing a template
Parsing a template can be done by calling the @Template@'s @Parse@ method. The keyword arguments provided to this call will from the replacement mapping for the template. In the following example, we will provide one such keyword, and leave the other undefined to show the (basic) behavior of the @Template.Parse@ method.
<pre><code class="python">
import templateparser
>>> template = templateparser.Template('Hello [title] [name]')
>>> template.Parse(title='sir')
'Hello sir [name]'
</code></pre>
h1(#parser). Parser class
The @Parser@ class provides simple management of multiple @Template@ objects. It is mainly used to load templates from disk. When initiating a @Parser@, the first argument provides the search path from where templates should be loaded (the default is the current working directory). An optional second argument can be provided to preload the template cache: a mapping of names and @Template@ objects.
h2. Loading templates
Creating a parser object, and loading the 'example.utp' template from the 'templates' directory works like this:
<pre><code class="python">
import templateparser
>>> # This sets the 'templates' directory as the search path for AddTemplate
>>> parser = templateparser.Parser('templates')
>>> # Loads the 'templates/example.utp' and stores it as 'example.utp':
>>> template = parser.AddTemplate('example.utp')
>>> template.Parse(title='mister', name='Bob Dobalina')
'Hello mister Bob Dobalina'
</code></pre>
The @AddTemplate@ method takes a second optional argument, which allows us to give the template a different name in the cache, which we will now explain.
h2. Template cache and auto-loading
The @Parser@ object behaves like a slightly modified dictionary to achieve this. Retrieving keys yields the associated template. Keys that are not present in the cache are _automatically_ retrieved from the filesystem:
<pre><code class="python">
import templateparser
>>> parser = templateparser.Parser('templates')
>>> parser
Parser({}) # The parser is empty (has no cached templates)
>>> # Automatically loads the named template from the 'templates' directory:
>>> parser['example.utp'].Parse(title='mister', name='Bob Dobalina')
'Hello mister Bob Dobalina'
>>> parser
Parser({'example.utp': Template([TemplateText('Hello '), TemplateTag('[title]'),
TemplateText(' '), TemplateTag('[name]')])})
</code></pre>
If these cannot be found, @TemplateReadError@ is raised:
<pre><code class="python">
import templateparser
>>> parser = templateparser.Parser('templates')
>>> parser['bad_template.utp'].Parse(failure='imminent')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/var/lib/underdark/libs/uweb/templateparser.py", line 147, in __getitem__
self.AddTemplate(template)
File "/var/lib/underdark/libs/uweb/templateparser.py", line 171, in AddTemplate
raise TemplateReadError('Could not load template %r' % template_path)
underdark.libs.uweb.templateparser.TemplateReadError: Could not load template 'templates/bad_template.utp'
</code></pre>
h2. @Parse@ and @ParseString@
For convencience and consistency, the @Parser@ comes with two handy methods to provide parsing of @Template@ objects, one from its cache, one from raw template strings. It is recommended to use these over the previously shown direct key-based access:
<pre><code class="python">
import templateparser
>>> parser = templateparser.Parser('templates')
>>> parser.Parse('example.utp', title='mister', name='Bob Dobalina')
'Hello mister Bob Dobalina'
>>> parser.ParseString('Hello [title] [name]', title='mister', name='Bob Dobalina')
'Hello mister Bob Dobalina'</code></pre>
h1(#using). Using TemplateParser inside µWeb
Within the default µWeb @PageMaker@, there is a @parser@ property, which provides a [[TemplateParser#parser|Parser]] object. The class constant @TEMPLATE_DIR@ provides the template search directory. The default template directory is @'templates'@. *N.B.* This path is relative to the file that contains the PageMaker class.
An example of TemplateParser to create a complete response:
<pre><code class="python">
from underdark.libs import uweb
import time
class PageMaker(uweb.PageMaker):
def VersionPage(self):
return self.parser.Parse(
'version.utp', year=time.strftime('%Y'), version=uweb.__version__)
</code></pre>
The example template for the above file could look something like this:
<pre><code class="html">
<!DOCTYPE html>
<html>
<head>
<title>µWeb version info</title>
</head>
<body>
<p>µWeb version [version] - Copyright 2010-[year] Underdark</p>
</body>
</html>
</code></pre>
h1(#syntax). Templating language syntax
The templating syntax is relatively limited, but with the limited syntax it provides a flexible and rich system to create templates. Covered in these examples are:
* Simple tags (used in various examples above)
* Tag indexing
* Tag functions
* Template language constructs
All examples will consist of three parts:
# The example template
# The python invocation string (the template will be named 'example.utp')
# The resulting output (as source, not as parsed HTML)
h2. Simple tags
This is an example for the most basic form of template tags. The tag is enclosed by square brackets as such: @[tag]@. Tags that match a provided argument to the Parse call get replaced. If there is no argument that matches the tag name, it is returned in the output verbatim. This is also demonstrated in the below example
The example below is a repeat of the example how to use TemplateParser inside µWeb, and shows the template result:
<pre><code class="html">
<!DOCTYPE html>
<html>
<head>
<title>µWeb version info</title>
</head>
<body>
<p>µWeb version [version] - Copyright 2010-[year] Underdark</p>
<p>
This [paragraph] is not replaced because there is no
paragraph argument provided to the parser.
</p>
</body>
</html>
</code></pre>
<pre><code class="python">
>>> parser.Parse('version.utp', year=time.strftime('%Y'), version=uweb.__version__)
</code></pre>
<pre><code class="html">
<!DOCTYPE html>
<html>
<head>
<title>µWeb version info</title>
</head>
<body>
<p>µWeb version 0.11 - Copyright 2010-212 Underdark</p>
<p>
This [paragraph] is not replaced because there is no
paragraph argument provided to the parser.
</p>
</body>
</html>
</code></pre>
h2. Tag indexing
h2. Tag functions
h3. Default html escaping
h3. Adding custom functions
h2. For loops
h2. Inlining templates
h2. Conditional statements
h2. Template unicode handling
Any @unicode@ object found while parsing, will automatically be encoded to UTF-8:
<pre><code class="python">
>>> template = 'Underdark [love] [app]'
>>> output = parser.ParseString(template, love=u'\u2665', app=u'\N{micro sign}Web')
>>> output
'Underdark Underdark \xe2\x99\xa5 \xc2\xb5Web' \xc2\xb5Web # The output in its raw UTF-8 representation
>>> output.decode('UTF8')
u'Underdark \u2665 \xb5Web' # The output converted to a Unicode object
>>> print output
Underdark ♥ µWeb # Printing the output in an UTF-8 environment
</code></pre>