Introduction

text-template is a small but powerful (as it is often in lisp) template library written in scheme. It can be used to generate any type of text - html, sql, code. Currently it supports SISC and PLT-Scheme scheme implementations, but it could be easily ported to other implementations. This is an open source software licensed under GPL.

Features

Text-based - text templates are more flexible then xml-based templates like xslt or other homebrew templates like this:

Xml-based templates have to be valid xml-documents itself and template expressions are usually represented by tags. This leads to bloated templates. In the above example there is code duplication caused by because it is not possible to inline condition into tag attribute "class", because you can't
Actually, text-template was developed to replace templates like presented above with this:

Compilable to function - template is parsed and compiled into function of context which can be then called many times. It means that there is no parsing or interpretation of template every time you use it.

Template expressions are s-expressions. It means that template expressions have some nice features of lisp syntax: regular, flexible, powerful, your-favorite-thing-about-lisp-syntax-here.

Dynamic scoping. This is just what it turned out to be and it seems to be natural scoping for templates. There is nothing about "dynamic vs lexical scope" in general.

Extendable - it is possible to use any type of object in template, you only need provide three accessor functions: (->string value), (->iterator value), (get-child value name).

You can also extend templates with your functions. Suppose you register function html which escapes html special charecters like &, <, >. After this you can use it in your templates like this: ${(html user_comment)} and be safe from XSS attacks.

Usage

Here are some examples of how to use templates

Prepare to work

At first implementation-specific code should be loaded, which load several libraries that text-template requires.

Simple value substitution

(context/set-generic context "name" "Nikita")
(context/set-generic context "age" "23")
((compile-template "Your name is ${name} and you are ${age} years old") context)
-->Your name is Nikita and you are 23 years old

Conditions

Template expressions may use several special forms: if, not, or, and.
Every context that is created with (create-context) is a child of default-context which has several buil-in functions. One of those was already mentioned - foreach. There are also functions that return boolean value and they can be used in conditionals. These are: =, <, >, set?, even?.

Appliyng anonymous template with no arguments syntax

In the example above "({|yes and its value is: ${b}})" means: apply anonymous template with no arguments. It is just like using ((lambda() (do1)(do2))) to have several things be done sequentially. Scheme has begin for this purpose and so text-template has #marker#body#marker#. marker can be anything (even nothing) and it defines where template body ends. So our previous example can be rewritten as follows:

((compile-template "b is set: ${(if (set? 'b') #1#yes and its value is: ${b}, by the way we can use ## here #1# 'no')}") context)
-->b is set: yes and its value is: whatever, by the way we can use ## here

Values

Context is a map of name - value, where value is any object with several access functions: (->string value), (->iterator value), (get-child value name). Actually value is a vector: (vector value ->string get-child ->iterator). If string, number, list or hashtable is passed to the function context/set-generic it will create appropriate value. If you want to use other types of objects you should create value yourself.