最近越来越讨厌Aspx和WebControl了, 发现用模版引擎再加上JS就可以做出很好的东西了, 前段时候研究了jQuery, 用它来开发Ajax 应用真是得心应手. StringTemplate 看起来好象也不错, 正好今天有空,拿来看了一下,正好园子里这方面的资料不是很多, 写出来与大家分享,搞了一整天,累死我了;( 下面是我的笔记,可能写得有点乱,请大家包含, 全部文件打包在
这里下载
这个工程在沙加的神舟本上 VS2008(WebApplication)+.Net2.0环境下调试完成. 我在代码里面有比较详细的注释和说明希望对大家有所帮助.
下面发部分代码出来:
主要的模版文件 :
使用FileGroup读取的文件~~Hello $myname$
<br />$title; null="-1", separator=" | "$
<br />
<h4>关于文件组</h4>
文件组还支持继承和接口实现,此为高级功能,详细内容参见官方文档.
<h4>用户信息</h4>
我们使用反射的方式来获取对象的属性,但是如何对日期这种数据类型执行格式化?<br />
姓名 : $user.Name$<br />
年龄 : $user.Age$<br />
生日 : $user.Birthday$<br />
女朋友 : $user.GirlFriend$<br />
这里我们使用了一个中间的方法来返回我们想要的日期形式, 短日期的生日 : $user.ShortBirthday$<br />
<h4>在访问属性时可以使用适配器模式来实现转换 st.SetAttribute("person", new Connector(p));</h4>
比如你的Person对象只有一个叫Name的属性,但是模版里面写的是$myname$, 这样就可以在Connector中写一个方法叫get_myname() 返回这个实
例的Name属性 :
public class Connector<br />


{<br />
Person _person;
public Connector(Person p)<br />


{ <br />
_person = p;<br />
}<br />
public string get_myname()<br />


{<br />
return _person.Name;
}<br />
}<br /><br />
<h3>使用自动聚合Automatic Aggregate Creation</h3>
<hr />

$users:
{姓名, 年龄 : $users.Name$,$users.Age$}$
<br />
<br />
<h3>列表构造</h3>
<hr />
多值列表<br />
$[mine,yours]$<br />
在传入多个值之后,会把所有的mine列在一起显示,然后把所有的yours放在一起显示
<br /><br />
<h3>模版引用</h3>
<hr />
<h4>下面是一个登陆窗口, 来自loginform.st这个文件</h4>
$loginform()$
$loginform(message="从行内的参数传递过来")$
$loginform(msg=demovalue())$把模版内容作为参数.
<br />
<br />
<h3>使用匿名模版</h3>
<hr />
没搞懂怎么玩的,好象没啥用. 我们待会再来搞它.<br />

<h3>使用穿透模式传递参数</h3>
<hr />
这个没啥好说的,假如你有个 a.st, 还有一个b.st, a.st在内容中引用b.st, 里面都含有一个叫'name'的参数,默认情况下只有a.st会获取这个参数值.
要想两个模版都获取到参数值要使用"SetPassThroughAttributes()"这个方法

<h3>对多值属性应用模版</h3>
<hr />
<h4>终于说到点有用的东西了, 假设我们需要一个简单的<ul>列表</h4>
我们把模版放在simple_list_item这个里面. 注意: 这个模版里面的it是关键字, 不需要预定义.<br />
<ul>$custermers:simple_list_item()$</ul>

我们再来个嵌套,把列表的内容加粗. 这个加粗的模版是在代码中定义的.<br />
这个是先加粗. 再把结果传入
<ul>$(custermers:bold()):simple_list_item()$</ul>
这次是依次调用
<hr />
<ul>$custermers:bold():simple_list_item()$</ul>
两种颜色交替显示的:
<hr />
$custermers:green(),blue();separator=", "$
<br /><br />
<h3>使用代码定义模版好象不太方便</h3>
<hr /><h4>这回再来看看匿名模版的作用</h4>
使用i0指定自动编号, 后面的数字表示起始位置.<br />

$custermers:
{$i0$. $it$<br />}$
<h4>再来个完美点的一行解决问题的:</h4><br />

<ul>$custermers:
{<strong>$it$</strong>}:
{<li>$it$</li>}$</ul>
<h4>嗯,看起来好象还不错,但是我不想用这个该死的"挨踢": it,怎么办?</h4>
我们可以使用自定义的参数名, 象这样:<br />

<ul>$custermers:
{ n | <strong>$n$</strong>}:
{ n | <li>$n$</li>}$</ul>
<h4>我还想加一个参数?</h4>

$qqs, nicknames :
{ n, p | $n$ : $p$</br /> }$
<br /><br />
<h3>那么现在来实战</h3>
<hr />
我们的目标是生成一个文章的列表.
<ul>

$articles :
{ ar | <li><a href='/view.aspx?id=$ar.ID$'>$ar.Title$====createdDate : $ar.CreatedDate$</a>}$
</ul>



using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using Antlr.StringTemplate;
using System.IO;
using System.Collections;

namespace TET.Core.httphandlers


{
public class test_template_page : IHttpHandler

{

IHttpHandler Members#region IHttpHandler Members
HttpContext con;

public bool IsReusable

{

get
{ return false; }
}

public void ProcessRequest(HttpContext context)

{
con = context;
Out("<html>");
Out("<head>");
Out("<style>h1,h2,h3{padding:3px;margin:0;color:maroon;}h4{padding:3px;margin:0;font-weight:bold;font-size:12px;}");
Out("body{line-height:150%;font-family:verdana;color:#666;font-size:12px;}h1{font-size:18px;}h2{font-size:16px;}h3{font-size:14px;}hr{padding:0;margin:0;margin-bottom:3px;border:none;height:1px;color:#ddd;background-color:#ddd;width:90%;}");
Out("#doc{margin:0pt auto;width:780px;border:solid 2px #e0e0e0;padding:10px;}ul{padding:0;margin:5px;margin-left:20px;}");
Out("</style>");
Out("</head>");
Out("<body><div id='doc'>");

//使用Inline的方式创建一个模版(当然也可以从文件内读取).
StringTemplate st = new StringTemplate("My First Template!! Hello $myname$");
st.SetAttribute("myname", "martin");
Out("<h3>第一个简单示例</h3>");
Out("<hr />");
Out(st.ToString());

StringTemplate stMulValue = new StringTemplate("这里有一个多值的变量 : $friends;separator=\",\"$");
stMulValue.SetAttribute("friends", "KCY");
stMulValue.SetAttribute("friends", "TQ");
stMulValue.SetAttribute("friends", "沙加");
stMulValue.SetAttribute("friends", "冬梅");
Out("<br /><br />");
Out("<h3>下面是一个多值输出示例, 对一个属性多性赋值后可以指定使用的分隔符.</h3>");
Out("<hr />");
context.Response.Write(stMulValue.ToString());

//使用静态类来封装这个模版类.
StringTemplateGroup stg = TemplateManager.GetFileGroup();
StringTemplate stFromGroup = stg.GetInstanceOf(TemplateManager.test_template_page);


stFromGroup.SetAttribute("myname", "Darkangel0728");
stFromGroup.SetAttribute("title", "新浪,method");
stFromGroup.SetAttribute("title", "第一个", null, "前一个是空值测试,传入一个空引用, 输出的是-1");
//多值属性,在赋空值的时候给一个默认值.

//在调用对象属性的时候ST是使用反射的方法来导找相应的属性, 调用的顺序如下:
//比如调用 object.name
// 叫name的属性
//get_name()
//Getname()
//Isname()
//getname()
//isname()
//name字段
//this["name"]

User user = new User();
user.Name = "沙加";
user.Age = 27;
user.Birthday = DateTime.Now;
stFromGroup.SetAttribute("user", user);
stFromGroup.SetAttribute("users.{Name,Age}", user.Name, user.Age);//自动聚合.

//多值列表
stFromGroup.SetAttribute("mine", "我的");
stFromGroup.SetAttribute("yours", "你的");
stFromGroup.SetAttribute("mine", "她的");
stFromGroup.SetAttribute("yours", "别人的");

stFromGroup.SetAttribute("message", "\"我是从外面来的\"");//给引用的模版赋值.

stFromGroup.SetAttribute("custermers","张三", "李四","王小二", "西红寺");//列表输出项目.

stg.DefineTemplate("bold","<strong>$it$</strong>");//定义一个可以把项目加粗的模版.
stg.DefineTemplate("blue", "<span style='color:blue'>$it$</span>");//蓝色
stg.DefineTemplate("green", "<span style='color:green'>$it$</span>");// 绿色的,用于两种颜色的列表交叉显示.

stFromGroup.SetAttribute("qqs","1234","8088","234423");
stFromGroup.SetAttribute("nicknames", "kiti", "jojo", "eric");

//使用表达式调用模版.
Shirt sh1 = new Shirt();
sh1.Owner = "沙加";
sh1.Color = "blue";

Shirt sh2 = new Shirt();
sh2.Owner = "俺的MM";
sh2.Color = "red";

stFromGroup.SetAttribute("shirts", sh1, sh2);


//文章列表输出

List<Article> list = new List<Article>();
for (int i = 0; i < 5; i++)

{
Article ar = new Article();
ar.ID = i;
ar.Title = "Darkangel" + i.ToString();
ar.CreatedDate = DateTime.Now.AddDays(i);
list.Add(ar);
}
stFromGroup.RegisterAttributeRenderer(typeof(DateTime), new DateRender());//可以使用构造函数生成别的格式
//除了这种方式还有就是前面提到的使用一个单独的方法来获取日期输出的字串.
stFromGroup.SetAttribute("articles", list.ToArray());

Out("<br /><br />");
Out("<h3>使用StringTemplateGroup, 从文件读取模版并输出. 这个Group对象默认是有缓存的. 可以让模版文件一次性加载. </h3>");
Out("<h4>或使用StringTemplateGroup.setRefreshInterval来指定过期策略. 设为0为不缓存, 在.net下好象没有实现,但是可以用文件缓存依赖来替代.</h4>");
Out("<hr />");
context.Response.Write(stFromGroup.ToString());



String templates = "group simple;vardef(type,name) ::= \"<type> <name>;\"";
templates += "method(type,name,args,statements) ::= <<";
templates += "<type> <name>(<args; separator=\",\">) {";// 在此处加入<br />之后后面的内容就不能输出了, 使用<>作为变量的标识符在输
//出Html的时候可能会有问题.
templates += "<statements; separator=\";<br />\"><br />}";
templates += ">>";//在一个文件内定义多个模版. 这里定义了两个模版, 一个叫vardef, 一个叫method. vardef中接受两个参数, type和name
//第二个接受3个参数 type,name,args.

// Use the constructor that accepts aSystem.IO.TextReader
StringTemplateGroup group = new
StringTemplateGroup(new StringReader(templates));
StringTemplate t1 = group.GetInstanceOf("vardef");
t1.SetAttribute("type", "int");
t1.SetAttribute("name", "foo");
Out("<br /><br />");
Out("<h3>在一个文件内定义多个模版,第一个</h3>");
Out("<hr />");
Out(t1.ToString());

StringTemplate t2 = group.GetInstanceOf("method");
t2.SetAttribute("type", "MyClass");
t2.SetAttribute("name", "Martin");
t2.SetAttribute("args", "firstArg");
t2.SetAttribute("args", "secondArg");
t2.SetAttribute("statements", "语句第一行");
t2.SetAttribute("statements", "语句第二行");
Out("<br /><br />");
Out("<h3>在一个文件内定义多个模版,第二个</h3>");
Out("<hr />");
Out(t2.ToString());

Out("<h3>谢谢各位支持,在沙加的神舟本上测试通过</h3>");
Out("<hr /><h4>开发环境VS2008, .net 2.0, 需要Web Application支持.</h4>");
Out("</div></body></html>");
}
public void Out(string str)

{
con.Response.Write(str);
}

#endregion
}
}

下面是前台输出的样子:

<html><head><style>h1,h2,h3
{padding:3px;margin:0;color:maroon;}h4
{padding:3px;margin:0;font-weight:bold;font-size:12px;}body