StringTemplate.Net 学习笔记(7):加载模板文件

在实际应用中,极少有可能把模板定义在代码中,一般都是存储在文件中。

ST通过StringTemplateGroup加载模板文件,ST中默认的模板文件后缀名为.st。

1、表达式分隔符

在演示加载模板文件之前,不得不说一下默认的表达式分隔符,ST为模板提供了2种表达式分隔符$…$和<…>,它们分别由Antlr3.ST.Language命名空间下的TemplateLexerAngleBracketTemplateLexer定义,模板(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)有了变化:

  1. 加载模板文件直接由StringTemplateGroup的LoadTemplateFromBeneathRootDirOrCLASSPATH方法来实现;旧版本通过FileSystemTemplateLoader来加载模板文件
  2. 通过设置RefreshInterval来更改模板缓存时间,设置为TimeSpan.Zero则每次都会重新从硬盘加载,与Java、Python版本一致;旧版本在FileSystemTemplateLoader内部使用FileSystemWatcher来监听文件变更,以自动刷新缓存
  3. 3.2开始支持从程序集嵌入资源中加载模板(使用了Assembly.GetManifestResourceStream方法);旧版本不支持
  4. 3.2不支持从当前程序集所在位置的相对路径加载模板;旧版本支持(这个没有印证过,官方文档是这么说的)

StringTemplateGroup加载模板文件的大致过程为:

  1. 通过LookupTemplate(StringTemplate enclosingInstance, string name)方法在当前group的templates字典中查找此名称的模板,如果已有此模板,则转到步骤5,否则转到步骤2
  2. 调用File.OpenRead读取文件内容
  3. 调用LoadTemplate(string name, TextReader r)逐行读取,读取完毕后调用String.Trim()方法去除2边空格
  4. 调用DefineTemplate(name, pattern)创建模板,并加入到当前group的templates字典(Dictionary<string, StringTemplate>)中
  5. 返回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

参考:http://www.antlr.org/wiki/display/ST/Defining+Templates

原文地址:https://www.cnblogs.com/lwme/p/1725538.html