由浅入深:自己动手开发模板引擎——解释型模板引擎(二)
受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术。本系列文章将会带您由浅入深的全面认识模板引擎的概念、设计、分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎。关于模板引擎的概念,我去年在百度百科上录入了自己的解释(请参考:模板引擎)。老陈曾经自己开发了一套网鸟Asp.Net模板引擎,虽然我自己并不乐意去推广它,但这已经无法阻挡群友的喜爱了!
概述
本课我们主要讨论“命令解释器”的实现。命令就是指令,指令也是构成更加复杂的模板引擎的基本元素之一。至此我们可以归纳出来,模板引擎在工作的过程中,首先将字符流转换为Token流,然后再将Token流转换为Element集合(也算是流),然后将特定的Element单独拿出来或组合在一起形成指令、语句等。写一个模板引擎,和写一个小型的编译器几乎相当,因此我们需要耐心、细心!
目标
解析并运行如下模板代码结构:
- /_Page_Footer.shtml
- /_Page_Header.shtml
- /_Public_Footer.shtml
- /_Public_Header.shtml
- /Index.shtml
文件"/_Page_Footer.shtml"包含的代码:
<!--#include file="_Public_Footer.shtml" -->
文件"/_Page_Header.shtml"包含的代码:
<!--#include file="_Public_Header.shtml" -->
文件"/_Public_Footer.shtml"包含的代码:
</body></html>
文件"/_Public_Header.shtml"包含的代码:
<!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>{UserName}的博客</title></head><body>
文件"/Index.shtml"包含的代码:
1 <!--#include file="_Page_Header.shtml" -->2 <ul>3 <li>博主姓名:{UserName}</li>4 <li>创建日期:{CreationTime:yyyy年MM月dd日 HH:mm:ss}</li>5 <li>粉丝数量:{FunsCount:D4}</li>6 </ul>7 <!--#include file="_Page_Footer.shtml" -->
今天的模板内容被切分成了5个部分,嵌套层次达到了3层,解析难度比较大。实际上在编写本文之前,我自己的解释型模板引擎在内部是使用正则表达式的方式来实现嵌套指令解析的。不过,我们今天不会这么做了!
使用正则表达式实现
本节课的目的是说明命令解释器的实现,本着循序渐进的原则,我们首先考虑使用正则表达式来实现“<!--#include file="_Page_Header.shtml" -->”命令,在以后的课程中我们将会学习更加复杂的代码解析方法。
我们需要按照顺序使用正则表达式递归的读取和合并代码文档,具体实现如下:
1 /// <summary> 2 /// 表示 #Include 命令解释器。 3 /// </summary> 4 public static class IncludeCommandParser 5 { 6 private static int _nestedCount; 7 8 /// <summary> 9 /// 处置包含文档。 10 /// </summary> 11 /// <param name="templateString">包含模板代码的字符串。</param> 12 /// <param name="basePath">处置包含命令时要使用的基准路径。</param> 13 /// <returns>返回 <see cref="string"/>。</returns> 14 public static string Parse(string templateString, string basePath) 15 { 16 if (String.IsNullOrWhiteSpace(templateString)) return String.Empty; 17 if (String.IsNullOrWhiteSpace(basePath)) return templateString; 18 19 if (Directory.Exists(basePath) == false) throw new DirectoryNotFoundException(); 20 21 return _ProcessSSIElement(templateString, basePath); 22 } 23 24 private static string _ProcessSSIElement(string templateString, string basePath) 25 { 26 if (_nestedCount > 10) return templateString; 27 28 var matches = Regex.Matches(templateString, @"<!--#include file=""([^""]+)""\s*-->", RegexOptions.IgnoreCase | RegexOptions.Singleline); 29 30 foreach (Match match in matches) 31 { 32 var file = new FileInfo(Path.Combine(basePath, match.Groups[1].Value.Replace('/', '\\'))); 33 34 if (file.Exists == false) continue; 35 36 var subTemplate = File.ReadAllText(file.FullName).Trim(); 37 38 subTemplate = _ProcessSSIElement(subTemplate, Path.GetDirectoryName(file.FullName)); 39 40 templateString = templateString.Replace(match.Groups[0].Value, subTemplate); 41 } 42 43 _nestedCount++; 44 45 return templateString; 46 } 47 }
测试代码:
1 [Test] 2 public void LoadFileTest() 3 { 4 var fileName = Path.Combine(Environment.CurrentDirectory, "Templates\\Index.shtml"); 5 6 Assert.AreEqual(File.Exists(fileName), true); 7 8 this._templateString = File.ReadAllText(fileName); 9 10 Assert.NotNull(this._templateString); 11 12 Trace.WriteLine(this._templateString); 13 14 Assert.Greater(this._templateString.IndexOf("{CreationTime:yyyy年MM月dd日 HH:mm:ss}", StringComparison.Ordinal), 0); 15 } 16 17 [Test] 18 public void ProcessTest() 19 { 20 this.LoadFileTest(); 21 22 Trace.WriteLine("本次输出:"); 23 24 var basePath = Path.Combine(Environment.CurrentDirectory, "Templates"); 25 var templateEngine = TemplateEngine.FromString(this._templateString, basePath); 26 27 templateEngine.SetVariable("url", "http://www.ymind.net/"); 28 templateEngine.SetVariable("UserName", "陈彦铭"); 29 templateEngine.SetVariable("title", "陈彦铭的博客"); 30 templateEngine.SetVariable("FunsCount", 98); 31 templateEngine.SetVariable("CreationTime", new DateTime(2012, 4, 3, 16, 30, 24)); 32 33 var html = templateEngine.Process(); 34 Trace.WriteLine(html); 35 }
运行结果:
1 <!--#include file="_Page_Header.shtml" --> 2 <ul> 3 <li>博主姓名:{UserName}</li> 4 <li>创建日期:{CreationTime:yyyy年MM月dd日 HH:mm:ss}</li> 5 <li>粉丝数量:{FunsCount:D4}个</li> 6 </ul> 7 <!--#include file="_Page_Footer.shtml" --> 8 9 本次输出: 10 <!DOCTYPE HTML> 11 <html> 12 <head> 13 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 14 <title>陈彦铭的博客</title> 15 </head> 16 <body> 17 <ul> 18 <li>博主姓名:陈彦铭</li> 19 <li>创建日期:2012年04月03日 16:30:24</li> 20 <li>粉丝数量:0098个</li> 21 </ul> 22 </body> 23 </html>
运行结果达到了我们的期望值!
总结和代码下载
本课只是简单的介绍命令解释器的实现思路,实际上还有其他很多办法可以实现。
从下节课开始,我们将会接触到更多代码标记的解析方式,每篇博文篇幅不会太长,但一定会挑重点、击中要害!
本节课的内容较为简单,不提供代码下载。
模板引擎系列教程的规模比原来预想的还要庞大,因为我不想仅仅帖出各种代码就了事,希望能从更多的角度给大家分享。因此,该系列文章以后全部划入周末写作。平时只写文字性内容,或小篇幅技术文章。
希望大家能够谅解!
转载于:https://www.cnblogs.com/ymind/archive/2012/04/15/progressively-develop-templateEngine-yourself-Interpreted-type-2.html
由浅入深:自己动手开发模板引擎——解释型模板引擎(二)相关推荐
- 由浅入深:自己动手开发模板引擎——解释型模板引擎
受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术.本系列文章将会带您由浅入深的全面认识模板引擎的概念.设计.分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎.关于 ...
- 由浅入深:自己动手开发模板引擎——置换型模板引擎(四)
受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术.本系列文章将会带您由浅入深的全面认识模板引擎的概念.设计.分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎.关于 ...
- 由浅入深:自己动手开发模板引擎——置换型模板引擎(三)
受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术.本系列文章将会带您由浅入深的全面认识模板引擎的概念.设计.分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎.关于 ...
- 由浅入深:自己动手开发模板引擎——置换型模板引擎(二)
受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术.本系列文章将会带您由浅入深的全面认识模板引擎的概念.设计.分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎.关于 ...
- 由浅入深:自己动手开发模板引擎——置换型模板引擎(一)
受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术.本系列文章将会带您由浅入深的全面认识模板引擎的概念.设计.分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎.关于 ...
- python中动态语言静态语言的定义_作为程序开发,你所需要知道的编译型与解释型、动态语言与静态语言、强类型语言与弱类型语言的概念以及区别...
作为程序开发,你所需要知道的编译型与解释型.动态语言与静态语言.强类型语言与弱类型语言的概念以及区别! 在各式各样的开发过程当中,我相信各位开发小伙伴在开发过程中并没有太关注什么是解释性语言和编译性语 ...
- freemarker ftl模板_Web开发人员必会的模板引擎技术之Freemarker
曾几何时,Web开发是个多么高大上的名字,程序猿们都以能搞定Web技术为荣,此时还没有前后端之说.然而随着互联网的发展,社会分工进一步细化,职业岗位也更加细分,慢慢开始有了前端攻城狮和后端攻城狮,技术 ...
- mysql模板引擎_MYSQL存储引擎解释
存储引擎解释 首先确定一点,存储引擎的概念是MySQL里面才有的,不是所有的关系型数据库都有存储引擎这个概念, MySQL支持多种存储引擎,每种引擎有着一些自己独特的功能,用户在使用的时候,可以根 ...
- 用Python开发一个自制的编程语言(虚拟机解释型)[2] 词法分析器(2)
在上一篇文章中,我们搭好了一个编程语言解释器基本的框架,完成了一部分的词法分析器,下面让我们继续努力.用Python开发一个自制的编程语言(虚拟机解释型)[1] 词法分析器(1)_嘉定世外的JinJi ...
最新文章
- SQLAlchemy_定义(一对一/一对多/多对多)关系
- Transformation XML(TCODE-STRANS)
- deepin linux深度ISO镜像下载地址
- Bazel构建工具的安装
- 2017 Material design 第二章第六节《富有创造性的定制方案》
- 面向对象基础-委托与事件
- python dicom图像分割_python读取DICOM头文件的实例
- Talib技术因子详解(十)
- 计算机一级考试 文字录入,计算机一年级《文字录入》期末考试题(理论)B
- 研发项目成本计算方法以及工作量评估
- 周六研易01:深入研究甲木选用法
- 启动服务器后台打印系统,服务器打印后台处理
- 怎么能避免浏览器请求超时_浏览器所允许的http请求最长的响应时间?
- ROS 交叉编译介绍
- 第8讲 - C语言关键字(8)
- 你们一个个都人工智能了,让PC怎么办?
- Nvidia Xavier平台CAN收发控制器调试记录
- EXP4恶意代码分析 20154306 刘宇轩
- 结合实例分析arm指令集中的adds指令与arm内嵌汇编
- mysql delete from table_mysql delete from table 失败
热门文章
- 源码解读:KubeVela 是如何将 appfile 转换为 K8s 特定资源对象的
- iptv直播_全球IPTV高清直播网络电视+4K频道
- 计算机应用基础(本)实训任务1,计算机应用基础(本)实训任务1-2.pdf
- 计算机二级c语言考生文件夹在哪,2017年全国计算机二级C语言考试题
- linux怎么复制手册,程序员的Linux上手手册(2) - 基础文件操作命令
- python优秀库_2017年度15个优秀的数据科学领域Python库
- arcengine遍历属性表_记录一次Hive表清理过程
- 【CV秋季划】模型算法与落地很重要,如何循序渐进地学习好?
- 【CV夏季划】2021年有三AI-CV夏季划出炉,冲刺秋招,从CV基础到模型优化彻底掌握...
- 【杂谈】关于批量采购与教材试点深度学习之图像识别,模型设计,人脸图像处理书籍相关问题...