由浅入深:自己动手开发模板引擎——置换型模板引擎1
受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术。本系列文章将会带您由浅入深的全面认识模板引擎的概念、设计、分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎。关于模板引擎的概念,我去年在百度百科上录入了自己的解释(请参考: 模板引擎 )。老陈曾经自己开发了一套 网鸟Asp.Net模板引擎 ,虽然我自己并不乐意去推广它,但这已经无法阻挡群友的喜爱了!
很显然,置换型模板引擎说的就是替换式模板引擎。它的工作原理是查找和替换字符串,但这个字符串的替换过程又分为直接查找替换和按流替代输出两种。直接查找替换实现简单,但存在一定的性能障碍,而按流替代的方式性能更好一点,但理解起来却没那么容易。今天我们就专门来讨论讨论置换型模板引擎的关键技术和实现。
概念
按照不同的置换方案,置换型模板引擎分为 查找替换式 和 按流替代式 两种。查找替换式又分为 字符串替换 和 正则替换两种 。
大家应该都很理解查找替换式模板引擎的含义了,它就是把定义好的标记替换为我们需要的内容即可。而按流替代式虽然在结果上也是将我们指定的标记“替换”为了实际内容,但它内部并没有用到Replace()这种方式,而是在遇到标记的时候直接写出对应的内容,它实际上没有所谓的替换操作,因此性能会好一些。
查找替换式
查找替换这个词大家已经是再也熟悉不过了,我们几乎每天都要编写一次或几次Replace()代码。而查找替换也是构建模板引擎的最基本的思想,任何模板引擎的机制归根结底都还是查找替换。假设我们有如下模板代码和业务数据:
1 /// <summary>
2 /// 模板文本。
3 /// </summary>
4 private const string _TEMPLATE_STRING = @" <a href=""{url}"">{title}</a><br /> " ;
5
6 /// <summary>
7 /// 业务数据。
8 /// </summary>
9 private Dictionary< string , string > _newsItems = new Dictionary< string , string > {
10 { " http://news.qq.com/a/20120330/001077.htm " , " 7名塔利班人员乔装女性 欲打入北约内部被捕 " },
11 { " http://news.qq.com/a/20120330/001409.htm " , " 乌克兰遭轮奸焚烧少女伤重不治离世 " },
12 { " http://news.qq.com/a/20120330/001288.htm " , " 国际空间站宇航员拍到北马里亚纳一火山喷发 " },
13 { " http://news.qq.com/a/20120330/001535.htm " , " 土耳其同性恋男子可免除兵役 须提供确凿证据 " },
14 { " http://news.qq.com/a/20120330/000874.htm " , " 英首相卡梅伦公布宴客名单 否认为筹款聚餐 " },
15 { " http://news.qq.com/a/20120329/001774.htm " , " 孩子飞行途中胡闹不守秩序 全家四口被赶下飞机 " },
16 { " http://news.qq.com/a/20120329/001771.htm " , " 男子上厕所时抽水马桶突然爆炸 大腿和背部受伤 " },
17 { " http://news.qq.com/a/20120329/001685.htm " , " 美国总统奥巴马有意与林书豪切磋球艺 " },
18 { " http://news.qq.com/a/20120329/001696.htm " , " 法国家长与教师联合抵制家庭作业 称加剧不平等 " },
19 { " http://news.qq.com/a/20120329/001650.htm " , " 印尼政府称超短裙“色情” 欲对其颁布禁令 " }
20 };
字符串替换
要使用如上的业务数据生成一个新闻列表,那么做法不外乎如下的代码实现了:
1 /// <summary>
2 /// 最简单的模板引擎。
3 /// </summary>
4 [Test]
5 public void StringReplace()
6 {
7 var html = new StringBuilder();
8
9 foreach ( var newsItem in this ._newsItems)
10 {
11 // 查找替换
12 var news = _TEMPLATE_STRING.Replace( " {url} " , newsItem.Key).Replace( " {title} " , newsItem.Value);
13
14 html.AppendLine(news);
15 }
16
17 Trace.WriteLine(html.ToString());
18 }
其输出结果如下:
1 < a href ="http://news.qq.com/a/20120330/001077.htm" > 7名塔利班人员乔装女性 欲打入北约内部被捕 </ a >< br />
2 < a href ="http://news.qq.com/a/20120330/001409.htm" > 乌克兰遭轮奸焚烧少女伤重不治离世 </ a >< br />
3 < a href ="http://news.qq.com/a/20120330/001288.htm" > 国际空间站宇航员拍到北马里亚纳一火山喷发 </ a >< br />
4 < a href ="http://news.qq.com/a/20120330/001535.htm" > 土耳其同性恋男子可免除兵役 须提供确凿证据 </ a >< br />
5 < a href ="http://news.qq.com/a/20120330/000874.htm" > 英首相卡梅伦公布宴客名单 否认为筹款聚餐 </ a >< br />
6 < a href ="http://news.qq.com/a/20120329/001774.htm" > 孩子飞行途中胡闹不守秩序 全家四口被赶下飞机 </ a >< br />
7 < a href ="http://news.qq.com/a/20120329/001771.htm" > 男子上厕所时抽水马桶突然爆炸 大腿和背部受伤 </ a >< br />
8 < a href ="http://news.qq.com/a/20120329/001685.htm" > 美国总统奥巴马有意与林书豪切磋球艺 </ a >< br />
9 < a href ="http://news.qq.com/a/20120329/001696.htm" > 法国家长与教师联合抵制家庭作业 称加剧不平等 </ a >< br />
10 < a href ="http://news.qq.com/a/20120329/001650.htm" > 印尼政府称超短裙“色情” 欲对其颁布禁令 </ a >< br />
正则表达式
正则表达式实现模板引擎说起来其实并不合适,大家也应该知道其最臭名昭著的就是性能。我们今天只是简单的提一下这种方案,并不算是真的要用它做一个模板引擎。但正则表达式技术在开发复杂的模板引擎是还是非常有用的。
FastReplacer
除了基本的字符串替换和正则表达式之外,这里我再介绍一种更加高效的替换方式—— FastReplacer 。原文地址: http://www.codeproject.com/Articles/298519/Fast-Token-Replacement-in-Csharp 。
FastReplacer通过将字符串中指定格式的标记切分为Token,然后再做查找替换,其效率比字符串替换、正则表达式和StringBuilder要高出许多倍!详情请看原文介绍。这里我列举一下它的使用方法:
如果您有打算做一个查找替换式的模板引擎,那么 FastReplacer 可能会给你带来意想不到的性能优化!
1 /// <summary>
2 /// FastReplacer实现。
3 /// </summary>
4 [Test]
5 public void FastReplacer()
6 {
7 var html = new StringBuilder();
8
9 foreach ( var newsItem in this ._newsItems)
10 {
11 // 您可以通过修改源代码为FastReplacer增加一个Clear方法
12 // 避免产生多个实例以提高性能
13 var fs = new FastReplacer( " { " , " } " );
14 fs.Append(_TEMPLATE_STRING);
15
16 fs.Replace( " {url} " , newsItem.Key);
17 fs.Replace( " {title} " , newsItem.Value);
18
19 html.AppendLine(fs.ToString());
20 }
21
22 Trace.WriteLine(html.ToString());
23 }
以上是简单的查找替换方式的举例,因为不是本文的重点,也很好理解,也就不多说了 (话说——写博客肿么这么累泥?) 。
按流替代式
几个月前我第一次看到 FastReplacer 的时候,以为它内部用的也是流式替代,但仔细研究之后发现不是。那么到底什么是按流替代呢?
我们来看看如下的代码拆解 (老陈所有的文章都是启发式的,因此在文字上不会下很大的工夫,偶滴词汇华丽的很不明显哇) :
< a href =" {url} " > {title} </ a >< br />
这段代码其实可以看做以下代码的组合 (这里以回车换行符隔开了) :
1 <a href= "
2 {url}
3 " >
4 {title}
5 </a><br />
现在有没有感觉到眼前一亮呢?我们把这个字符串按照标记拆分成了5段,每一个小段,无论长短,我们都理解为Token。Token在流式解析当中是一个最基本的元素。
或许,到这里您已经看明白了,其实就是把模板代码按照一定的规则拆分成Token流,就类似于.NET内置的各种Stream一样,与字符串最接近的例如StringReader/StringWriter、XmlReader/XmlWriter等。使用.NET做Web开发的朋友一定对System.Web.HttpResponse再也熟悉不过了,它的Write()就是封装了一个字符串的流的写入操作,只不过这个流最终是写到HTTP网络连接上的。
话题转回来,我们要实现的流式替代就类似于如下过程:
1 // --------------------------------
2 // 流程
3 // <a href="
4 // {url} --> 写为目标数据
5 // ">
6 // {title} --> 写为目标数据
7 // </a><br />
8 // --------------------------------
9 // 伪代码
10 foreach ( var token in tokens)
11 {
12 if (token == " {url} " )
13 {
14 Write( " 链接地址 " );
15 }
16 else (token == " {title} " )
17 {
18 Write( " 新闻标题 " );
19 }
20 else
21 {
22 // 原原本本的输出
23 Write(token);
24 }
25 }
看完代码,您要是再不明白什么是流式替代的话,那我真的要哭了!
不过,新的问题产生了——如何把模板代码变换为Token流呢?不要着急,这是下一节我们将要讲述的内容!
小结及代码下载
因为我的写作时间并不多,因此这里采用了单元测试的一些代码结构,不过对大家阅读和理解不会造成影响。
本文代码将与下一篇文章合并提供下载,祝各位工作顺利、开心快乐!
【NoSQL群】NoSQL系列技术QQ群:
一群:23152359(满员)
二群:193713524(强烈推荐)
三群:132740383(实名群,仅邀请加入)
四群:191830739(精英群,仅邀请加入)
入群写明理由,否则一律拉黑!
关于老陈:一只不小心踏入互联网十二年的老猴子,喜欢在群里跟大家伙儿研究和分享各种V。天造的懒汉,十足的吃货!
模板引擎
模板引擎技术深度分享。
由浅入深:自己动手开发模板引擎——置换型模板引擎(一)
摘要: 很显然,置换型模板引擎说的就是替换式模板引擎。它的工作原理是查找和替换字符串,但这个字符串的替换过程又分为直接查找替换和按流替代输出两种。直接查找替换实现简单,但存在一定的性能障碍,而按流替代的方式性能更好一点,但理解起来却没那么容易。今天我们就专门来讨论讨论置换型模板引擎的关键技术和实现。 阅读全文
posted @ 2012-03-31 09:08 陈彦铭 阅读(620) | 评论 (10) 编辑
由浅入深:自己动手开发模板引擎——什么是模板引擎
摘要: 最初的模板引擎是为了实现业务逻辑和代码分离,后来发现这样的模式给界面维护带来了极大的便利,这也是一种MVC模式的实现。现在我们在很多地方都可以看到模板引擎的身影,比如各种CMS、论坛、代码生成器,甚至是Mootools、JQuery等JavaScript库都用到了模板引擎。那么模板引擎到底是个什么东东呢?模板引擎在实际生产环境中有着什么样的意义?我们到底是否应该使用模板引擎技术?接下来我们会一一解答。 阅读全文
posted @ 2012-03-29 09:13 陈彦铭 阅读(2054) | 评论 (18) 编辑
作者: Leo_wl
出处: http://www.cnblogs.com/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息查看更多关于由浅入深:自己动手开发模板引擎——置换型模板引擎1的详细内容...