C# 的文本模板类






4.14/5 (12投票s)
一个使用 RegEx 回调函数的 .NET 文本模板简单类。
引言
可以使用 RegEx.Replace()
方法的 MatchEvaluator
委托在 C# 中实现一个基于标签的模板系统。这些标签存储在哈希表中,键是标签本身,替换文本是 TemplateTag
对象的 Value。操作哈希表和解析模板的代码包含在单个类 TemplateParser
中。
背景
我广泛使用 ASPTemplate 进行 ASP 开发和代码生成,因此我自然而然地开始寻找 C# 中类似的东西。在我的搜索过程中,我遇到了 Jack Herrington 撰写的文章 Ruby 中的模板,其中结合了正则表达式和哈希表来构建一个简单的模板系统。由于我找不到任何其他满足我需求的基于 C# 的标签模板系统,所以我决定按照相同的想法自己编写一个。
目标是能够获取包含标签的模板文档,并有一种简单的方法用值替换这些标签。模板文档看起来像
Tag1 == [%tag1%] Tag2 == [%tag2%]
The sky is [%SkyColor%].
Today is [%TodayDate%].
其中标签由 [%...%] 标记分隔。如果我们将标签设置为以下值
[%tag1%] = This is Tag 1
[%tag2%] = This is not Tag 1 but Tag 2
[%SkyColor%] = blue
[%TodayDate%] = 11/19/2004
那么模板解析器的最终输出应该为
Tag1 == This is Tag 1 Tag2 == This is not Tag 1 but Tag 2
The sky is blue.
Today is 11/19/2004.
代码
TemplateParser
类包含存储标签和处理模板的所有代码。这些标签存储在 HashTable
_templateTags
中。
private Hashtable _templateTags = new Hashtable();
HashTable
包含一个 TemplateTag
对象集合。TemplateTag
对象包含两个 string
属性,Tag
和 Value
。Tag
用作哈希表键,而 Value
用于替换模板中的标签。
模板标签通过重载的 public
方法 AddTag()
添加到哈希表。可以使用 RemoveTag()
方法删除单个标签,或者可以使用 ClearTags()
方法清除所有标签。
public void AddTag( TemplateTag templateTag )
{
_templateTags[templateTag.Tag] = templateTag;
}
public void AddTag( string Tag, string Value )
{
AddTag( new TemplateTag( Tag, Value ) );
}
public void RemoveTag( string Tag )
{
_templateTags.Remove( Tag );
}
public void ClearTags()
{
_templateTags.Clear();
}
默认的标签样式是 [%...%],并且使用正则表达式 @"(\[%\w+%\])"
找到这些标签。这可以通过更改 TemplateParser
的 MatchPattern
属性来更改。
Regex.Replace
函数具有一个接受委托函数的重载运算符。委托函数需要传递一个 System.Text.RegularExpressions.Match
参数,并返回一个 string
。
NetTemplate
的委托函数检查 Match.Value
(即模板标签)是否在标签 HashTable
中。如果标签存在,则从 HashTable
返回标签的 Value
,否则返回一个空字符串。
private string _replaceTagHandler( Match token )
{
if ( _templateTags.Contains( token.Value ) )
return ((TemplateTag) _templateTags[token.Value]).Value;
else
return string.Empty;
}
public
ParseTemplateString()
方法获取要解析的字符串并返回已解析的字符串。这允许您处理单个字符串,而不仅仅局限于处理模板文件。
public string ParseTemplateString( string Template )
{
MatchEvaluator replaceCallback = new MatchEvaluator( _replaceTagHandler );
string newString = Regex.Replace( Template, _matchPattern, replaceCallback );
return newString;
}
ParseTemplateFile()
获取模板的文件名,将内容读入文件缓冲区,然后将缓冲区传递给 ParseTemplateString()
。
public string ParseTemplateFile( string TemplateFilename )
{
string fileBuffer = _fileToBuffer( TemplateFilename );
return ParseTemplateString( fileBuffer );
}
private string _fileToBuffer( string Filename )
{
if( !File.Exists( Filename ) )
throw new ArgumentNullException( Filename,
"Template file does not exist" );
StreamReader reader = new StreamReader( Filename );
string fileBuffer = reader.ReadToEnd();
reader.Close();
return fileBuffer;
}
使用 TemplateParser
要解析模板字符串,请创建 TemplateParser
的一个实例,添加标签和值,然后执行方法 ParseTemplateString()
public void SimpleParse()
{
TemplateParser tp = new TemplateParser();
tp.AddTag( new TemplateTag( "[%Title%]", "Template Test" ) );
string inputString = @"This is a [%Title%] or is it.";
string outputString = tp.ParseTemplateString(inputString);
string expectedResults = @"This is a Template Test or is it.";
Assert.AreEqual( expectedResults, outputString);
}
要解析模板文件,唯一需要的区别是将文件名传递给 ParseTemplateFile()
方法
public void TemplateFileTester()
{
string TemplateFilename = @".\TemplateTest.txt";
TemplateParser tp = new TemplateParser();
tp.AddTag( new TemplateTag( "[%test1%]", "test1 SAT") );
tp.AddTag( new TemplateTag( "[%test2%]", "test2 SAT") );
tp.AddTag( new TemplateTag( "[%test3%]", "test3 SAT") );
tp.AddTag( new TemplateTag( "[%test4%]", "test4 SAT") );
tp.AddTag( new TemplateTag( "[%test5%]", "test5 SAT") );
tp.AddTag( new TemplateTag( "[%test6%]", "test6 SAT") );
string parsedFile = tp.ParseTemplateFile(TemplateFilename);
string TemplateOutput = @".\TemplateTestOut.txt";
if (File.Exists(TemplateOutput)) File.Delete(TemplateOutput);
StreamWriter writer = new StreamWriter(TemplateOutput);
writer.Write(parsedFile);
writer.Flush();
writer.Close();
}
关注点
我真的对这个模板系统的构建方式感到惊讶。诚然,我没有进行任何测量来查看它的运行速度,但是考虑到我的大多数模板文件都很小,这应该不是一个大问题。
我将来想进行的一个修改是为 TemplateTag
对象使用一个接口。这将允许我使用字符串值以外的更多内容作为模板。
历史
- 2004 年 12 月 9 日:文章提交。
- 2004 年 12 月 10 日:根据 SimmoTech 的更正和更改。