简单模板:
Thank You for your order ${order.billFirstName} ${order.billLastName}.
<br>
Your Order Total is: ${format(order.total, "C")}
<br>
<#if test="${order.shipcountry isnot "US"}">
Your order will arrive in 2-3 weeks
<#else>
Your order will arrive in 5-7 days
<#/if>
The templates can have expressions, if/elseif/else statement, foreach statement, for statement, set statement and other templates.

Templates API: There are 2 classes mainly used in Template Engine: Template and TemplateManager.
Template holds a single instance of a template and TemplateManager is used for executing templates.
Easiest way of creating Templates is by using static methods of Template or TemplateManager:
Template template = Template.FromString(string name, string data)
Template template = Template.FromFile(string name, string filename)
then you use it to instantilate TemplateManager.
TemplateManager mngr = new TemplateManager(template);
or even easier:
TemplateManager mngr = TemplateManager.FromFile(filename);
TemplateManager mngr = TemplateManager.FromString(template);
when using FromString method, the string passed contains template code. This method can be used to dynamically generate text without having templates in files.
You use SetValue(string name, object value); to add values that can be used within the templates.
例如:
mngr.SetValue("customer", new Customer("Tom", "Jackson"));

There are several built in functions and additional functions can be easily added. The built in functions are:
equals(obj1, obj2) - 测试obj1 和 obj2 是否相等. 返回boolean值.

notequals(obj1, obj2) - 测试obj1 和 obj2 是否不相等. 相当于:not(equals(obj1, obj2))

iseven(num) - 测试 num 是否为偶数

isodd(num) - 测试 num 是否为奇数

isempty(string) - 测试 string 长度是否等于0. 相当于:equals(string.Length, 0)

isnotempty(string) - 测试 string 长度是否大于0.

isnumber(num) - 测试 num 是否为数字

toupper(string) - 格式化成大写

tolower(string) - 格式化成小写

isdefined(varname) - 测试 varname 是否已经定义类型

ifdefined(varname, value) - 如果varname已经定义就得到value,否则为null. 例如:${ifdefined("name", name)}

length(string) - 得到string的长度

tolist(collection, property, delim) - will convert collection to string with delim as seperator. If you pass property, the value of the property will be evaluated on each element of collection. If you omit property, then the object itself will be used.
例如:
suppose you have list as:
	ArrayList list = new ArrayList();
	list.Add("one");
	list.Add("two");
	list.Add("three");
	template.SetValue("mylist", list);
then in your template:
${toList(mylist, " & ")}
the output will be: one & two & three

suppose you have list as:
	list.Add(new Customer("Tom", "Whatever"));
	list.Add(new Customer("Henry", "III"));
	list.Add(new Customer("Tom", "Jackson"));
	template.SetValue("mylist", list);
then in template:
${toList(mylist, "firstName", ",")}
the output will be: Tom,Henry,Tom

isnull(obj) - 测试obj 是否为 null

not(boolvalue) - boolvalue为true时为false,boolvalue为false时为true

iif(booleanExpression, iftruevalue, iffalsevalue) - 形如C#中的 booleanExpression ? iftruevalue : iffalsevalue
例如:
${iif(isodd(i), "bgcolor=yellow", "bgcolor=red")}
will output bgcolor=yellow if i is odd number and bgcolor=red if i is not odd number

format(object, formatstring) - will call ToString(formatstring) on object. Object has to implement IFormattable interface, otherwise ToString() will be called.
例如:
(suppose total is decimal with value 1208.45)
${format(total, "C")}
will output: $1,208.45

trim(string) - will trim string object

filter(collection, booleanproperty) - will return new List from collection for those objects whose booleanproperty property evaluates to true

gt(obj1, obj2) - 当obj1大于obj2时为true (obj1 and obj2 must implement IComparable. All numeric types do)

lt(obj1, obj2) - 当obj1小于obj2时为true (obj1 and obj2 must implement IComparable. All numeric types do)

compare(obj1, obj2) - will return -1 if obj1 < obj2, 0 is obj1 == obj2, and 1 if obj1 > obj2 (obj1 and obj2 must implement IComparable. All numeric types do)

or(bool1, bool2) - 当bool1或bool2为true时为true
例如:
${or(equals(state, "IL"), equals(state, "NY"))} - returns true if state is either IL or NY

and(bool1, bool2) - 当bool1和bool2都为true时为true

comparenocase(string1, string2) - will do case insenstive comparison of string1 and string2 and return true if they are equal

stripnewlines(string) - will return all \r\n instances and replace them with space

typeof(object) - will return string representation of the type of object. 例如: typeof("hello") return "string". typeof(3) returns int

cint(value) - 使用 .net类库中的接口Convert.ToInt32)

cdouble(value) - 将值格式为成 double型

cdate(value) - 将值格式为成 DateTime型. 例如: ${cdate("2005-5-1")}

cdatestring(value, string1) - 使用指定的string1格式将当前值格式化. 例如: ${cdatestring("2005-5-1","yy-MM-dd")}

createtypereference(type) - you can use this function to create references to static types so that you can access static properties or call methods of a static object. It's most useful when combind with <#set tag (explained below)
${createtypereference("System.Math").Round(3.39789)}
${createtypereference("System.Math").PI}
or
<#set name="MyMath" value="${createtypereference("System.Math")}" />
${MyMath.Round(3.3)}
${MyMath.PI}


is - 例如: ${obj1 is obj2}.

isnot - 例如: ${obj1 isnot obj2}

and - 类似C#中的: &&

or - 类似C#中的:||

lt, lte, gt, gte - 分别类似 ("<"、"<="、">"、">=").
${varOne lt 3}
${varTwo lte cdbl(3)}
${varThree gt varFour and varFive gte 5.0}
Built In Tags:
IF
You can also conditionally output text based on some expression using special if tag:
<#if test="${booleanexpression}">

<#elseif test="${bool}">

<#else>

<#/if>
elseif and else are optional. If test of "if" evaluates to true, then block inside of "if" will be output, otherwise elseif will be tested (if exists) and then else.
例如:
<#if test="${cust.country is "US"}">
You are US customer.
<#else>
You are from: ${cust.country} country.
<#/if>
If cust.country is "US" then the output will be: You are US customer.

FOREACH
You can loop through collection of elements (any object that implements IEnumerable interface) using FOREACH tag.
<#foreach collection="${collection}" var="cust" index="i">
${i}: ${cust.lastname}, ${cust.firstname}
<#/foreach>

Suppose customers is array of customer objects: customers = Customer("Tom", "Jackson"), Customer("Mary", "Foo")
The output will be:
1. Jackson, Tom
2. Foo, Mary

During execution, variable name that is passed as var attribute will be assigned with element from the collection. Index attribute can be omitted, and is used to represent index variable for the loop. It starts with 1 and gets increments with each iteration.

FOR
You can use FOR tab to loop through integer values by one.
<#for from="1" to="10" index="i">
${i}: ${customers[i].name}
<#/for>


SET
Set tag allows you to set values based on other expressions:
<#set name="var" value="${someexpression}" />
After set statement is executed you can use var as if it was a local variable.
It might be useful when accessing complex object values.
Instead of writing:
${customers[i].address.firstname} ${customers[i].address.lastname} ${customers[i].address.address1}
You can do: lt;#set name="add" value="${customers[i].address}" /> ${add.firstname} ${add.lastname} ${add.address1}
It's especially useful with createtypereference function (see above)

Custom Templates:
You can also create your own templates inside of template file that you can call. You do that using template tag:
<#template name="ShowCustomer">
${customer.lastname}, ${customer.firstname} 
<#/template>

<#showcustomer customer="${cust}" />
You can pass any attributes to the template, and you can use those inside of the template. The template can also access all variables that are defined outside of the template. When calling template you have to put trailing slash at the end, or put closing tag:
<#showcustomer />
or
<#showcustomer><#/showcustomer>

The template also received special variable: innerText that is the content of executing the inner elements of calling template.
<#template name="bold">
<b>${innerText}</b>
<#/template>

<#bold>${cust.lastname}, ${cust.firstname}<#/bold>
the output will be: <b>Jackson, Tom</b> (if customer is Tom Jackson)

You can also nest those:
<#template name="italic">${innerText}<#/template>

<#bold><#italic>This will be bold and italic<#/italic><#/bold>
You can also invoke templates based on the name using apply tag:
<#apply template="${usetemplate}">this is content<#/apply>
If usetemplate is "bold" then "bold" template will be called.

Templates can be nested inside other template:
<#template name="doit">
	<#template name="colorme">
	<font color=${color}>${innerText}</font>
	<#/template>
	
<#colorme color="blue">colorize me<#/colorme>
<#/template>
colorme template can only be used within doit template.
Templates can also be added programmatically:
TemplateManager mngr = ...;
mngr.AddTemplate(Template.FromString("bold", "<b>${innerText}</b>"));
now bold template can be used anywhere within processing.

Version 2.0 adds ability to create custom tags in C# (or any .net language) that can extend the TemplateManager with additional functionality. Together with the sources is Example 2 which includes 2 custom tags email for sending email and base64 for base64 encoding content.
Once those tags are registered with TemplateManger you can call them like:
<#email from="andrew@adersoftware.com" to="someuser@example.com" subject="Hello" server="127.0.0.1"> Hello ${customer.firstname} ${customer.lastname} <#/email>

Version 2 also added ITemplateHandler interface for better interaction with template execution. You can than set templateManager's Handler property to a handler, and this handler will be called before and after manager is done processing the template. This handler is also available as this object, and you can access any property or call methods of the handler from within the template. Example 2 includes "MyHandler.cs" as an example on how to use it.

------------------------- Here is a sample based on order confirmation.
class Order
{
	string firstname, lastname, address1, city, state, zip, country;

	public string Address1
	{
		get { return this.address1; }
	}

	public string City
	{
		get { return this.city; }
	}

	public string Country
	{
		get { return this.country; }
	}

	public string Firstname
	{
		get { return this.firstname; }
	}

	public string Lastname
	{
		get { return this.lastname; }
	}

	public string State
	{
		get { return this.state; }
	}

	public string Zip
	{
		get { return this.zip; }
	}
}

Order order = GetOrder();
TemplateManager mngr = TemplateManager.FromFile("order-confirmation.st");
mngr.SetValue("order", order);
System.IO.StringWriter writer = new System.IO.StringWriter();
mngr.Process(writer);

string emailBody = writer.ToString();
-------------------------------------------
order-confirmation.st
-------------------------------------------
<#showitem>
${item.sku} - ${item.name}<br>
<#if test="${equals(item.qty, 1)}">
Price: ${format(item.price, "C")}<br>
<#else>
You bought ${item.qty} items for ${format(item.price, "C")} 
	(total: ${format(item.total, "C")})
<#/if>
<#/showitem>

${order.firstname} ${order.lastname}<br>
${order.address1}<br>
<#if test="${isnotempty(order.address2)}">${order.address2}<br><#/if>
${order.city}, ${order.zip} ${order.state}
<br>
<table>
<#foreach collection="${order.orderitems}" var="orderitem" index="i">
<tr>
	<td>${i}.</td>
	<td bgcolor="${iif(isodd(i), "#DEDEDE", "white")}">
	<#showitem item="${orderitem}" />
	</td>
</tr>
<#/foreach>
</table>
Shipping: ${format(order.shipping, "C")}<br>
Taxes: ${format(order.tax, "C")}<br>
Order Total: ${format(order.total, "C")}<br>
--------------------------------------------
Description of order-confirmation.st
First showitem template is defined which shows a single line item of the order. item is passed as attribute to showitem.
Then address is shown. Note how if is used to conditionally display second line of address with ending <br> tag.
Then each line item of order is looped through using #forech tag. iif function is used to color everyother line with #DEDEDE color.

--------------------------------------------------
Example #2 for constructing complex SQL queries:
--------------------------------------------------
string[] cols = new string[]{"id", "name", "email"};
TemplateManager mngr = TemplateManager.FromFile(file);
mngr.SetValue("colums", cols);
mngr.SetValue("tablename", "customer");
string query = mngr.Process();
and the template file is:
select ${toList(columns, ",")} from ${tablename}