在实际应用中,极少有可能把模板定义在代码中,一般都是存储在文件中。
ST通过StringTemplateGroup加载模板文件,ST中默认的模板文件后缀名为.st。
1、表达式分隔符
在演示加载模板文件之前,不得不说一下默认的表达式分隔符,ST为模板提供了2种表达式分隔符$…$和<…>,它们分别由Antlr3.ST.Language命名空间下的TemplateLexer、AngleBracketTemplateLexer定义,模板(st)的默认表达式分隔符为$…$;模板组(stg)中的模板默认表达式分隔符为<…>(v2.2版默认为$…$)。
如果不想使用这些表达式分隔符,可以通过继承Antlr.Runtime.Lexer来定义自己的表达式分隔符。
下面演示一下使用尖括号作为模板的表达式分隔符:
StringTemplate st = new StringTemplate("<title>", typeof(AngleBracketTemplateLexer)); st.SetAttribute("title", "使用尖括号作为ST表达式分隔符"); Console.WriteLine(st.ToString());
输出:使用尖括号作为ST表达式分隔符也可以在初始化StringTemplateGroup时指定表达式分隔符。
2、加载模板文件
StringTemplateGroup使用一个templates字典作为在当前group缓存模板,多次加载同一个模板文件,只会从硬盘加载一次。
在3.2版本的ST中,加载模板文件与之前的旧版本(3.1beta1、3.0.1)有了变化:
- 加载模板文件直接由StringTemplateGroup的LoadTemplateFromBeneathRootDirOrCLASSPATH方法来实现;旧版本通过FileSystemTemplateLoader来加载模板文件
- 通过设置RefreshInterval来更改模板缓存时间,设置为TimeSpan.Zero则每次都会重新从硬盘加载,与Java、Python版本一致;旧版本在FileSystemTemplateLoader内部使用FileSystemWatcher来监听文件变更,以自动刷新缓存
- 3.2开始支持从程序集嵌入资源中加载模板(使用了Assembly.GetManifestResourceStream方法);旧版本不支持
- 3.2不支持从当前程序集所在位置的相对路径加载模板;旧版本支持(这个没有印证过,官方文档是这么说的)
StringTemplateGroup加载模板文件的大致过程为:
- 通过LookupTemplate(StringTemplate enclosingInstance, string name)方法在当前group的templates字典中查找此名称的模板,如果已有此模板,则转到步骤5,否则转到步骤2
- 调用File.OpenRead读取文件内容
- 调用LoadTemplate(string name, TextReader r)逐行读取,读取完毕后调用String.Trim()方法去除2边空格
- 调用DefineTemplate(name, pattern)创建模板,并加入到当前group的templates字典(Dictionary<string, StringTemplate>)中
- 返回StringTemplate实例
创建一个模板文件test.st,放到bin\debug\Templates,(当前运行在debug模式),内容:
$title$
从绝对路径加载模板文件,需要指定模板文件所在目录:
StringTemplateGroup group = new StringTemplateGroup("g1", AppDomain.CurrentDomain.BaseDirectory + "\\Templates"); StringTemplate st = group.GetInstanceOf("test"); st.SetAttribute("title", "从绝对路径加载模板文件"); Console.WriteLine(st.ToString());
输出:从绝对路径加载模板文件
如果需要使用相对路径或者不同的路径形式加载模板文件,可以简单的重写StringTemplateGroup的方法:
class LWMEStringTemplateGroup : StringTemplateGroup { public LWMEStringTemplateGroup(string name):base(name){} public LWMEStringTemplateGroup(string name, string rootDir):base(name, rootDir){} public override string GetTemplateNameFromFileName(string fileName) { return Path.GetFileNameWithoutExtension(fileName); } protected override StringTemplate LoadTemplateFromBeneathRootDirOrCLASSPATH(string fileName) { StringTemplate template = null; string name = this.GetTemplateNameFromFileName(fileName); if (this.RootDir == null) { if (!Path.IsPathRooted(fileName)) return this.LoadTemplate(name, fileName); } if (Path.IsPathRooted(fileName)) { return this.LoadTemplate(name, fileName); } if (this.RootDir != null) { template = this.LoadTemplate(name, Path.Combine(this.RootDir, fileName)); } return template; } }
演示代码:
LWMEStringTemplateGroup group = new LWMEStringTemplateGroup("g1"); StringTemplate st1 = group.GetInstanceOf("Templates\\test"); StringTemplate st2 = group.GetInstanceOf(AppDomain.CurrentDomain.BaseDirectory + "Templates\\test"); st1.SetAttribute("title", "通过相对路径加载模板文件"); st2.SetAttribute("title", "通过绝对路径加载模板文件"); Console.WriteLine(st1.ToString()); Console.WriteLine(st2.ToString());
输出结果:通过相对路径加载模板文件 通过绝对路径加载模板文件
以上只是一个简单的示例,假如需要其他的自定义功能,可以通过重写StringTemplateGroup的方法来实现。
另外:加载模板文件并不限于以上方法,也不限于.st后缀,可以直接通过StreamReader、File等对象直接读取文件内容(个人不太喜欢使用这种方式)。
本文地址:http://www.cnblogs.com/lwme/archive/2010/05/01/1725538.html