自定義標籤大體能夠理解爲一個HTML代碼塊,也能夠指向一個HTML文件。html
在模板頁中,不少地方須要相同的內容,例如頁面的頭部、尾部等,這個時候,能夠利用自定義標籤來定義HTML代碼,而後在模板頁中引用就能夠了。正則表達式
自定義標籤的格式以下:
{%@ pageTop%} 頁面頂部的頂部的自定義標籤;算法
自定義標籤中的HTML代碼,我用了XML來記錄,固然也有可視化的編輯界面來操做,在這裏就再也不綴述,只是說明一下原理便可,XML以下:asp.net
<Tag Uid="5895643"> <Name>PageTop</Name> <Type>page</Type> <Intro><![CDATA[全部頁面的頂部]]></Intro> <Page>PageTop.html</Page> <Context><![CDATA[<div id="pagetop">logo 信息化動力核心 </div> <div></div>]]></Context> </Tag>
上述代碼,標明瞭自定義標籤的惟一標識、名稱、類型(指定某個頁面)、介紹、html文件名、html代碼塊;ide
說到這裏就簡單了,咱們只須要把自定義標籤從模板頁中檢索出來,替換成HTML代碼就好了。代碼以下:ui
/// <summary> /// 將模板內容中的全部自定義標籤,替換爲實際的值 /// </summary> /// <param name="html">要處理的模板對象</param> /// <returns></returns> public string Transact(TemplateBuider.PageTransact.Html html) { string patt = @"{%@\s*(\S[^\s%]+)\s*%}"; Regex rex = new Regex(patt, RegexOptions.Singleline); MatchCollection mc = rex.Matches(html.HtmlContext); for (int i = 0; i < mc.Count; i++) { Match ma = mc[i]; string key = ma.Groups[1].Value; //獲取當前標籤對象 Song.TemplateManager.Tags.CustomTag custom = _tags.Find(delegate(TemplateManager.Tags.CustomTag p) { return p.Name.ToLower() == key.ToLower(); }); if (custom == null) continue; //轉換自定義標籤中的路徑,使之與當前模板頁爲相對路徑 string context =_replacePath(html, custom); //將自定義標籤合併到的模板 html.HtmlContext = Microsoft.VisualBasic.Strings.Replace(html.HtmlContext, ma.Value, context, 1, -1, Microsoft.VisualBasic.CompareMethod.Text); } return html.HtmlContext; }
上述代碼有一些是我係統中相關方法,你們沒必要關注,關鍵是正則表達式。spa
可這個時候,有個問題。各個模板頁並不在一個文件夾下,路徑各不相同,自定義標籤中的HTML若是有超連接,在模板頁引用後,若是隻是簡單的替換,這些超連接就有可能出錯,找不到指定的內容。因此,咱們必須將自定義標籤中的連接對象轉換成當前模板的路徑名。.net
思路是這樣的,首先找出自定義標籤的路徑,若是自定義標籤是指向HTML文件的,則按Html路徑;若是是純HTML代碼,則以當前模板庫的路徑爲路徑;自定義標籤中的全部連接,包括超連接、CSS引用、Js引用、iframe等,轉換爲相對於自定義標籤路徑的路徑;而後找當前模板頁的路徑;將全部的連接轉換爲當前模板頁的路徑。code
這中間牽涉到一個算法,從A文件到B文件的相對路徑。舉例說:A文件在/3/4/5/q/w/a.html,B文件在/3/4/6/s/b.html,若是A文件中寫一個超連接引用B文件,這個超連接怎麼寫?
我這裏寫了一個方法。計算兩個文件的相對路徑,代碼以下:htm
/// <summary> /// 計算兩個文件的相對路徑 /// </summary> /// <param name="baseFile">用於參照的文件,就從當前文件開始查找另外一個文件</param> /// <param name="targetFile">目標文件,就是求它的相對路徑</param> /// <returns>返回targetFile相對於baseFile的相對路徑</returns> private string _getRelativePath(string baseFile, string targetFile) { baseFile = baseFile.Replace("\\", "/"); baseFile = baseFile.ToLower(); targetFile = targetFile.ToLower(); // while (baseFile.IndexOf("/") > -1 && targetFile.IndexOf("/") > -1) { string b = baseFile.Substring(0, baseFile.IndexOf("/")); string t = targetFile.Substring(0, targetFile.IndexOf("/")); if (b != t) break; baseFile = baseFile.Substring(baseFile.IndexOf("/") + 1); targetFile = targetFile.Substring(targetFile.IndexOf("/") + 1); } string path = ""; while (baseFile.IndexOf("/") > -1) { baseFile = baseFile.Substring(baseFile.IndexOf("/") + 1); path += "../"; } return path + targetFile; }
有了上面的方法,就好處理了,真正的超連接轉換,就是正則匹配處理了。方法以下:
/// <summary> /// 將模板頁中的路徑處理成相對於當前模板頁的路徑 /// </summary> /// <param name="html"></param> /// <param name="tag"></param> /// <returns></returns> private string _replacePath(TemplateBuider.PageTransact.Html html, TemplateManager.Tags.CustomTag tag) { string context = tag.Context; //處理自定義標籤中的超連接,使其相對於當前文件路徑 string cutomPath = _cutomPath(tag); //將超連接處理爲相對於模板頁的路徑 string linkExpr = @"(?<=\s+)(?<key>href|src|action|background[^=""']*)=([""'])?(?<value>[^'"">]*)\1?"; Regex regex = new Regex(linkExpr, RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase); MatchCollection mc = regex.Matches(tag.Context); foreach (Match m in mc) { string link = m.Groups["value"].Value.Trim(); if (link == "") continue; //外網連接不處理,如Http://開頭的超連接 if (new Regex(@"[a-zA-z]+://[^\s]*", RegexOptions.Singleline).IsMatch(link)) continue; //根路徑不處理,如/manage/index.aspx,第一個字符是/ if (new Regex(@"^\/\w+.").IsMatch(link)) continue; //若是是參數標籤,則不處理 if (new Regex(@"^{.+").IsMatch(link)) continue; //將超連接轉換爲相對於靜態化目錄的路徑 link = _getCutomLinkPath(cutomPath, link); //將超連接轉換爲基於當前模板頁的相對路徑 link = _getRelativePath(html.TagetFile, link); link = m.Groups[2].Value + "=\"" + link + "\""; context = context.Replace(m.Value, link); } return context; }
在上述代碼中,根路徑不處理、站外連接不處理、以{開頭的連接不處理。
總結
個人這個自定義標籤功能並不強,雖然自定義標籤中也能夠有其它組件,但其本質未變,只是HTML代碼塊的替換。原本想寫帶參數的自定義標籤呢,這樣就更相似於asp.net的用戶控件,精力有限,暫時先這樣吧。