上文展示了简单的模板组文件语法,本文来更详细的了解模板组文件的语法。
本文假设已经在应用程序启动时设置了默认的模板组loader(详细看上一篇):
void Application_Start(object sender, EventArgs e) { StringTemplateGroup.RegisterGroupLoader(new LWMEGroupLoader(AppDomain.CurrentDomain.BaseDirectory, null)); }
1、注释
这里的注释是指模板组文件的注释,它不同于模板文件的注释,仅仅用于在模板组文件内(模板之外),它们是:
- //单行注释
- /**/多行注释
示例:
group test; //单行模板组文件注释 /*多行 模板组文件 注释*/ t1() ::= << <!模板之内注释语法不变!> >> //单行模板组文件注释 /*多行 模板组文件 注释*/ t2() ::= << <!模板之内注释语法不变!> >>
2、模板的内容换行及缩进
与模板文件一样,模板组内的模板同样会清除内容两边的空格。如:
foo() ::= << rodent >>
与
foo() ::= "rodent"
是一样的。但是在多行模板中换行,它会保持换行符,如:
foo() ::= << 2nd line is not blank, but first is >>
与
foo() ::= <<<\n> same as before; newline then this line >>
再如:
foo() ::= << rodent >>
与
foo() ::= << rodent<\n> >>
此方法同样适用于模板文件,也可以通过实现IStringTemplateWriter接口或继承AutoIndentWriter类来定制模板内容的缩进。
3、模板参数
在模板定义中,每一个参数都必须明确的定义在参数列表中,否则在调用setAttribute的时候会出错,例如定义以下模板:
group test; t1(): << <arg> >>
当调用SetAttribute("arg", "test")时,会报错,不调用SetAttribute("arg", "test")则不会,感觉这个限制应该再严格一点。
参数对默认值的支持,这个与sql server的存储过程参数类似,定义如下模板组(bin\debug\templates\test.stg),当未传递arg2时使用arg2的默认值:
group test; t1(arg1,arg2="参数2") ::= << <arg1> <arg2> >>
当调用的代码为:
StringTemplateGroup g = StringTemplateGroup.LoadGroup("Templates/test"); StringTemplate st = g.GetInstanceOf("t1"); st.SetAttribute("arg1", "参数1"); st.SetAttribute("arg2", "参数2"); Console.WriteLine(st.ToString());
输出:参数1 参数2
当注释掉st.SetAttribute("arg2", "参数2"); 时:
输出:参数1 参数2默认值
它同样支持从匿名模板获取默认值,把模板组定义改成:
group test; t1(arg1, arg2={arg2默认值}) ::= << <arg1> <arg2> >>
同样适用,但若仅仅只是这样的话倒是没太多意义,或许是我还没找到使用的方法。
4、模板作为参数
ST支持模板作为参数传递,定义模板组:
group test; t1(arg1) ::= << <arg1> >> t2(arg1) ::= << <arg1> >>
调用代码:
StringTemplateGroup g = StringTemplateGroup.LoadGroup("Templates/test"); StringTemplate st1 = g.GetInstanceOf("t1"); StringTemplate st2 = g.GetInstanceOf("t2"); st1.SetAttribute("arg1", st2); st2.SetAttribute("arg1", "test"); Console.WriteLine(st1.ToString());
输出: test
但假如把st2.SetAttribute("arg1", "test")改成st2.SetAttribute("arg1", st1),而且开启了LintMode时(StringTemplate.LintMode = true,在调试的时候使用的)将会引起递归调用,参考http://www.antlr.org/wiki/display/ST/Template+and+attribute+lookup+rules。
5、Maps
模板组文件支持一种字典(key/value)类型,稍微有点不同的是它还定义一个默认值,先看例子(调用代码省略):
group test; dict ::= [ "int" : "0", "long" : "00", "float" : "0.0", "bool" : "false", "first" : "1", default : "null" ] t1() ::= << <dict.int> <dict.float> <dict.none> <dict.("first")> >>
输出:0 0.0 null 1
从上面例子可以看出,当访问Maps不存在的key时,会返回它的默认值定义;对于保留字,它同样需要使用dict.("reserveword")来访问。
Maps也可以通过代码访问,它返回的是一个HashTable实例:
StringTemplateGroup g = StringTemplateGroup.LoadGroup("Templates/test"); IDictionary map = g.GetMap("dict"); foreach(DictionaryEntry entry in map) { Console.WriteLine("{0} {1}", entry.Key, entry.Value); }
输出:
float 0.0 first 1 _default_ null bool false long 00 int 0
既然是集合类型,那么同样能够在模板组文件里遍历:
group test; mapIterator() ::= << <dict.keys:{key| 键:<key> 值:<dict.(key)>};separator=","> <\n> <dict.values:{value | <value>};separator=","> >>
输出:
键:float 值:0.0,键:first 值:1,键:_default_ 值:null,键:bool 值:fa lse,键:long 值:00,键:int 值:0 0.0,1,null,false,00,0
不过,default也输出来了...
Maps是一个很好的特性,使用它可以轻松的实现多语言化,如:
中文界面
dict ::= [ "file" : "打开文件", "close" : "关闭文件", "exit" : "退出", default : "未定义" ]
英文界面
dict ::= [ "file" : "open file", "close" : "close file", "exit" : "exit", default : "undefined" ]
通过不同的区域设置来加载不同的语言文件。当然,还可以用于其他类似场景。
本篇就到此为止吧,继承及接口放到下篇。
本文地址:http://www.cnblogs.com/lwme/archive/2010/05/01/1725784.html