作为产品中的一大特色,模板机制一经推出,就引来了大家特别是站长们的关注。但它所饱受的风风
雨雨也成了那时不少人关注的话题。而今天本人将结合在产品组中的开发经历,介绍一下模板机制在设计
使用时的一些体会心得。希望借此陋文,使模板机制揭开“神秘”面纱,为大家在实际设计中提供一些有
价值的参考和建议。

好了,开始今天的话题:)

首先阐述一下模板设计的目标,因为这对于它最终要实现的功能非常重要。考虑到国内大部分站长基
本上都不具备.net开发背景,而我们的模板就是要降低这个门槛,便于站长进行设计订制以及修改等。而
另一个目的就是要提升aspx页面的访问速度,所以我们并未在模板设计时引入(web)控件机制,因为如果
使用.net控件,在windows的临时目录中会进行控件的订制生成(按用户设置的属性)。虽然在.net2.0
使用了fastobjectfactory的机制来提升页面生成的效率,比如使用batch批量编译选项 (web.config
文件中配置)生成的DLL(这里的DLL也是在临时目录下生成的随机命名的DLL文件,且重复编译的情况在所
难免)。但最终还是无法改变要生成服务器端控件的过程。

我们在设计模板本身所提供的语法时,尽可能逼近HTML的书写习惯,这样只要有HTML编写网页经验的
人就会很容易适应这种书写方式。当然有 asp开发经验的站长也能很快上手,因为模板的语法非常类似于
asp, 比如有<%if ...%>,<%else%>这样的写法等等。另外我们的模板语法也力求简练精悍,只需很少的
语法规则就直接支持生成内容丰富且形式多样的页面。说了这些,相信大家已经有兴趣来一看究竟了。不忙,
这里先要介绍一下如何使用模板机制来生成aspx页面。因为我有一位从事.net开发多年的朋友,在一次聊
天时他说,修改我们的前台页面时要手工修改"aspx/.../"下的相应的aspx文件,而当他看到 aspx文件中
的内容时大吃一惊,举个例子如下(aspx/1/logout.aspx):

.....命名空间和类的引用

1Discuz!NT 模板机制分析<scriptrunat="server">
2Discuz!NT 模板机制分析overrideprotectedvoidOnInit(EventArgse)
3Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
4Discuz!NT 模板机制分析
5Discuz!NT 模板机制分析base.OnInit(e);
6Discuz!NT 模板机制分析
7Discuz!NT 模板机制分析templateBuilder.Append("<!DOCTYPEhtmlPUBLIC/"-//W3C//DTDXHTML1.0Transitional//EN
8Discuz!NT 模板机制分析/"/"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd/">/r/n");
9Discuz!NT 模板机制分析templateBuilder.Append("<htmlxmlns=/"http://www.w3.org/1999/xhtml/">/r/n");
10Discuz!NT 模板机制分析templateBuilder.Append("<head>/r/n");
11Discuz!NT 模板机制分析templateBuilder.Append("<metahttp-equiv=/"Content-Type/"content=/"text/html;
12Discuz!NT 模板机制分析charset=utf-8/"/>/r/n");
13Discuz!NT 模板机制分析templateBuilder.Append(""+meta.ToString()+"/r/n");
14Discuz!NT 模板机制分析templateBuilder.Append("<title>"+pagetitle.ToString()+""+
15Discuz!NT 模板机制分析config.Seotitle.ToString().Trim()+"-"+
16Discuz!NT 模板机制分析config.Forumtitle.ToString().Trim()+"-PoweredbyDiscuz!NT
17Discuz!NT 模板机制分析</title>/r/n");
18Discuz!NT 模板机制分析templateBuilder.Append("<linkrel=/"icon/"href=/"favicon.ico/"
19Discuz!NT 模板机制分析type=/"image/x-icon/"/>/r/n");
20Discuz!NT 模板机制分析templateBuilder.Append("<linkrel=/"shortcuticon/"href=/"favicon.ico/"
21Discuz!NT 模板机制分析type=/"image/x-icon/"/>/r/n");
22Discuz!NT 模板机制分析templateBuilder.Append("<!--调用样式表-->/r/n");
23Discuz!NT 模板机制分析templateBuilder.Append("<linkrel=/"stylesheet/"href=/"templates/"+
24Discuz!NT 模板机制分析templatepath.ToString()+"/dnt.css/"
25Discuz!NT 模板机制分析type=/"text/css/"media=/"all/"/>/r/n");
26Discuz!NT 模板机制分析templateBuilder.Append(""+link.ToString()+"/r/n");
27Discuz!NT 模板机制分析templateBuilder.Append("<scripttype=/"text/javascript/"src=/"templates/"+
28Discuz!NT 模板机制分析templatepath.ToString()+"/report.js/"></"+"script>/r/n");
29Discuz!NT 模板机制分析templateBuilder.Append("<scripttype=/"text/javascript/"src=/"templates/"+
30Discuz!NT 模板机制分析templatepath.ToString()+"/common.js/"></"+"script>/r/n");
31Discuz!NT 模板机制分析templateBuilder.Append("<scripttype=/"text/javascript/"src=/"editor/common.js/">
32Discuz!NT 模板机制分析</"+"script>/r/n");
33Discuz!NT 模板机制分析templateBuilder.Append("<scripttype=/"text/javascript/"src=/"editor/menu.js/">
34Discuz!NT 模板机制分析</"+"script>/r/n");
35Discuz!NT 模板机制分析templateBuilder.Append(""+script.ToString()+"/r/n");
36Discuz!NT 模板机制分析templateBuilder.Append("</head>/r/n");
37Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析
38Discuz!NT 模板机制分析
39Discuz!NT 模板机制分析

相信大家看到这样的aspx页面都会晕上一阵子,直接修改的想法已变得非常不现实了,简直是“不
可能完成的任务”。而实际上,我们并不希望大家或站长来完成这项工作。因为这是系统自动生成的。
而生成的前提就是在template/下的模板“目录”中的HTM文件。还是借用上面的logout,只是这里要看
的是模板目录下同名的logout.htm模板文件。它的内容如下:

1Discuz!NT 模板机制分析<%template_header%>
2Discuz!NT 模板机制分析<divid="foruminfo">
3Discuz!NT 模板机制分析<divclass="userinfo">
4Discuz!NT 模板机制分析Discuz!NT 模板机制分析<h2><ahref="{config.forumurl}">Discuz!NT 模板机制分析{config.forumtitle}</a><strong>用户退出</strong></h2>
5Discuz!NT 模板机制分析</div>
6Discuz!NT 模板机制分析</div>
7Discuz!NT 模板机制分析<!--TheCurrentend-->
8Discuz!NT 模板机制分析<%template_msgbox%>
9Discuz!NT 模板机制分析</div>
10Discuz!NT 模板机制分析<%template_footer%>
11Discuz!NT 模板机制分析


大家可能会说,难道就是这几行就实现了上面aspx页面的内容吗?当然不是了,请大家注意:

1Discuz!NT 模板机制分析<%template_header%>
2Discuz!NT 模板机制分析

这一行,其实就是告诉模板页面生成器: 这是一个子模板。

因为我们在开始设计模板机制时就想到要简化模板代码并提升可重用性,因此要支持子模板机制。
这就类似于设计网页时的页首和页尾,我们在网页引用时,只需要include进来即可,而当修改页首和
页尾时,只须变动相应文件即可。

这里不妨再打开_header.htm(注意子模板名称要用下划线开头),发现内容如下:

1Discuz!NT 模板机制分析<%template_pageheader%>
2Discuz!NT 模板机制分析<body>
3Discuz!NT 模板机制分析<divid="append_parent"></div>
4Discuz!NT 模板机制分析<divid="container">
5Discuz!NT 模板机制分析<!--headerstart-->
6Discuz!NT 模板机制分析<divid="header">
7Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析.
8Discuz!NT 模板机制分析
9Discuz!NT 模板机制分析

有意思,又是一个“子模板”出现在了第一行。不错,我们的机制允许模板被嵌套使用,这样会
使页面的“组装”更加灵活多样。

即然都走到这一步,不妨再打开_pageheader子模板,正所谓“不撞南墙不回头”嘛:)

1Discuz!NT 模板机制分析<!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR
2Discuz!NT 模板机制分析/xhtml1/DTD/xhtml1-transitional.dtd">
3Discuz!NT 模板机制分析<htmlxmlns="http://www.w3.org/1999/xhtml">
4Discuz!NT 模板机制分析<head>
5Discuz!NT 模板机制分析<metahttp-equiv="Content-Type"content="text/html;charset=utf-8"/>
6Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{meta}
7Discuz!NT 模板机制分析Discuz!NT 模板机制分析<title>Discuz!NT 模板机制分析{pagetitle}Discuz!NT 模板机制分析{config.seotitle}-Discuz!NT 模板机制分析{config.forumtitle}-PoweredbyDiscuz!NT</title>
8Discuz!NT 模板机制分析<linkrel="icon"href="favicon.ico"type="image/x-icon"/>
9Discuz!NT 模板机制分析<linkrel="shortcuticon"href="favicon.ico"type="image/x-icon"/>
10Discuz!NT 模板机制分析<!--调用样式表-->
11Discuz!NT 模板机制分析<linkrel="stylesheet"href="templates/{templatepath}/dnt.css"type="text/css"media="all"/>
12Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{link}
13Discuz!NT 模板机制分析<scripttype="text/javascript"src="templates/{templatepath}/report.js"></script>
14Discuz!NT 模板机制分析<scripttype="text/javascript"src="templates/{templatepath}/common.js"></script>
15Discuz!NT 模板机制分析<scripttype="text/javascript"src="editor/common.js"></script>
16Discuz!NT 模板机制分析<scripttype="text/javascript"src="editor/menu.js"></script>
17Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{script}
18Discuz!NT 模板机制分析</head>
19Discuz!NT 模板机制分析
20Discuz!NT 模板机制分析

折腾了一圈,到这里出现了上面aspx页中的对应内容,有意思吧,不过里面的{pagetitle}和{
config.seotitle}以及{config.forumtitle}这样的东东又是什么呢? 其实非常简单,这就是按照模
板语法格式所书写的代码,因为这两处在模板生成之后会变成

1Discuz!NT 模板机制分析templateBuilder.Append("<title>"+pagetitle.ToString()+""+
2Discuz!NT 模板机制分析config.Seotitle.ToString().Trim()+"-"+
3Discuz!NT 模板机制分析config.Forumtitle.ToString().Trim()+"-PoweredbyDiscuz!NT
4Discuz!NT 模板机制分析</title>/r/n");

好了,到了这里我们应该清楚了,以后要修改前台页面的一个标准流程:

1.按模板语法修改相应的模板文件夹下的模板文件;
2.在后台生成或使用官方的模板生成器生成相应aspx页面即可;

其实流程非常简单,相信即使不懂aspx开发的朋友也会很快适应并上手。前提就是要了解模板语
法,除了上面所说的以外,还有一些常用的语法如下图:

Discuz!NT 模板机制分析
这里不妨引用官方文档中的链接,里面的说明会更清楚:)

相关链接如下:http://nt.discuz.net/download/doc/dnt_2_skindoc.zip

好了,目前我们只是知道了如使使用和修改它,但所谓的“模板生成”机制又是个什么样子呢!
必定到这里我们只走完了一半旅途,下面将会介绍模板的生成机制。


首先要看一下后台的模板(列表)管理界面,如下图:
Discuz!NT 模板机制分析

从上图可知道,模板是按名称(目录)来进行管理的,而每个模板都有名称,存放路径,版权,
作者等相关信息。而这此信息都是来自于每个模板(目录)下的about.xml文件,这里将它的内容贴
出来:

1Discuz!NT 模板机制分析<?xmlversion="1.0"encoding="utf-8"?>
2Discuz!NT 模板机制分析<about>
3Discuz!NT 模板机制分析<templatename="basic"
4Discuz!NT 模板机制分析author="Discuz!NT"
5Discuz!NT 模板机制分析createdate="2007-11-12"
6Discuz!NT 模板机制分析ver="1.1112"
7Discuz!NT 模板机制分析fordntver="2.0"
8Discuz!NT 模板机制分析copyright="Copyright2007ComsenzInc."/>
9Discuz!NT 模板机制分析</about>
10Discuz!NT 模板机制分析
11Discuz!NT 模板机制分析

注: 上图中的那个“乐队演出”图片其实是模板目录下的about.png文件,它相当于一张预览图。

需要说明的是上图中不是所有模板都能在前台使用,而是当被标记为“已入库”才可在前台使用,
而入库即数据库,下面就是数据库中的截图:

Discuz!NT 模板机制分析

而接下来要说的,就是模板列表中每个模板后面的“生成”链接所要干的活了。

如果大家手头上有reflector的话,请使用这个工具加载我们官方提供的产品目录下的bin文件夹
中的discuz.common.dll文件,找到 PageTemplate这个类。这里为了便于说明,将反射所得到的代码
加上注释贴出来:

Discuz!NT 模板机制分析Discuz!NT 模板机制分析Code
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->1Discuz!NT 模板机制分析publicabstractclassPageTemplate
2Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
3Discuz!NT 模板机制分析publicstaticRegex[]r=newRegex[21];
4Discuz!NT 模板机制分析
5Discuz!NT 模板机制分析staticPageTemplate()
6Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
7Discuz!NT 模板机制分析
8Discuz!NT 模板机制分析RegexOptionsoptions=Utils.GetRegexCompiledOptions();
9Discuz!NT 模板机制分析
10Discuz!NT 模板机制分析r[0]=newRegex(@"<%template([^/[/]/{/}/s]+)%>",options);
11Discuz!NT 模板机制分析
12Discuz!NT 模板机制分析r[1]=newRegex(@"<%loop((/(([a-zA-Z]+)/))?)([^/[/]/{/}/s]+)([^/[/]/{/}/s]+)%>",options);
13Discuz!NT 模板机制分析
14Discuz!NT 模板机制分析r[2]=newRegex(@"<%//loop%>",options);
15Discuz!NT 模板机制分析
16Discuz!NT 模板机制分析r[3]=newRegex(@"<%while([^/[/]/{/}/s]+)%>",options);
17Discuz!NT 模板机制分析
18Discuz!NT 模板机制分析r[4]=newRegex(@"<%//while([^/[/]/{/}/s]+)%>",options);
19Discuz!NT 模板机制分析
20Discuz!NT 模板机制分析r[5]=newRegex(@"<%if(?:/s*)(([^/s]+)((?:/s*)(/|/||/&/&)(?:/s*)([^/s]+))?)(?:/s*)%>",options);
21Discuz!NT 模板机制分析
22Discuz!NT 模板机制分析r[6]=newRegex(@"<%else(((?:/s*)if(?:/s*)(([^/s]+)((?:/s*)(/|/||/&/&)(?:/s*)([^/s]+))?))?)(?:/s*)%>",options);
23Discuz!NT 模板机制分析
24Discuz!NT 模板机制分析r[7]=newRegex(@"<%//if%>",options);
25Discuz!NT 模板机制分析
26Discuz!NT 模板机制分析//解析{var.a}
27Discuz!NT 模板机制分析r[8]=newRegex(@"(/{strtoint/(([^/s]+?)/)/})",options);
28Discuz!NT 模板机制分析
29Discuz!NT 模板机制分析//解析{request[a]}
30Discuz!NT 模板机制分析r[9]=newRegex(@"(<%urlencode/(([^/s]+?)/)%>)",options);
31Discuz!NT 模板机制分析
32Discuz!NT 模板机制分析//解析{var[a]}
33Discuz!NT 模板机制分析r[10]=newRegex(@"(<%datetostr/(([^/s]+?),(.*?)/)%>)",options);
34Discuz!NT 模板机制分析r[11]=newRegex(@"(/{([^/./[/]/{/}/s]+)/.([^/[/]/{/}/s]+)/})",options);
35Discuz!NT 模板机制分析
36Discuz!NT 模板机制分析//解析普通变量{}
37Discuz!NT 模板机制分析r[12]=newRegex(@"(/{request/[([^/[/]/{/}/s]+)/]/})",options);
38Discuz!NT 模板机制分析
39Discuz!NT 模板机制分析//解析==表达式
40Discuz!NT 模板机制分析r[13]=newRegex(@"(/{([^/[/]/{/}/s]+)/[([^/[/]/{/}/s]+)/]/})",options);
41Discuz!NT 模板机制分析
42Discuz!NT 模板机制分析//解析==表达式
43Discuz!NT 模板机制分析r[14]=newRegex(@"({([^/[/]//{/}='/s]+)})",options);
44Discuz!NT 模板机制分析
45Discuz!NT 模板机制分析//解析普通变量{}
46Discuz!NT 模板机制分析r[15]=newRegex(@"({([^/[/]//{/}='/s]+)})",options);
47Discuz!NT 模板机制分析
48Discuz!NT 模板机制分析//解析==表达式
49Discuz!NT 模板机制分析r[16]=newRegex(@"(([=|>|<|!]=)//"+"/""[email protected]"([^/s]*)//"+"/")",options);
50Discuz!NT 模板机制分析
51Discuz!NT 模板机制分析//命名空间
52Discuz!NT 模板机制分析r[17]=newRegex(@"<%namespace([^/[/]/{/}/s]+)%>",options);
53Discuz!NT 模板机制分析
54Discuz!NT 模板机制分析//C#代码
55Discuz!NT 模板机制分析r[18]=newRegex(@"<%csharp%>([/s/S]+?)<%/csharp%>",options);
56Discuz!NT 模板机制分析
57Discuz!NT 模板机制分析//set标签
58Discuz!NT 模板机制分析r[19]=newRegex(@"<%set((/(([a-zA-Z]+)/))?)(?:/s*)/{([^/s]+)/}(?:/s*)=(?:/s*)(.*?)(?:/s*)%>",options);
59Discuz!NT 模板机制分析
60Discuz!NT 模板机制分析r[20]=newRegex(@"(<%getsubstring/(([^/s]+?),(./d*?),(./d*?),([^/s]+?)/)%>)",options);
61Discuz!NT 模板机制分析}

62Discuz!NT 模板机制分析
63Discuz!NT 模板机制分析
64Discuz!NT 模板机制分析Discuz!NT 模板机制分析/**////<summary>
65Discuz!NT 模板机制分析///获得模板字符串.首先查找缓存.如果不在缓存中则从设置中的模板路径来读取模板文件.
66Discuz!NT 模板机制分析///模板文件的路径在Web.config文件中设置.
67Discuz!NT 模板机制分析///如果读取文件成功则会将内容放于缓存中.
68Discuz!NT 模板机制分析///</summary>
69Discuz!NT 模板机制分析///<paramname="skinName">模板名</param>
70Discuz!NT 模板机制分析///<paramname="templateName">模板文件的文件名称,也是缓存中的模板名称.</param>
71Discuz!NT 模板机制分析///<paramname="nest">嵌套次数</param>
72Discuz!NT 模板机制分析///<paramname="templateid">模板id</param>
73Discuz!NT 模板机制分析///<returns>string值,如果失败则为"",成功则为模板内容的string</returns>

74Discuz!NT 模板机制分析publicvirtualstringGetTemplate(stringforumpath,stringskinName,stringtemplateName,intnest,inttemplateid)
75Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
76Discuz!NT 模板机制分析StringBuilderstrReturn=newStringBuilder();
77Discuz!NT 模板机制分析if(nest<1)
78Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
79Discuz!NT 模板机制分析nest=1;
80Discuz!NT 模板机制分析}

81Discuz!NT 模板机制分析elseif(nest>5)
82Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
83Discuz!NT 模板机制分析return"";
84Discuz!NT 模板机制分析}

85Discuz!NT 模板机制分析
86Discuz!NT 模板机制分析
87Discuz!NT 模板机制分析stringextNamespace="";
88Discuz!NT 模板机制分析stringpathFormatStr="{0}{1}{2}{3}{4}.htm";
89Discuz!NT 模板机制分析stringfilePath=string.Format(pathFormatStr,Utils.GetMapPath(forumpath+"templates"),System.IO.Path.DirectorySeparatorChar,skinName,System.IO.Path.DirectorySeparatorChar,templateName);
90Discuz!NT 模板机制分析
91Discuz!NT 模板机制分析//如果指定风格的模板文件不存在Discuz!NT 模板机制分析
92Discuz!NT 模板机制分析if(!System.IO.File.Exists(filePath))
93Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
94Discuz!NT 模板机制分析//默认风格的模板是否存在Discuz!NT 模板机制分析
95Discuz!NT 模板机制分析filePath=string.Format(pathFormatStr,Utils.GetMapPath(forumpath+"templates"),System.IO.Path.DirectorySeparatorChar,"default",System.IO.Path.DirectorySeparatorChar,templateName);
96Discuz!NT 模板机制分析if(!System.IO.File.Exists(filePath))
97Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
98Discuz!NT 模板机制分析return"";
99Discuz!NT 模板机制分析}

100Discuz!NT 模板机制分析}

101Discuz!NT 模板机制分析using(System.IO.StreamReaderobjReader=newSystem.IO.StreamReader(filePath,Encoding.UTF8))
102Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
103Discuz!NT 模板机制分析System.Text.StringBuildertextOutput=newSystem.Text.StringBuilder();
104Discuz!NT 模板机制分析
105Discuz!NT 模板机制分析textOutput.Append(objReader.ReadToEnd());
106Discuz!NT 模板机制分析objReader.Close();
107Discuz!NT 模板机制分析
108Discuz!NT 模板机制分析//处理命名空间
109Discuz!NT 模板机制分析if(nest==1)
110Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
111Discuz!NT 模板机制分析//命名空间
112Discuz!NT 模板机制分析foreach(Matchminr[17].Matches(textOutput.ToString()))
113Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
114Discuz!NT 模板机制分析extNamespace+="/r/n<%@Importnamespace=/""+m.Groups[1].ToString()+"/"%>";
115Discuz!NT 模板机制分析textOutput.Replace(m.Groups[0].ToString(),string.Empty);
116Discuz!NT 模板机制分析}

117Discuz!NT 模板机制分析
118Discuz!NT 模板机制分析}

119Discuz!NT 模板机制分析//处理Csharp语句
120Discuz!NT 模板机制分析foreach(Matchminr[18].Matches(textOutput.ToString()))
121Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
122Discuz!NT 模板机制分析//csharpCode+="/r/n"+m.Groups[1].ToString()+"/r/n";
123Discuz!NT 模板机制分析textOutput.Replace(m.Groups[0].ToString(),m.Groups[0].ToString().Replace("/r/n","/r/t/r"));
124Discuz!NT 模板机制分析}

125Discuz!NT 模板机制分析
126Discuz!NT 模板机制分析textOutput.Replace("/r/n","/r/r/r");
127Discuz!NT 模板机制分析textOutput.Replace("<%","/r/r/n<%");
128Discuz!NT 模板机制分析textOutput.Replace("%>","%>/r/r/n");
129Discuz!NT 模板机制分析
130Discuz!NT 模板机制分析textOutput.Replace("<%csharp%>/r/r/n","<%csharp%>").Replace("/r/r/n<%/csharp%>","<%/csharp%>");
131Discuz!NT 模板机制分析
132Discuz!NT 模板机制分析
133Discuz!NT 模板机制分析string[]strlist=Utils.SplitString(textOutput.ToString(),"/r/r/n");
134Discuz!NT 模板机制分析intcount=strlist.GetUpperBound(0);
135Discuz!NT 模板机制分析
136Discuz!NT 模板机制分析for(inti=0;i<=count;i++)
137Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
138Discuz!NT 模板机制分析strReturn.Append(ConvertTags(nest,forumpath,skinName,strlist[i],templateid));
139Discuz!NT 模板机制分析}

140Discuz!NT 模板机制分析}

141Discuz!NT 模板机制分析if(nest==1)
142Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
143Discuz!NT 模板机制分析Discuz!NT 模板机制分析stringtemplate=string.Format("<%@Pagelanguage=/"c#/"Codebehind=/"Discuz!NT 模板机制分析{0}.aspx.cs/"AutoEventWireup=/"false/"EnableViewState=/"false/"Inherits=/"Discuz.ForumPage.Discuz!NT 模板机制分析{0}/"%>/r/n<%@Importnamespace=/"System.Data/"%>/r/n<%@Importnamespace=/"Discuz.Common/"%>/r/n<%@Importnamespace=/"Discuz.Forum/"%>/r/n<%@Importnamespace=/"Discuz.Entity/"%>/r/n{1}/r/n<scriptrunat=/"server/">/r/noverrideprotectedvoidOnInit(EventArgse)/r/n{{/r/n/r/n/t/*/r/n/t/tThispagewascreatedbyDiscuz!NTTemplateEngineat{2}./r/n/t/t本页面代码由Discuz!NT模板引擎生成于{2}./r/n/t*//r/n/r/n/tbase.OnInit(e);/r/n{3}/r/n/tResponse.Write(templateBuilder.ToString());/r/n}}/r/n</script>/r/n",templateName,extNamespace,DateTime.Now.ToString(),strReturn.ToString());
144Discuz!NT 模板机制分析
145Discuz!NT 模板机制分析stringpageDir=Utils.GetMapPath(forumpath+"aspx//"+templateid.ToString()+"//");
146Discuz!NT 模板机制分析if(!Directory.Exists(pageDir))
147Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
148Discuz!NT 模板机制分析Utils.CreateDir(pageDir);
149Discuz!NT 模板机制分析}

150Discuz!NT 模板机制分析
151Discuz!NT 模板机制分析stringoutputPath=pageDir+templateName+".aspx";
152Discuz!NT 模板机制分析
153Discuz!NT 模板机制分析
154Discuz!NT 模板机制分析
155Discuz!NT 模板机制分析using(FileStreamfs=newFileStream(outputPath,FileMode.Create,FileAccess.ReadWrite,FileShare.ReadWrite))
156Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
157Discuz!NT 模板机制分析Byte[]info=System.Text.Encoding.UTF8.GetBytes(template);
158Discuz!NT 模板机制分析fs.Write(info,0,info.Length);
159Discuz!NT 模板机制分析fs.Close();
160Discuz!NT 模板机制分析}

161Discuz!NT 模板机制分析
162Discuz!NT 模板机制分析}

163Discuz!NT 模板机制分析returnstrReturn.ToString();
164Discuz!NT 模板机制分析}

165Discuz!NT 模板机制分析
166Discuz!NT 模板机制分析Discuz!NT 模板机制分析/**////<summary>
167Discuz!NT 模板机制分析///转换标签
168Discuz!NT 模板机制分析///</summary>
169Discuz!NT 模板机制分析///<paramname="nest">深度</param>
170Discuz!NT 模板机制分析///<paramname="skinName">模板名称</param>
171Discuz!NT 模板机制分析///<paramname="inputStr">模板内容</param>
172Discuz!NT 模板机制分析///<paramname="templateid">模板id</param>
173Discuz!NT 模板机制分析///<returns></returns>

174Discuz!NT 模板机制分析privatestringConvertTags(intnest,stringforumpath,stringskinName,stringinputStr,inttemplateid)
175Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
176Discuz!NT 模板机制分析stringstrReturn="";
177Discuz!NT 模板机制分析boolIsCodeLine;
178Discuz!NT 模板机制分析stringstrTemplate;
179Discuz!NT 模板机制分析strTemplate=inputStr.Replace("//","////");
180Discuz!NT 模板机制分析strTemplate=strTemplate.Replace("/"","///"");
181Discuz!NT 模板机制分析strTemplate=strTemplate.Replace("</script>","<//"+/"script>");
182Discuz!NT 模板机制分析IsCodeLine=false;
183Discuz!NT 模板机制分析
184Discuz!NT 模板机制分析
185Discuz!NT 模板机制分析foreach(Matchminr[0].Matches(strTemplate))
186Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
187Discuz!NT 模板机制分析IsCodeLine=true;
188Discuz!NT 模板机制分析strTemplate=strTemplate.Replace(m.Groups[0].ToString(),"/r/n"+GetTemplate(forumpath,skinName,m.Groups[1].ToString(),nest+1,templateid)+"/r/n");
189Discuz!NT 模板机制分析}

190Discuz!NT 模板机制分析
191Discuz!NT 模板机制分析foreach(Matchminr[1].Matches(strTemplate))
192Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
193Discuz!NT 模板机制分析IsCodeLine=true;
194Discuz!NT 模板机制分析if(m.Groups[3].ToString()=="")
195Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
196Discuz!NT 模板机制分析strTemplate=strTemplate.Replace(m.Groups[0].ToString(),
197Discuz!NT 模板机制分析string.Format("/r/n/tint{0}__loop__id=0;/r/n/tforeach(DataRow{0}in{1}.Rows)/r/n/t{{/r/n/t/t{0}__loop__id++;/r/n",m.Groups[4].ToString(),m.Groups[5].ToString()));
198Discuz!NT 模板机制分析}

199Discuz!NT 模板机制分析else
200Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
201Discuz!NT 模板机制分析strTemplate=strTemplate.Replace(m.Groups[0].ToString(),
202Discuz!NT 模板机制分析string.Format("/r/n/tint{1}__loop__id=0;/r/n/tforeach({0}{1}in{2})/r/n/t{{/r/n/t/t{1}__loop__id++;/r/n",m.Groups[3].ToString(),m.Groups[4].ToString(),m.Groups[5].ToString()));
203Discuz!NT 模板机制分析}

204Discuz!NT 模板机制分析}

205Discuz!NT 模板机制分析
206Discuz!NT 模板机制分析
207Discuz!NT 模板机制分析
208Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析
209Discuz!NT 模板机制分析
210Discuz!NT 模板机制分析
211Discuz!NT 模板机制分析if(IsCodeLine)
212Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
213Discuz!NT 模板机制分析strReturn=strTemplate+"/r/n";
214Discuz!NT 模板机制分析}

215Discuz!NT 模板机制分析else
216Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
217Discuz!NT 模板机制分析if(strTemplate.Trim()!="")
218Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
219Discuz!NT 模板机制分析StringBuildersb=newStringBuilder();
220Discuz!NT 模板机制分析foreach(stringtempinUtils.SplitString(strTemplate,"/r/r/r"))
221Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
222Discuz!NT 模板机制分析if(temp.Trim()=="")
223Discuz!NT 模板机制分析continue;
224Discuz!NT 模板机制分析sb.Append("/ttemplateBuilder.Append(/""+temp+"//r//n/");/r/n");
225Discuz!NT 模板机制分析}

226Discuz!NT 模板机制分析strReturn=sb.ToString();
227Discuz!NT 模板机制分析}

228Discuz!NT 模板机制分析}

229Discuz!NT 模板机制分析returnstrReturn;
230Discuz!NT 模板机制分析}

231Discuz!NT 模板机制分析
232Discuz!NT 模板机制分析
233Discuz!NT 模板机制分析
234Discuz!NT 模板机制分析Discuz!NT 模板机制分析/**////<summary>
235Discuz!NT 模板机制分析///解析特殊变量
236Discuz!NT 模板机制分析///</summary>
237Discuz!NT 模板机制分析///<returns></returns>

238Discuz!NT 模板机制分析publicabstractstringReplaceSpecialTemplate(stringforumpath,stringskinName,stringstrTemplate);
239Discuz!NT 模板机制分析}

240Discuz!NT 模板机制分析
241Discuz!NT 模板机制分析


基本上都是对正则式的使用,因为本人不是这方面的高手,所以就不多说了,相信开源之后大家拿
源码和注释一看便知:)

这里需要说明的就是ReplaceSpecialTemplate(string forumpath,string skinName,....) 这个函
数,它的实现我们要到discuz.forum.dll中去找,这里为了方便,直接就将反射出来的代码加上注释贴
出来,大家一看便知:

1Discuz!NT 模板机制分析publicclassForumPageTemplate:PageTemplate
2Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
3Discuz!NT 模板机制分析
4Discuz!NT 模板机制分析Discuz!NT 模板机制分析/**////<summary>
5Discuz!NT 模板机制分析///解析特殊变量
6Discuz!NT 模板机制分析///</summary>
7Discuz!NT 模板机制分析///<paramname="skinName">皮肤名</param>
8Discuz!NT 模板机制分析///<paramname="strTemplate">模板内容</param>
9Discuz!NT 模板机制分析///<returns></returns>

10Discuz!NT 模板机制分析publicoverridestringReplaceSpecialTemplate(stringforumpath,stringskinName,stringstrTemplate)
11Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
12Discuz!NT 模板机制分析Regexr;
13Discuz!NT 模板机制分析Matchm;
14Discuz!NT 模板机制分析
15Discuz!NT 模板机制分析StringBuildersb=newStringBuilder();
16Discuz!NT 模板机制分析sb.Append(strTemplate);
17Discuz!NT 模板机制分析r=newRegex(@"({([^/[/]//{/}='/s]+)})",RegexOptions.IgnoreCase|RegexOptions.Multiline|RegexOptions.Compiled);
18Discuz!NT 模板机制分析for(m=r.Match(strTemplate);m.Success;m=m.NextMatch())
19Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
20Discuz!NT 模板机制分析if(m.Groups[0].ToString()=="{forumversion}")
21Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
22Discuz!NT 模板机制分析sb=sb.Replace(m.Groups[0].ToString(),Utils.GetAssemblyVersion());
23Discuz!NT 模板机制分析}

24Discuz!NT 模板机制分析elseif(m.Groups[0].ToString()=="{forumproductname}")
25Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
26Discuz!NT 模板机制分析sb=sb.Replace(m.Groups[0].ToString(),Utils.GetAssemblyProductName());
27Discuz!NT 模板机制分析}

28Discuz!NT 模板机制分析}

29Discuz!NT 模板机制分析
30Discuz!NT 模板机制分析foreach(DataRowdrinGetTemplateVarList(forumpath,skinName).Rows)
31Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
32Discuz!NT 模板机制分析sb=sb.Replace(dr["variablename"].ToString().Trim(),dr["variablevalue"].ToString().Trim());
33Discuz!NT 模板机制分析}

34Discuz!NT 模板机制分析returnsb.ToString();
35Discuz!NT 模板机制分析}

36Discuz!NT 模板机制分析
37Discuz!NT 模板机制分析
38Discuz!NT 模板机制分析Discuz!NT 模板机制分析/**////<summary>
39Discuz!NT 模板机制分析///获取模板内容
40Discuz!NT 模板机制分析///</summary>
41Discuz!NT 模板机制分析///<paramname="skinName">皮肤名</param>
42Discuz!NT 模板机制分析///<paramname="templateName">模板名</param>
43Discuz!NT 模板机制分析///<paramname="nest">嵌套次数</param>
44Discuz!NT 模板机制分析///<paramname="templateid">皮肤id</param>
45Discuz!NT 模板机制分析///<returns></returns>

46Discuz!NT 模板机制分析publicoverridestringGetTemplate(stringforumpath,stringskinName,stringtemplateName,intnest,inttemplateid)
47Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
48Discuz!NT 模板机制分析returnbase.GetTemplate(forumpath,skinName,templateName,nest,templateid);
49Discuz!NT 模板机制分析}

50Discuz!NT 模板机制分析
51Discuz!NT 模板机制分析Discuz!NT 模板机制分析/**////<summary>
52Discuz!NT 模板机制分析///获得模板变量列表
53Discuz!NT 模板机制分析///</summary>
54Discuz!NT 模板机制分析///<paramname="skinName">皮肤名</param>
55Discuz!NT 模板机制分析///<returns></returns>

56Discuz!NT 模板机制分析publicstaticDataTableGetTemplateVarList(stringforumpath,stringskinName)
57Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
58Discuz!NT 模板机制分析Discuz.Cache.DNTCachecache=Discuz.Cache.DNTCache.GetCacheService();
59Discuz!NT 模板机制分析DataTabledt=cache.RetrieveSingleObject("/Forum/"+skinName+"/TemplateVariable")asDataTable;
60Discuz!NT 模板机制分析
61Discuz!NT 模板机制分析if(dt!=null)
62Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
63Discuz!NT 模板机制分析returndt;
64Discuz!NT 模板机制分析}

65Discuz!NT 模板机制分析else
66Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
67Discuz!NT 模板机制分析DataSetdsSrc=newDataSet("template");
68Discuz!NT 模板机制分析Discuz!NT 模板机制分析string[]filename=newstring[1]Discuz!NT 模板机制分析{Utils.GetMapPath(forumpath+"templates/"+skinName+"/templatevariable.xml")};
69Discuz!NT 模板机制分析
70Discuz!NT 模板机制分析if(Utils.FileExists(filename[0]))
71Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
72Discuz!NT 模板机制分析dsSrc.ReadXml(filename[0]);
73Discuz!NT 模板机制分析
74Discuz!NT 模板机制分析if(dsSrc.Tables.Count==0)
75Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
76Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析
77Discuz!NT 模板机制分析}

78Discuz!NT 模板机制分析}

79Discuz!NT 模板机制分析else
80Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析{
81Discuz!NT 模板机制分析Discuz!NT 模板机制分析Discuz!NT 模板机制分析
82Discuz!NT 模板机制分析}

83Discuz!NT 模板机制分析
84Discuz!NT 模板机制分析cache.AddSingleObject("/Forum/"+skinName+"/TemplateVariable",dsSrc.Tables[0],filename);
85Discuz!NT 模板机制分析returndsSrc.Tables[0];
86Discuz!NT 模板机制分析}

87Discuz!NT 模板机制分析}

88Discuz!NT 模板机制分析}

89Discuz!NT 模板机制分析
90Discuz!NT 模板机制分析


相信看到这里,熟悉设计模式的朋友会看出来,这里用到了"Template Method"模式,因为这
种模式很简单,就不多做介绍了,相关信息可以看一下GOF的那本书或到网上一搜便知。

下面要说的就是上面的这个 ForumPageTemplate类目前所要实现的功能。因为模板中要被订制
的东西有很多,而我们目前所搭建的功能只是为了生成和转换时使用,当用户有要替换的特殊变量
就会出现无法订制的情况。所以才提供了这个类以便实现与模板有关的用户订制需求。当然目录所
提供的功能只是简单的替换而已,但并不排除以后随着用户口味的挑剔而进行升级扩展的可能。

而用户进行特殊变量定制也非常简单,只要在上面所贴的后台“模板列表”图中的后面点击相
应的“管理”链接之后就会看到下面的页面,如图:

Discuz!NT 模板机制分析

只要再点击右下方的“模板变量列表”,即可以进入定制模板变量的页面,如图:

Discuz!NT 模板机制分析
大家只要进行相应操作设置即可。


好了,关于模板机制的介绍,这里就先告一段落了。有问题的朋友可以在回复中进行交流和发
EMAIL给我([email protected],[email protected],[email protected])。

相关文章: