使用asp.net创建自己的模板引擎是相当简单的事情,而我们所使用的仅仅需要正则和反射两个工具就足够了。
来看看下面一个来自于真实项目的模板页(者进行了适当的精简,为方便阅读):
<!DOCTYPE html>
<html>
<head>
<title>${SYS_NAME}</title>
</head>
<body>
$require('${id}')
${partial:"common/blog.header.phtml"}
<div class="sitepath">您当前的位置:<a href="${SYS_DOMAIN}" rel="nofollow">首页</a>>$sitemap('${categoryTag}')>${title}</div>
<!-- 显示文档 -->
$archive('${id}','
<h1>{title}</h1>
<p class="meta">作者:{authorname} 发布时间:{createtime2} 浏览次数:
<span class="hightlight">{count}</span> 评论:<span class="hightlight">{replay}</span> 条<br />
{content}
</p>
')
<div class="relation" style="text-align:center;padding:20px 0">
上一篇:$prevarchive('${id}','<a href="{url}">{title}</a>') | 下一篇:$nextarchive('${id}','<a href="{url}">{title}</a>')
<br />关键词:
$tags('${tags}','<a href="{searchurl}" target="_blank">{name}</a> ')
</div>
<!-- 文档评论 -->
<div class="comments" id="comments">
<ul>
$comment('<li id="comment{id}"><span class="meta"><span class="floor">{index}楼</span>
<span class="user">{nickname}</span> 于 <span class="date">{date}说:</span><span class="content">{content}</span></li>'
,'false','true')
</ul>
</div>
<div id="submitComment">
<span class="title">发布评论</span>
$comment_editor('','true')
</div>
${partial:"common/blog.footer.phtml"}
</body>
</html>
在这个模板页中,使用$method(param) 来调用数据所提供的方法,在方法内部可以接受一个模板片段参数,改参数使用{paramName} 传入,并返回数据。
通过文件,我们不难看出这是一个博客的博文显示页面,包括了评论功能。通过插槽式的组合,我们可以通过修改这个文件而无需重写代码(仅对功能相对固定的系统),充分使用模板带来的便利优势。接下来的一系列文章,将通过对这个模板引擎的分析,教新手开发一个自定义的模板引擎。...
以下是片段代码:SmpleTpl.cs
/*******************************************
* 文 件 名:SimpleTpl.cs
* 文件说明:asp.net模板引擎解析文件
* 创 建 人:newmin
* 个人博客: http://blog.ops.cc
******************************************/
namespace U1City.Shop.Unit
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Reflection;
/// <summary>
/// 简单模板解析类
/// </summary>
public sealed class SimpleTpl
{
/// <summary>
/// 包含方法的类型实例
/// </summary>
private object classInstance;
public SimpleTpl(object classInstance)
{
this.classInstance = classInstance;
}
/// <summary>
/// 数据列正则
/// </summary>
private static Regex fieldRegex = new Regex("{([a-z0-9_]+)}");
/// <summary>
/// 执行解析模板内容
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
public static string Execute(object instance, string html)
{
string resultTxt = html; //返回结果
const string tagPattern = "\\$([a-z0-9]+)\\(([^)]+')\\)";
const string paramPattern = "'([^']+)',*";
Regex tagRegex = new Regex(tagPattern); //方法正则
Regex paramRegex = new Regex(paramPattern); //参数正则
Type type = instance.GetType();
MethodInfo method;
string tagName;
object[] parameters;
Type[] parameterTypes; //参数类型数组
MatchCollection paramMcs;
resultTxt = tagRegex.Replace(resultTxt, m =>
{
tagName = m.Groups[1].Value;
string x = m.Groups[2].Value;
//获得参数
paramMcs = paramRegex.Matches(m.Groups[2].Value);
parameters = new object[paramMcs.Count];
//查找是否存在方法(方法参数均为string类型)
parameterTypes = new Type[parameters.Length];
for (int i = 0; i < parameterTypes.Length; i++)
{
parameterTypes[i] = typeof(String);
}
method = type.GetMethod(
tagName,
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.IgnoreCase,
null,
parameterTypes,
null);
//如果方法存在则执行返回结果,否则返回原始值
if (method == null)
{
return m.Value;
}
else
{
//则给参数数组赋值
for (int i = 0; i < paramMcs.Count; i++)
{
parameters[i] = paramMcs[i].Groups[1].Value;
}
//执行方法并返回结果
return method.Invoke(instance, parameters).ToString();
}
});
return resultTxt;
}
/// <summary>
/// 执行解析模板内容
/// </summary>
public string Execute(string html)
{
return Execute(this.classInstance, html);
}
}
}