AderTemplate
http://www.cnblogs.com/kwklover/archive/2007/07/12/815509.html
概述
AderTemplate是一个小型的模板引擎。无论是拿来直接使用还是用来研究模板引擎实现方式,都是一个不错的选择。本文尝试对其源代码做一些分析。
数据流程
AderTemplate的数据处理流程可以总结为:
模版文件 -> 模版分析 -> Template对象 -> 分析处理Template的Element集合 -> 输出目标文本
模版语法
简化描述如下:
1,变量替换 :如#variable#
2,循环语句 :<ad:foreach var="x" collection="#values#" index=”i”></ad:foreach>
3,判断语句 :<ad:if test="#value#"> </ad:if>
详细请参看AderTemplate的相关说明.
模版分析
模版分析的过程可以分成两步:
1,把模版文件分析成Token流 ;
2,对Token流进行分析,形成Element集合
所以,首先要了解Token和Element的结构与异同。
Token的类结构:
TokenKind(Token的类型)的详细说明:
TokenKind |
说明 |
EOF |
结束符 |
Comment |
注释,但在AderTemplate没看到具体实现 |
ID |
这个比较难描述,下面会通过输出Token流来直官了解下ID |
TextData |
文本数据,不包含模版语法的独立文本区 |
TagStart |
Tag的开始标记,即<ad: 注:Tag是一个Element,后面详述 |
TagEnd |
Tag的结束符,即 > ,注意与TagClose的区别 |
TagEndClose |
Tag的自闭结束符 ,即 /> |
TagClose |
Tag的结束标记 即</ad: 与<ad:对应,所以与TagEnd很容易区别 |
TagEquals |
Tag的=符号。与Tag无关的=属于TextData,非TagEquals |
ExpStart |
在AderTemplate中,语法#v#被定义为Expression.左#为ExpStart |
ExpEnd |
在AderTemplate中,语法#v#被定义为Expression.右#为ExpEnd |
LParent |
左括号 ( |
RParent |
右括号 ) |
Dot |
即一个点 . |
Comma |
逗号 , |
Integer |
数字 |
StringStart |
文本的开始符,即” |
StringEnd |
文本的结束符,即” |
StringText |
How to description ? |
为了获得更直观的认识。下面尝试把一个简单的模版文件分析的Token流输出。
模版文件,我们暂且命名为templateFile
<ad:foreach collection="#GetBookList(3)#" var="book" index="i">
<tr>
<td>#i#</td>
<td>#book.BookName#</td>
<td>#book.BookCount#</td>
</tr>
</ad:foreach>
分析的代码:
static void Main(string[] args)
{
string data = string.Empty;
using (System.IO.StreamReader reader = new System.IO.StreamReader(templateFile))
{
data = reader.ReadToEnd();
}
//模版分析,形成Token流
TemplateLexer lexer = new TemplateLexer(data);
Console.WriteLine("=======开始输出TemplateLexer分析出Token流=======");
do
{
Token token = lexer.Next();
Console.WriteLine("\tToken类型:{0}\t行列:({1}, {2})\t数据:{3}", token.TokenKind.ToString(), token.Line, token.Col
, token.Data.Replace("\r\n", ""));
if (token.TokenKind == TokenKind.EOF)
break;
} while (true);
Console.WriteLine("=======结束输出TemplateLexer分析出Token流=======\r\n");
}
输出结果:
对照表格的说明和输出结果。可以把Token理解为特定类型的”文本区’,即把模版文件按照TokenKind定义的类型分解成多个文本区(Token),所以分析模版文件形成的Token流(集合)是一种相对线性的结构。是对模版文件的初步分析与处理。
下面继续说说Element的类体系:
上述类关系图中可以看到Element主要有四个继承体系。
但每个类表达的意义是什么呢?
下面用一个表格做一个简单的说明。
类名 |
指代及其含义 |
Element |
各种Element的基类 |
Text |
文本类的Element , 与TokenKind为TextData的Token相似的概念 |
TagClose |
Tag结束符号 |
Tag |
Tag是一个比较广的概念。上述的模版可以表示一个foreach tag |
Expression |
AderTemplate把语法类似#values#定义为一个Expression |
FCall |
Expression子类之一,表示该Expression是一个外部函数(Function) |
FieldAccess |
Expression子类之一,可以近似的理解成”字段访问”,如#book.BookName# |
Name |
Expression子类之一,可以近似的理解成”外部变量”,如#i# |
StringLiteral |
Expression子类之一,可以近似的理解成”非数字型变量”。 |
IntLiteral |
Expression子类之一,可以近似的理解成”数字型变量”。 |
StringExpression |
Expression子类之一,但其表示的是Expression的集合封装类 |
为了获得更直观的了解。我们可以通过分析上述的模版文件输出的Element来理解。因为此部分代码比较多。所以不列出了。后面会提供包含本文提到的所有代码的example.
这里需要说明的是Tag Element,Tag是一个复合结构.Tag在不同的分析阶段,会些许不同。
如下面代码的(1)和(2)分析出的Element是不同的。可通过输出结果来跟踪异同。
TemplateLexer lexer = new TemplateLexer(templateData);
TemplateParser parser = new TemplateParser(lexer);
List<Element> elems = parser.Parse(); --(1)
TagParser tagParser = new TagParser(elems);
elems = tagParser.CreateHierarchy(); --(2)
Token与Element异同分析:
在上面已经提到,Token是对模版文件的一种初步分析和分解。AderTemplate对模版文件的分析处理目标是把模版文件表达为一个Template对象。而Template对象的本质其实就是Element集合的封装类,也就是AderTemplate的对模版文件的分析其实是希望把模版文件在程序结构层面表达为一个Element的集合,从上面的Element和Token类关系图可以看出。Element远比Token复杂的多。如果直接从模版文件直接分析成Element集合结构的话,可以预见分析过程会变的相当复杂。所以AderTemplate引入了Token数据结构作为一种辅助分析手段。使得AderTemplate的对模版文件的分析过程变得更流畅和清晰了。程序的架构也变得相对优雅。所以我认为阅读AderTemplate的源代码,关键是理解Token与Element的结构和作用。特别是Element结构。因为它是AderTemplate的基础结构。即解决了在程序层面用什么结构来表达模版文件的问题。
模版分析涉及到的处理类:
TemplateLexer : 从模版文件中分析成Token流。
TemplateParser: 基于Token流分析成初步的Element集合结构。
TagParser : 把TemplateParser分析出的Element集合做最后的优化处理。
Template(模版)对象:
在AderTemplate中。我们可以简单地认为一个Template就是经过模版分析后形成的最终的Element集合的封装体。
Template(模版)处理:
对Template的Element集合进行分析。生成目标文本。
此过程涉及到的技术其实不复杂,就是反射和委托,所以本文不打算详细分析此过程。否则篇幅过大。而且没什么意义。在后面我会提供一个模拟AderTemplate从Element分析处理到生成目标文本过程的例字。
相关例子
为了辅助理解AderTemplate的整个处理过程。我写了几个例子。
1,输出Token的结构信息。对比模版文件辅助理解Token的结构
2,输出从Token流中分析出的Element集合的结构信息。以辅助理解Element的结构。
3,模拟从Element集合中生成目标文本的过程。辅助理解从Element集合到生成目标文本的整个处理流程和过程。这个过程是相对简单的。从这个角度来看,AderTemplate用Element集合来表达模版文件是一个比较优秀的设计。
至于如何从模版文件分析成Element集合(Template对象)则是一个相对复杂的过程了。最好的解释还是源代码本身了。所以就不在此不做更多的分析了。
总结
AderTemplate是一个小型的模版引擎。功能并不算强大。但基本功能已经具备。从应用的角度来说,可能未必是一个最好的选择。但想学习模版引擎的开发。确是一个很不错的选择。我个人认为其架构还是比较优秀的。而且数据处理流程也很清晰。
AderTemplate的更多相关文章
随机推荐
- ZK框架笔记5、事件
事件是org.zkoss.zk.ui.event.Event类,它通知应用程序发生了什么事情.每一种类型的事件都由一个特定的类来表示. 要响应一个事件,应用程序必须为事 ...
- Struct2-使用随笔
提要:最近写了一个2-3各页面的使用Struts2的Demo,在这里做下总结,都已经3年多没做J2EE了,有些感觉都快找不到了. 目录 1.必备开发工具 2.必备jar包 3.了解知识点 4.遇到的问 ...
- git笔记之安装使用
git是什么? 简介一下,Git是一个开源的分布式版本号控制系统,用以有效.快速的处理从非常小到非常大的项目版本号管理.Git是眼下世界上最先进的分布式版本号控制系统,没有传说中的之中的一个. Git ...
- 让网页自动调用双核浏览器的极速模式(<meta name="renderer" content="webkit">)
背景:最近做了一个网站,传单服务器之后,每次打开都是乱码,不对啊,我在本地测得明明是排版很整齐啊,然后发现,360用的是“兼容模式”打开的,这就尴尬了,用户一打开就是乱码,这用户体验得有多差!用户可不 ...
- 折腾docker安装笔记
最近尝试把netcore迁移到docker,然后在本地虚拟机尝试装下 发现yum安装好复杂 于是记录下 1.7.2 centos的ios装虚拟机 2.修改网络 配置文件 查看网络地址 然后xshell ...
- jquery遍历总结(转)
遍历 DOM jQuery 提供了多种遍历 DOM 的方法. 遍历方法中最大的种类是树遍历(tree-traversal). 下一章会讲解如何在 DOM 树中向上.下以及同级移动. 向上遍历 DOM ...
- C#颜色 Color.FromArgb ColorTranslator 16进制
//方法1: //引用命名空间 using System.Drawing; 16进制颜色代码转Color类型:ColorTranslator.FromHtml(color); Color类型转16进制 ...
- Linux中history历史命令使用方法详解
当你在玩Linux的时候,如果你经常使用命令行来控制你的Linux系统,那么有效地使用命令历史机制将会使效率获得极大提升.事实上,一旦你掌 握了我在下面给出的15个有关Linux history历史命 ...
- 最全面的 Sublime Text 使用指南
最全面的 Sublime Text 使用指南 摘要(Abstract) 本文系统全面的介绍了Sublime Text,旨在成为最优秀的Sublime Text中文教程. 前言(Prologue) ...
- PHP进制转换[实现2、8、16、36、64进制至10进制相互转换]
自己写了一个PHP进制转换程序,一个类吧,第一次写这个东东,写这个东东,在处理文本文件时能用得到. 可以实现: 10进制转换2.8.16.36.62进制2.8.16.36.62进制转换10进制 有 ...