Click here to Skip to main content
11,643,493 members (78,738 online)
Click here to Skip to main content

Ader Template Engine

, 30 Aug 2004 114.3K 732 64
Rate this:
Please Sign up or sign in to vote.
Library for generating text output from source template and input parameters.

Introduction

Ader TemplateEngine is a .NET class library (written in C#) for generating text output from source template and input parameters. It can be used in many scenarios: website page building, email generation, XML generation, source code generation, etc. Its idea is based on Antlr stringTemplate, but the syntax is based on ColdFusion language.

Currently, .NET Ader TemplateEngine works with .NET 2.0 only, but I have plans on making it work with .NET 1.0/1.1 and maybe Java. Ader TemplateEngine is released under GNU General Public License.

Here is a very simple template:

Thank You for your order #order.billFirstName# #order.billLastName#.
<br>
Your Order Total is: #format(order.total, "C")#

The templates can have expressions, if/elseif/else statements, foreach statement and other templates.

Templates API:

There are two 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 instantiate 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.

E.g.:

mngr.SetValue("customer", new Customer("Tom", "Jackson"));

Then you can refer to customer within the template. You can use any type of object for value. When the value of variable is to be output, ToString() method will be called.

Expressions

Expressions are enclosed with # (hash or pound) characters:

Example:

#firstName#

This example will output value of first name. If you need to output # character, just escape it with another #.

Example:

Your SS## is #ssnumber#

Inside of expression block, you can output any variable:

#somevar#

Access property of a variable:

#somestring.Length#

Property name is not case sensitive. So you can call: #string.length# or #string.LENGTH#. Or call a function:

#trim(somename)#

There are several built in functions, and additional functions can be easily added. The built in functions are:

  • equals(obj1, obj2) - invokes equals method on obj1 with obj2 as parameter. Returns boolean value.
  • notequals(obj1, obj2) - Returns !equals(obj1, obj2). Is equivalent to calling: not(equals(obj1, obj2)).
  • iseven(num) - tests whether number is an even number.
  • isodd(num) - tests whether number is an odd number.
  • isempty(string) - tests whether string has 0 characters. Same as equals(string.Length, 0).
  • isnotempty(string) - tests whether string has at least 1 character.
  • isnumber(num) - tests whether num is of numeric type.
  • toupper(string) - converts string to upper case.
  • tolower(string) - converts string to lower case.
  • isdefined(varname) - tests whether variable named varname is defined.
  • ifdefined(varname, value) - returns value if varname is defined. Especially useful: #ifdefined("name", name)# - will output value of name if it's defined, otherwise will output nothing.
  • len(string) - returns length of string.
  • tolist(collection, property, delim) - will convert collection to string with delim as separator. If you pass property, the value of the property will be evaluated on each element of the collection. If you omit property, then the object itself will be used.

    Example: 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) - tests whether obj is null.
  • not(boolvalue) - returns not (!) of boolean value.
  • iif(booleanExpression, iftruevalue, iffalsevalue) - same as booleanExpression ? iftruevalue : iffalsevalue in C#.

    Example:

    #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.

    Example: 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 boolean property property evaluates to true.
  • gt(obj1, obj2) - will return true if obj1 > obj2. (obj1 and obj2 must implement IComparable. All numeric types do).
  • lt(obj1, obj2) - will return true if obj1 < obj2. (obj1 and obj2 must implement IComparable. All numeric types do).
  • compare(obj1, obj2) - will return -1 if obj1 < obj2, 0 if obj1 = obj2, and 1 if obj1 > obj2. (obj1 and obj2 must implement IComparable. All numeric types do).
  • or(bool1, bool2) - will return true if either bool1 or bool2 are true.

    Example:

    #or(equals(state, "IL"), equals(state, "NY"))# - 
    returns true if state is either IL or NY
  • and(bool1, bool2) - will return true if both bool1 and bool2 are true.
  • comparenocase(string1, string2) - will do case insensitive 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.

Built In Tags:

  • IF

    You can also conditionally output text based on some expression using special if tag:

    <ad:if test="#booleanexpression#">
    <ad:elseif test="#bool#">
    <ad:else>
    </ad: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.

    Example:

    <ad:if test="#equals(cust.country, "US"))#">
    You are US customer.
    <ad:else>
    You are from: #cust.country# country.
    </ad: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.

    <ad:foreach collection="#collection#" var="cust" index="i">
    #i#: #cust.lastname#, #cust.firstname#
    </ad: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 incremented with each iteration.

Custom Templates:

You can also create your own templates inside of template file, that you can call. You do that using template tag:

<ad:template name="ShowCustomer">
#customer.lastname#, #customer.firstname# 
</ad:template>

<ad:showcustomer customer="#cust#" />

You can pass any attribute 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:

<ad:showcustomer />

or

<ad:showcustomer></ad:showcustomer>

The template also receives special variable: innerText that is the content of executing the inner elements of calling template.

<ad:template name="bold">
<b>#innerText#</b>
</ad:template>

<ad:bold>#cust.lastname#, #cust.firstname#</ad:bold>

the output will be:

<b>Jackson, Tom</b>
(if customer is Tom Jackson)

You can also nest those:

<ad:template name="italic">#innerText#</ad:template>
<ad:bold><ad:italic>This will be bold and italic</ad:italic></ad:bold>

You can also invoke templates based on the name, using apply tag:

<ad:apply template="#usetemplate#">this is content</ad:apply>

If usetemplate is "bold", then "bold" template will be called.

Templates can be nested inside other templates:

<ad:template name="doit">
    <ad:template name="colorme">
      <font color=#color#>#innerText#</font>
    </ad:template>

    <ad:colorme color="blue">colorize me</ad:colorme>
</ad: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. 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

<ad:showitem>
#item.sku# - #item.name#<br>
<ad:if test="#equals(item.qty, 1)#">
Price: #format(item.price, "C")#<br>
<ad:else>
You bought #item.qty# items for #format(item.price, "C")# 
                        (total: #format(item.total, "C")#)
</ad:if>
</ad:showitem>

#order.firstname# #order.lastname#<br>
#order.address1#<br>
<ad:if test="#isnotempty(order.address2)#">#order.address2#<br></ad:if>
#order.city#, #order.zip# #order.state#
<br>
<table>
<ad:foreach collection="#order.orderitems#" var="orderitem" index="i">
<tr>
    <td>#i#.</td>
    <td bgcolor="#iif(isodd(i), "##DEDEDE", "white")#">
    <ad:showitem item="#orderitem#" />
    </td>
</tr>
</ad: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 ad:foreach tag. iif function is used to color every other 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#

Example 1 project has two sample templates that are used to process the same data. First, it outputs it as a C# class to the screen, then it uses HTML template to create HTML file.

If you have any questions, you can use AderTemplates forums.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Werdna
Chief Technology Officer
United States United States
No Biography provided

You may also be interested in...

Comments and Discussions

 
QuestionAder Template is not working for a simple variable replace Pin
liglio14-Oct-14 8:20
memberliglio14-Oct-14 8:20 
AnswerRe: Ader Template is not working for a simple variable replace Pin
Werdna14-Oct-14 13:48
memberWerdna14-Oct-14 13:48 
Questionproblem with adder template Pin
Tridip Bhattacharjee5-Dec-12 1:18
memberTridip Bhattacharjee5-Dec-12 1:18 
AnswerRe: problem with adder template Pin
Werdna5-Dec-12 5:02
memberWerdna5-Dec-12 5:02 
GeneralRe: problem with adder template Pin
Tridip Bhattacharjee5-Dec-12 19:30
memberTridip Bhattacharjee5-Dec-12 19:30 
GeneralRe: problem with adder template Pin
Werdna7-Dec-12 3:36
memberWerdna7-Dec-12 3:36 
QuestionDoes it work with RTF Pin
Balck.01-Feb-11 20:14
memberBalck.01-Feb-11 20:14 
GeneralMy 5 Pin
robocodeboy16-Dec-10 22:29
memberrobocodeboy16-Dec-10 22:29 
GeneralMy vote of 5 Pin
robocodeboy16-Dec-10 21:59
memberrobocodeboy16-Dec-10 21:59 
Generalmake it support external template files [modified] Pin
Unruled Boy20-Sep-07 23:46
memberUnruled Boy20-Sep-07 23:46 
Generalmath expression evaluation Pin
Unruled Boy11-Aug-05 22:23
memberUnruled Boy11-Aug-05 22:23 
GeneralRe: math expression evaluation Pin
Werdna12-Aug-05 5:20
memberWerdna12-Aug-05 5:20 
Questiontags executed/evaluated all at once? Pin
Unruled Boy6-Aug-05 6:07
memberUnruled Boy6-Aug-05 6:07 
AnswerRe: tags executed/evaluated all at once? Pin
Werdna8-Aug-05 11:57
memberWerdna8-Aug-05 11:57 
Questionvoid -> [null] ? Pin
Unruled Boy5-Aug-05 21:33
memberUnruled Boy5-Aug-05 21:33 
AnswerRe: void -&gt; [null] ? Pin
Werdna6-Aug-05 5:55
memberWerdna6-Aug-05 5:55 
Questionruntime var? Pin
Unruled Boy5-Aug-05 18:06
memberUnruled Boy5-Aug-05 18:06 
AnswerRe: runtime var? Pin
Werdna6-Aug-05 5:53
memberWerdna6-Aug-05 5:53 
GeneralRe: runtime var? Pin
Unruled Boy6-Aug-05 5:58
memberUnruled Boy6-Aug-05 5:58 
Generalor() expression failed Pin
Unruled Boy1-Aug-05 21:24
memberUnruled Boy1-Aug-05 21:24 
GeneralRe: or() expression failed Pin
Werdna2-Aug-05 3:52
memberWerdna2-Aug-05 3:52 
GeneralRe: or() expression failed Pin
Unruled Boy2-Aug-05 5:05
memberUnruled Boy2-Aug-05 5:05 
GeneralGPL Licence Pin
Schnulle31-Jul-05 20:21
memberSchnulle31-Jul-05 20:21 
GeneralRe: GPL Licence Pin
Unruled Boy31-Jul-05 20:50
memberUnruled Boy31-Jul-05 20:50 
GeneralRe: GPL Licence Pin
Werdna1-Aug-05 3:36
memberWerdna1-Aug-05 3:36 
GeneralRe: GPL Licence Pin
Schnulle5-Sep-05 2:08
memberSchnulle5-Sep-05 2:08 
GeneralRe: GPL Licence Pin
SteveC-A99-Feb-07 7:52
memberSteveC-A99-Feb-07 7:52 
GeneralRe: GPL Licence Pin
d.marzo14-Feb-06 6:47
memberd.marzo14-Feb-06 6:47 
Questionnested function failed? Pin
Unruled Boy31-Jul-05 19:59
memberUnruled Boy31-Jul-05 19:59 
AnswerRe: nested function failed? Pin
Unruled Boy31-Jul-05 20:02
memberUnruled Boy31-Jul-05 20:02 
GeneralRe: nested function failed? Pin
Werdna1-Aug-05 3:35
memberWerdna1-Aug-05 3:35 
QuestionNested templates with collections? Pin
Unruled Boy31-Jul-05 16:58
memberUnruled Boy31-Jul-05 16:58 
AnswerRe: Nested templates with collections? Pin
Werdna31-Jul-05 17:18
memberWerdna31-Jul-05 17:18 
Questionwhere are the sample codes for *.sta files in &quot;Example Templates&quot;? Pin
Unruled Boy30-Jul-05 17:04
memberUnruled Boy30-Jul-05 17:04 
AnswerRe: where are the sample codes for *.sta files in &quot;Example Templates&quot;? Pin
Unruled Boy30-Jul-05 17:19
memberUnruled Boy30-Jul-05 17:19 
GeneralRe: where are the sample codes for *.sta files in "Example Templates"? Pin
Werdna31-Jul-05 7:11
memberWerdna31-Jul-05 7:11 
GeneralRe: where are the sample codes for *.sta files in &quot;Example Templates&quot;? Pin
Unruled Boy31-Jul-05 15:55
memberUnruled Boy31-Jul-05 15:55 
General&lt;ad:...&gt; Tags cause blank lines Pin
Schnulle20-Jul-05 20:52
memberSchnulle20-Jul-05 20:52 
GeneralRe: &lt;ad:...&gt; Tags cause blank lines Pin
Werdna27-Jul-05 14:54
memberWerdna27-Jul-05 14:54 
GeneralIndentation Pin
Schnulle20-Jul-05 3:27
memberSchnulle20-Jul-05 3:27 
GeneralRe: Indentation Pin
Werdna20-Jul-05 4:32
memberWerdna20-Jul-05 4:32 
GeneralRe: Indentation Pin
Schnulle20-Jul-05 19:09
memberSchnulle20-Jul-05 19:09 
GeneralRe: Indentation Pin
Schnulle5-Sep-05 2:07
memberSchnulle5-Sep-05 2:07 
Generalsupport for all character sets Pin
Unruled Boy7-Jun-05 22:01
memberUnruled Boy7-Jun-05 22:01 
GeneralRe: support for all character sets Pin
Werdna8-Jun-05 12:52
memberWerdna8-Jun-05 12:52 
Questionwhy not update the article? Pin
Unruled Boy30-May-05 13:16
memberUnruled Boy30-May-05 13:16 
AnswerRe: why not update the article? Pin
Werdna7-Jun-05 9:42
memberWerdna7-Jun-05 9:42 
GeneralTemplateEngine Version 2 Available Pin
Werdna18-May-05 11:46
memberWerdna18-May-05 11:46 
GeneralRe: TemplateEngine Version 2 Available Pin
Unruled Boy19-May-05 4:21
memberUnruled Boy19-May-05 4:21 
GeneralRe: TemplateEngine Version 2 Available Pin
Werdna19-May-05 4:45
memberWerdna19-May-05 4:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.150731.1 | Last Updated 31 Aug 2004
Article Copyright 2004 by Werdna
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid