使用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); } }}