模板引擎開發(三)-自定義標籤的處理

自定義標籤大體能夠理解爲一個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的用戶控件,精力有限,暫時先這樣吧。

相關文章
相關標籤/搜索