自己写的简单的模板引擎
Posted 秋荷雨翔的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自己写的简单的模板引擎相关的知识,希望对你有一定的参考价值。
开发网站需要用到模板引擎,自己写了一个简单的。功能很简单,只做了两件事,一个是替换Model一个是替换List,支持List嵌套。
html模板示例代码如下:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script type="text/javascript" src="/Scripts/jquery/jquery-1.7.1.min.js"></script> <script type="text/javascript" src="/Site/common.js"></script> <script type="text/javascript"> $(function () { $("title").html("${siteInfo.siteName}"); }); </script> </head> <body style="background-color: #fff; font-size: 14px;"> <span style="color: red;">网站基本信息</span><br /> <img alt="" src="${siteInfo.logoUrl}" style="width: 100px; height: 100px;" /> <span>${siteInfo.siteName}</span> <br /> <span style="color: red;">菜单</span> <!-- 菜单 开始 ===================================================================================== --> <ul id="rootMenu"> <#foreach list="channel" model="rootMenu" where="siteId=1 and level=1" > <li> <img alt="" src="${rootMenu.iconUrl}" style="height: 30px; width: 30px;" /> <a href="/Home/List?channelId=${rootMenu.id}&page=1">${rootMenu.title}</a> </li> <ul> <#foreach list="channel" model="subMenu" where="parentId=${rootMenu.id}" > <li> <img alt="" src="${subMenu.iconUrl}" style="height: 30px; width: 30px;" /> <a href="/Home/List?channelId=${subMenu.id}&page=1">${subMenu.title},${subMenu.sort}</a> </li> <#/foreach> </ul> <#/foreach> </ul> <!--菜单 结束 ====================================================================================== --> <span style="color: red;">新闻活动</span> <!-- 内容列表 开始 ===================================================================================== --> <ul> <#foreach list="content" model="con" where="channel.id=1" page="1" pageSize="5"> <li> <img alt="" src="${con.imgUrl}" style="height: 20px; width: 20px;" /> <a href="/Home/Content?contentId=${con.id}">${con.title}</a> ${con.publishTime} </li> <#/foreach> </ul> <!-- 内容列表 结束 ===================================================================================== --> <span style="color: red;">社会责任</span> <!-- 内容列表 开始 ===================================================================================== --> <ul> <#foreach list="content" model="con" where="channel.id=1" page="1" pageSize="5" > <li> <img alt="" src="${con.imgUrl}" style="height: 20px; width: 20px;" /> <a href="/Home/Content?contentId=${con.id}">${con.title}</a> ${con.publishTime} </li> <#/foreach> </ul> <!-- 内容列表 结束 ===================================================================================== --> </body> </html>
模板引擎代码如下,设计的可能不是太好,不过很简单明了:
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Web; using Models; namespace DAL { /// <summary> /// 模板引擎 /// </summary> public class TemplateDal { #region 载入模板 /// <summary> /// 载入模板 /// </summary> public static string LoadTemplate(HttpServerUtilityBase server, string url) { string result = string.Empty; StreamReader sr = new StreamReader(server.MapPath(url), Encoding.UTF8); result = sr.ReadToEnd(); sr.Close(); return result; } #endregion #region 替换页面model /// <summary> /// 替换页面model /// </summary> public static string ReplaceModels(string pageHtml, Dictionary<string, object> data) { Regex reg = new Regex(@"\${([^\${}]+)\.([^\${}]+)}", RegexOptions.IgnoreCase); MatchCollection mc = reg.Matches(pageHtml); foreach (Match m in mc) { if (data.Keys.Contains<string>(m.Groups[1].Value)) { object model = data[m.Groups[1].Value]; Type type = model.GetType(); PropertyInfo propertyInfo = type.GetProperty(m.Groups[2].Value); object obj = propertyInfo.GetValue(model, null); string val = string.Empty; if (obj != null) { if (obj.GetType() == typeof(DateTime)) { val = ((DateTime)obj).ToString("yyyy-MM-dd"); } else { val = obj.ToString(); } } pageHtml = pageHtml.Replace("${" + m.Groups[1].Value + "." + m.Groups[2].Value + "}", val); } } return pageHtml; } #endregion #region 替换列表的model /// <summary> /// 替换列表的model /// </summary> public static string ReplaceModels(string html, string model, object data) { Regex reg = new Regex(@"\${[^\${}]+\.([^\${}]+)}", RegexOptions.IgnoreCase); MatchCollection mc = reg.Matches(html); foreach (Match m in mc) { Type type = data.GetType(); PropertyInfo propertyInfo = type.GetProperty(m.Groups[1].Value); object obj = propertyInfo.GetValue(data, null); string val = string.Empty; if (obj != null) { if (obj.GetType() == typeof(DateTime)) { val = ((DateTime)obj).ToString("yyyy-MM-dd"); } else { val = obj.ToString(); } } html = html.Replace("${" + model + "." + m.Groups[1].Value + "}", val); } return html; } #endregion #region 判断页面是否存在 foreach 标签 /// <summary> /// 判断页面是否存在 foreach 标签 /// </summary> public static bool HasForeach(string html) { Regex reg = new Regex(@"<#foreach[\s]+[^<>]*>", RegexOptions.IgnoreCase | RegexOptions.Singleline); return reg.IsMatch(html); } #endregion #region 替换foreach /// <summary> /// 替换foreach /// </summary> public static string ReplaceLists(string pageHtml) { #region 生成标签集合 Regex reg = new Regex(@"<#foreach[\s]+[^<>]*>", RegexOptions.IgnoreCase | RegexOptions.Singleline); Regex reg2 = new Regex(@"<#/foreach>", RegexOptions.IgnoreCase | RegexOptions.Singleline); MatchCollection mc = reg.Matches(pageHtml); MatchCollection mc2 = reg2.Matches(pageHtml); List<Tag> tagList = new List<Tag>(); foreach (Match m in mc) { Tag tag = new Tag(m.Index, TagType.TagStart, m.Value); tagList.Add(tag); } foreach (Match m in mc2) { Tag tag = new Tag(m.Index, TagType.TagEnd, m.Value); tagList.Add(tag); } tagList.Sort((a, b) => a.pos - b.pos); #endregion for (int i = 0; i < tagList.Count; i++) { Tag tag = tagList[i]; int depth = 0; if (tag.type == TagType.TagStart) { for (int j = i + 1; j < tagList.Count; j++) { if (tagList[j].type == TagType.TagEnd && depth == 0) { string innerHtml = pageHtml.Substring(tag.pos + tag.tagStr.Length, tagList[j].pos - tag.pos - tag.tagStr.Length); ForeachTag foreachTag = new ForeachTag(tag.pos, tagList[j].pos, tag.tagStr, tagList[j].tagStr, innerHtml, pageHtml); return foreachTag.pageHtml; } if (tagList[j].type == TagType.TagStart) { depth++; } if (tagList[j].type == TagType.TagEnd) { depth--; } } } } return pageHtml; } #endregion } //end of class TemplateDal #region Foreach标签 /// <summary> /// Foreach标签 /// </summary> public class ForeachTag { /// <summary> /// 开始位置 foreach开始标签的开始位置 /// </summary> public int start { get; set; } /// <summary> /// 结束位置 foreach结束标签的开始位置 /// </summary> public int end { get; set; } /// <summary> /// 标签字符串 /// </summary> public string tagStr { get; set; } /// <summary> /// 结束标签字符串 /// </summary> public string tagEndStr { get; set; } /// <summary> /// 标签内html /// </summary> public string innerHtml { get; set; } /// <summary> /// 页面html /// </summary> public string pageHtml { get; set; } /// <summary> /// 列表的标识 /// </summary> public string list { get; set; } /// <summary> /// 列表的model /// </summary> public string model { get; set; } /// <summary> /// where /// </summary> public string where { get; set; } /// <summary> /// 当面页数 /// </summary> public int page { get; set; } /// <summary> /// 每页数据条数 /// </summary> public int pageSize { get; set; } /// <summary> /// 替换结果html /// </summary> public string resultHtml { get; set; } public ForeachTag(int start, int end, string tagStr, string tagEndStr, string innerHtml, string pageHtml) { this.start = start; this.end = end; this.tagStr = tagStr; this.tagEndStr = tagEndStr; this.innerHtml = innerHtml; this.pageHtml = pageHtml; Regex reg = new Regex(@"([^\s]+)\s*=\s*""([^""]+)""", RegexOptions.IgnoreCase); MatchCollection mc = reg.Matches(this.tagStr); foreach (Match m in mc) { switch (m.Groups[1].Value) { case "list": this.list = m.Groups[2].Value; break; case "model": this.model = m.Groups[2].Value; break; case "where": this.where = m.Groups[2].Value; break; case "page": this.page = Convert.ToInt32(m.Groups[2].Value); break; case "pageSize": this.pageSize = Convert.ToInt32(m.Groups[2].Value); break; } } switch (list) { case "channel": StringBuilder sb = new StringBuilder(); ChannelDal m_ChannelDal = new ChannelDal(); List<cms_channel_ext> channelList = m_ChannelDal.GetList(this.where); foreach (cms_channel_ext channel in channelList) { sb.Append(TemplateDal.ReplaceModels(this.innerHtml, this.model, channel)); } this.pageHtml = this.pageHtml.Substring(0, this.start) + sb.ToString() + this.pageHtml.Substring(this.end + this.tagEndStr.Length); break; case "content": sb = new StringBuilder(); ContentDal m_ContentDal = new ContentDal(); PagerModel pager = new PagerModel(); pager.rows = this.pageSize; pager.page = this.page; List<cms_content_ext> contentList = m_ContentDal.GetList(ref pager, this.where); foreach (cms_content_ext content in contentList) { sb.Append(TemplateDal.ReplaceModels(this.innerHtml, this.model, content)); } this.pageHtml = this.pageHtml.Substring(0, this.start) + sb.ToString() + "<span id=‘totalRows‘ style=‘display:none;‘>" + pager.totalRows + "</span>" + this.pageHtml.Substring(this.end + this.tagEndStr.Length); break; default: this.pageHtml = this.pageHtml.Substring(0, this.start) + this.pageHtml.Substring(this.end + this.tagEndStr.Length); break; } } } #endregion #region 标签类型 /// <summary> /// 标签类型 /// </summary> public enum TagType { /// <summary> /// 标签开始 /// </summary> TagStart = 1, /// <summary> /// 标签结束 /// </summary> TagEnd = 2 } #endregion #region 标签 /// <summary> /// 标签 /// </summary> public class Tag { /// <summary> /// 标签位置 /// </summary> public int pos { get; set; } /// <summary> /// 标签类型 /// </summary> public TagType type { get; set; } /// <summary> /// 标签字符串 /// </summary> public string tagStr { get; set; } public Tag(int pos, TagType type, string tagStr) { this.pos = pos; this.type = type; this.tagStr = tagStr; } } #endregion } //end of namespace DAL
在Controller中使用模板引擎:
public ActionResult List(int channelId, int page) { PagerModel pager = new PagerModel(); pager.page = page; cms_siteinfo siteInfo = m_SiteInfoDal.Get(); cms_channel channel = m_ChannelDal.Get(channelId); cms_site site = m_SiteDal.Get(channel.siteId); cms_content content = m_ContentDal.GetByChannelId(channelId); if (content == null) { return new RedirectResult(string.Format("/site/{0}/error.html", site.folder)); } string templateHtml = string.Empty; switch (channel.listType) { case (int)Enums.ChannelListType.文字列表: templateHtml = TemplateDal.LoadTemplate(Server, string.Format("/site/{0}/list.html", site.folder)); break; case (int)Enums.ChannelListType.图片列表: templateHtml = TemplateDal.LoadTemplate(Server, string.Format("/site/{0}/list-image.html", site.folder)); break; case (int)Enums.ChannelListType.单篇文章: return new RedirectResult(string.Format("/Home/Content?contentId={0}", content.id)); case (int)Enums.ChannelListType.页面链接: return new RedirectResult(string.Format("{3}?page={1}&channelId={2}", site.folder, page, channelId, channel.pageUrl)); } Dictionary<string, object> dic = new Dictionary<string, object>(); dic.Add("channel", channel); dic.Add("siteInfo", siteInfo); dic.Add("content", content); dic.Add("pager", pager); templateHtml = TemplateDal.ReplaceModels(templateHtml, dic); while (TemplateDal.HasForeach(templateHtml)) { templateHtml = TemplateDal.ReplaceLists(templateHtml); } ViewBag.pageHtml = templateHtml; return View(); }
以上是关于自己写的简单的模板引擎的主要内容,如果未能解决你的问题,请参考以下文章