65.9K
CodeProject 正在变化。 阅读更多。
Home

Ader 模板引擎

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (24投票s)

2004年8月31日

6分钟阅读

viewsIcon

174747

downloadIcon

916

用于从源模板和输入参数生成文本输出的库。

引言

Ader TemplateEngine 是一个 .NET 类库(用 C# 编写),用于从源模板和输入参数生成文本输出。它可用于多种场景:网站页面构建、电子邮件生成、XML 生成、源代码生成等。其思想基于 Antlr stringTemplate,但语法基于 ColdFusion 语言。

目前,.NET Ader TemplateEngine 仅支持 .NET 2.0,但我计划使其支持 .NET 1.0/1.1,甚至可能是 Java。Ader TemplateEngine 在 GNU General Public License 下发布。

这是一个非常简单的模板

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

模板可以包含表达式、if/elseif/else 语句、foreach 语句和其他模板。

模板 API

模板引擎主要使用两个类:TemplateTemplateManagerTemplate 保存模板的单个实例,TemplateManager 用于执行模板。创建模板最简单的方法是使用 TemplateTemplateManager 的静态方法

Template template = Template.FromString(string name, string data);
Template template = Template.FromFile(string name, string filename);

然后您可以使用它来实例化 TemplateManager

TemplateManager mngr = new TemplateManager(template);

甚至更简单

TemplateManager mngr = TemplateManager.FromFile(filename);
TemplateManager mngr = TemplateManager.FromString(template);

使用 FromString 方法时,传递的字符串包含模板代码。此方法可用于动态生成文本,而无需将模板保存在文件中。您可以使用 SetValue(string name, object value); 来添加可在模板中使用的值。

例如:

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

然后您可以在模板中引用 customer。您可以使用任何类型的对象作为值。当变量的值需要输出时,将调用 ToString() 方法。

表达式

表达式用 #(井号)字符括起来

示例

#firstName#

此示例将输出名字的值。如果您需要输出 # 字符,只需用另一个 # 来转义它。

示例

Your SS## is #ssnumber#

在表达式块内,您可以输出任何变量

#somevar#

访问变量的属性

#somestring.Length#

属性名不区分大小写。因此,您可以调用:#string.length##string.LENGTH#。或者调用一个函数

#trim(somename)#

有几个内置函数,并且可以轻松添加其他函数。内置函数包括

  • equals(obj1, obj2) - 调用 obj1equals 方法,并将 obj2 作为参数。返回布尔值。
  • notequals(obj1, obj2) - 返回 !equals(obj1, obj2)。等同于调用:not(equals(obj1, obj2))
  • iseven(num) - 测试数字是否为偶数。
  • isodd(num) - 测试数字是否为奇数。
  • isempty(string) - 测试字符串是否不包含字符。与 equals(string.Length, 0) 相同。
  • isnotempty(string) - 测试字符串是否至少包含 1 个字符。
  • isnumber(num) - 测试 num 是否为数字类型。
  • toupper(string) - 将 string 转换为大写。
  • tolower(string) - 将 string 转换为小写。
  • isdefined(varname) - 测试名为 varname 的变量是否已定义。
  • ifdefined(varname, value) - 如果 varname 已定义,则返回该值。特别有用:#ifdefined("name", name)# - 如果 name 已定义,则输出其值,否则什么也不输出。
  • len(string) - 返回 string 的长度。
  • tolist(collection, property, delim) - 将 collection 转换为字符串,以 delim 作为分隔符。如果传递了 property,则将在集合的每个元素上评估 property 的值。如果省略 property,则使用对象本身。

    示例:假设您有一个列表

        ArrayList list = new ArrayList();
        list.Add("one");
        list.Add("two");
        list.Add("three");
        template.SetValue("mylist", list);

    然后在您的模板中

    #toList(mylist, " & ")#

    输出将是:one & two & three

    假设您有一个列表

        list.Add(new Customer("Tom", "Whatever"));
        list.Add(new Customer("Henry", "III"));
        list.Add(new Customer("Tom", "Jackson"));
        template.SetValue("mylist", list);

    然后在模板中

    #toList(mylist, "firstName", ",")#

    输出将是:Tom,Henry,Tom。

  • isnull(obj) - 测试 obj 是否为 null
  • not(boolvalue) - 返回布尔值的非 (!)。
  • iif(booleanExpression, iftruevalue, iffalsevalue) - 相当于 C# 中的 booleanExpression ? iftruevalue : iffalsevalue

    示例

    #iif(isodd(i), "bgcolor=yellow", "bgcolor=red")#

    如果 i 是奇数,则输出 bgcolor=yellow,如果 i 不是奇数,则输出 bgcolor=red。

  • format(object, formatstring) - 将在 object 上调用 ToString(formatstring)object 必须实现 IFormattable 接口,否则将调用 ToString()

    示例:假设 total 是值为 1208.45 的 decimal

    #format(total, "C")#

    将输出:$1,208.45

  • trim(string) - 将修剪 string 对象
  • filter(collection, booleanproperty) - 将从 collection 中返回一个新的 List,包含那些布尔属性 property 评估为 true 的对象。
  • gt(obj1, obj2) - 如果 obj1 > obj2,则返回 true。(obj1obj2 必须实现 IComparable。所有数字类型都实现了)。
  • lt(obj1, obj2) - 如果 obj1 < obj2,则返回 true。(obj1obj2 必须实现 IComparable。所有数字类型都实现了)。
  • compare(obj1, obj2) - 如果 obj1 < obj2,则返回 -1;如果 obj1 = obj2,则返回 0;如果 obj1 > obj2,则返回 1。(obj1obj2 必须实现 IComparable。所有数字类型都实现了)。
  • or(bool1, bool2) - 如果 bool1bool2true,则返回 true

    示例

    #or(equals(state, "IL"), equals(state, "NY"))# - 
    returns true if state is either IL or NY
  • and(bool1, bool2) - 如果 bool1bool2 都为 true,则返回 true
  • comparenocase(string1, string2) - 将执行不区分大小写的比较 string1string2,如果它们相等,则返回 true
  • stripnewlines(string) - 将返回所有 \r\n 实例并将其替换为空格。

内置标签

  • IF

    您还可以根据某些表达式有条件地输出文本,使用特殊的 if 标签

    <ad:if test="#booleanexpression#">
    <ad:elseif test="#bool#">
    <ad:else>
    </ad:if>

    elseifelse 是可选的。如果 "if" 的测试结果为 true,则输出 "if" 内块的内容,否则测试 elseif(如果存在),然后测试 else

    示例

    <ad:if test="#equals(cust.country, "US"))#">
    You are US customer.
    <ad:else>
    You are from: #cust.country# country.
    </ad:if>

    如果 cust.country 是 "US",则输出将是:You are US customer.

  • FOREACH

    您可以使用 FOREACH 标签循环遍历元素集合(任何实现 IEnumerable 接口的对象)。

    <ad:foreach collection="#collection#" var="cust" index="i">
    #i#: #cust.lastname#, #cust.firstname#
    </ad:foreach>

    假设 customers 是客户对象数组

    customers = Customer("Tom", "Jackson")
    Customer("Mary", "Foo")

    输出将是:

    1. Jackson, Tom
    2. Foo, Mary

    在执行过程中,作为 var 属性传递的变量名将被赋为集合中的元素。index 属性可以省略,用于表示循环的索引变量。它从 1 开始,并在每次迭代中递增。

自定义模板

您还可以在模板文件中创建自己的模板,然后调用它们。您通过 template 标签来做到这一点

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

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

您可以将任何属性传递给模板,并且您可以在模板内部使用这些属性。模板还可以访问在模板外部定义的所有变量。调用模板时,必须在末尾加上斜杠,或者使用闭合标签

<ad:showcustomer />

<ad:showcustomer></ad:showcustomer>

模板还接收一个特殊变量:innerText,它是调用模板的内部元素执行的内容。

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

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

输出将是

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

您也可以嵌套它们

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

您还可以使用 apply 标签根据名称调用模板

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

如果 usetemplate 是 "bold",则将调用 "bold" 模板。

模板可以嵌套在其他模板中

<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 模板只能在 doit 模板内部使用。模板也可以通过编程方式添加

TemplateManager mngr = ...;
mngr.AddTemplate(Template.FromString("bold", "<b>#innerText#</b>"));

现在,bold 模板可以在处理的任何地方使用。这是一个基于订单确认的示例

    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>

order-confirmation.st 的描述

首先,定义了 showitem 模板,它显示订单的单个行项。item 作为属性传递给 showitem。然后显示地址。注意如何使用 if 来有条件地显示地址的第二行并加上 <br> 标签。然后使用 ad:foreach 标签循环遍历订单的每一行项。使用 iif 函数为每隔一行着色为 #DEDEDE。

示例 #2:构建复杂的 SQL 查询

string[] cols = new string[]{"id", "name", "email"};
TemplateManager mngr = TemplateManager.FromFile(file);
mngr.SetValue("colums", cols);
mngr.SetValue("tablename", "customer");
string query = mngr.Process();

模板文件是

select #toList(columns, ",")# from #tablename#

示例 1 项目有两个示例模板,用于处理相同的数据。首先,它将数据作为 C# 类输出到屏幕,然后使用 HTML 模板创建 HTML 文件。

如果您有任何问题,可以使用 AderTemplates 论坛

© . All rights reserved.