自定义标签大体能够理解为一个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的用户控件,精力有限,暂时先这样吧。