请选择 进入手机版 | 继续访问电脑版

 找回密码
 注册

只需一步,快速开始

蓝色理想 最新研发动态 新增登录提醒插件 - 用至我的站点 地图任务一定要做 - 给官方提建议

论坛活动及任务 地图和邮件任务 请多用悬赏提问 热夏来袭,选一款蓝色理想的个性T恤吧!

MIUI手机主题设计大赛,奔驰大奖等你拿! 急需前端攻城狮,获得内部推荐机会 悬赏答疑,赚取积分兑奖品!

查看: 3412|回复: 22

[.net] 模版的微处理 [复制链接]

hubro 楼主

Hi 阿洛瓦

钻石会员

帖子
4323
体力
9030
威望
3
发表于 2007-5-24 14:26:47 |显示全部楼层
引言

在传统的模版处理里,都是一些简单的替换,定义好一个标签$title$,然后把这个换成动态的内容,小到一个字符串,大到一个列表
问题来了,如果是列表,这个列表是要我们用程序来循环的,也就是说,这个列表在你的模版里是改不了的,有更好的办法?
定义这个循环?在我见过的一些内容处理中,就算这些是能被定义的,但也是写死的,意味着,这个循环只能单独对这个模块有用,其它的得另写了
没有更好的办法?
我们需要自定义的循环的列表模版
要让模版列表有循环功能,只能手动来处理了,可以根据特定的标识,得到哪部份要循环
简单结构如下
  1. loop
  2. //something
  3. end loop
复制代码

可以把它定义为这样,temp:loop只是随便起的名字
  1.   <!--temp:loop-->
  2.   //要循环的内容
  3.   <!--temp:loop-->
复制代码


对于这样的循环,怎么和数据源关联上,怎么循环
给它加一个ID
  1.   <!--temp:loop id=news-->
  2.   //要循环的内容
  3.   <!--temp:loop-->
复制代码

取出模版里这个循环用正则可以很方便办到
得到这段代码,再匹配到这个循环的id是news和中间循环的内容
我们根据news值生成数据源,遍历每一行
  1. for(...)
  2. {
  3. //生成要循环的内容
  4. }
复制代码

这样完成了一个循环模版的处理过程,news是一个参数,当然可以定义其它的参数,可以先把它存好,再调用对应的
自定义的数据源
在上面知道这个循环的id是news,我们定义一个为对应为news的数据源,数据源多针对的数据库,也就是SQL语句的不同
不同的SQL语句得到不同的数据源,还有哪些参数,该显示哪些字段
对于这些参数,可以先存起来,如果有一个循环的id是news,则找到这些参数,生成DATATABLE,供循环使用,这样数据源和循环就分离了
字段显示
得到数据源和要循环的内容,剩下的就是把要循环的内容里的特殊标记替换成相应的字段值就行了
字段,可以直接替换,如果有个标记是{--field--}
替换为
  1. //DataRow dr....
  2. str=str.Replace("{--field--}",dr["field"].ToString());
复制代码

在上面数据源的参数里,对字段作了限制,如只能使用哪些字段,在这也可以体现,只替换存在的字段
综合上面,这个循环可以循环为
  1. <table width="200" border="1">
  2.   <tr>
  3.     <td>id</td>
  4.     <td>title</td>
  5.   </tr>
  6. <!--temp:loop  id="news"-->
  7.   <tr>
  8.     <td>{--id--}</td>
  9.     <td>{--title--}</td>
  10.   </tr>
  11.   <!--temp:loop-->
  12. </table>
复制代码

综上,一个简单的自定义循环完成了,当然还有很多细节
对列表进行分页和接收参数
上面实现了简单的列表,大多时候,是要对列表进行分页
我们增加对应的分页标签
为了使分页标签能随意放,不能循环标签直接关联,不放在里面,放在外面,增加一个特殊标记
{--temp:page for=news--}
for=news,用这来指定对应的循环
在为news的数据源,定义时,增加一个属性,是否分页
在处理循环时,如果当前循环对的是news,如果它的分页属性是true,根据当前的数据,索引页(REQUEST)生成分页
因为分页标签的位置可能不和循环在一起如下面所示
  1. <table width="200" border="1">
  2.   <tr>
  3.     <td>id</td>
  4.     <td>title</td>
  5.   </tr>
  6. <!--temp:loop  id="news"-->
  7.   <tr>
  8.     <td>{--id--}</td>
  9.     <td>{--title--}</td>
  10.   </tr>
  11.   <!--temp:loop-->
  12. </table>
  13. <div>{--temp:page for=news--}</div>
复制代码

它在外面,我们处理标签时得到的代码也只是循环标签之间的(包函标签),所以不能直接替换,可以这样做
在循环标签后面加上一段代码,记录这个循环的分页信息,过后再处理分页,处理后如下
  1. <table width="200" border="1">
  2.   <tr>
  3.     <td>id</td>
  4.     <td>title</td>
  5.   </tr>
  6. <!--这个循环标签已处理这,应该是具体的HTML代码-->
  7. <!--temp:loop  id="news"-->
  8.   <tr>
  9.     <td>{--id--}</td>
  10.     <td>{--title--}</td>
  11.   </tr>
  12.   <!--temp:loop-->
  13. {--temp:page for=news count=30 page=2 pagesize=10--}
  14. </table>
  15. <div>{--temp:page for=news--}</div>
复制代码

这样,处理完循环,留下了分页的信息,再来处理对应的分页标签
先找{--temp:page for=news--}这样的标记,匹配出它的for值
再找{--temp:page for=news count=30 page=2 pagesize=10--}这样的标记,匹配出它的for值
如果两值相等,那它们就是属于同一个循环的了,把{--temp:page for=news--}标记按{--temp:page for=news count=30 page=2 pagesize=10--}里的参数生成分页
参数用正则匹配出来,这样就完成了分页位置的转换,完成分页
如何传递参数
常用的参数传递都是Request,服务器内部的就不必考虑了,太复杂
我们按Request
在上面数据源设置中,提到了设置参数,字段等,可以在这里设置传递的参数
可以按存储过程的方式来处理
如果要得到的最终SQL语句是
  1. select * from news where class=10
复制代码

我们处理成这样
  1. select * from news where class=@class
复制代码

剩下的就是解析这个@class了
可以看作这个参数key是@class,value要我们来定义
value是传递过来的,但是由哪个key传递过来的
再定个规则
  1. @class=class
复制代码

意思是说@class是由class这个参数传递过来
投入使用
遍历定义的参数则
  1. for(分割参数规则数组,循环)
  2. {
  3. 取出对应的key,value
  4. 生成的SQL语句为:select * from news where class=Request[value]
  5. }
复制代码

完成参数传递
字段处理
对于字段显示,不仅仅是停留在直接输出上就行了,比如对于标题,不想让它以HTML显示,或要截断到前几个字符
怎样在匹配字段时,把这些要执行的操作也加上去
可以这样写
  1. {--title[UNHTML]--}
  2. {--title[CUT_STRING,30]--}
复制代码

在方括号里定义要处理的方法,逗号分割所需的参数,取得括号里的参数,再进行枚举处理
甚至可以一回处理多个
  1. {--title[UNHTML&CUT_STRING,30]--}
复制代码

用&号隔开,处理时分割它,再循环
于是做了这些规则

[--字段[type]--]
UBB,处理为UBB
UNHTML,处理为UNHTML
C_STRING,截断长度的字符串如"C_STRING,20"
取前20个字符
C_CONTENT,截行,如"C_CONTENT,5"
取前5行
TIME,格式化时间,系统写法,如"TIME,yyyy-MM"
URLENCODE,进行URL编码
URLDECODE,进行URL解码
SPLIT,分割字符,如:SPLIT,"\,","<a href=$1>$1</a>"
把此字符按","号分割,并循环,如果是","号,要写成"\,"
一般字符处理,差不多了
对大容量字符,更高效替换
一般进行替换操作都这样
  1. str=str.replace(字符串一,字符串二)
复制代码

不难发现一个问题,如果str要循环替换很多次,下一次替换时会累加上上次替换的内容,并且全遍历一次,如果字符串二很多,替换的过程就像阶梯效果,越来越大,所以速度越来越慢
要解决这个问题只能找另外的方法替换这种表达方式
如何以更高效率代替这种操作
思路如下,每次替换完后,在下次替换时先排除这次替换的内容,累加本次替换的内容
算法如下
  1.             Regex r;
  2.             Match m;
  3.             string sDetail=Textbox1.Text;
  4.             //sDetail=sDetail.Replace(" ","#");
  5.             r = new Regex(@"(<.+?>)",RegexOptions.IgnoreCase);
  6.             int last_i=0;
  7.             string str2=sDetail;
  8.             string str1="";
  9.             long t1=DateTime.Now.Ticks;
  10.             for (m = r.Match(sDetail); m.Success; m = m.NextMatch())
  11.             {
  12.                
  13.                 int n=m.Groups[1].Length;//匹配长度
  14.                 str2=str2.Substring(last_i,str2.Length-last_i);//去掉上次后的结果
  15.                 int k=str2.IndexOf(m.Groups[1].ToString());//当前位置
  16.                 string this_v=str2.Substring(k,n);//当前匹配的值
  17.                 string str3=str2.Substring(0,k+n);//当前得到的值
  18.                 str1+=str3.Replace(m.Groups[1].ToString(),rps);
  19.                 //Response.Write("当前字符:"+Server.HtmlEncode(str2)+",当前匹配字符:"+Server.HtmlEncode(this_v)+""+"<br>");
  20.                 last_i=k+n;//记录当前匹配的位置
  21.             }
复制代码

完整文章和实例测试
http://www.hubro.net/item/915/
模版重利用
不管标签怎么简单,模版多了,写起来还是很累了,HTML文件不能像动态文件一样include,怎么处理好呢
HTML文件不能include,我们就在处理前include,定义标签:
  1. {--include:top--}
复制代码

定义了一个名为top的include文件,我们找出名为top的模版,读取代码,替换掉,形成完整的文件再处理
形成的最终模版
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
  3. <head>
  4. <meta http-equiv="Content-Language" content="zh-cn" />
  5. <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
  6. <meta http-equiv="pragma" content="no-cache" />
  7. <meta name="robots" content="all" />
  8. <meta name="author" content="Nicky" />
  9. <meta name="Copyright" content="www.w3cn.org" />
  10. <meta name="description" content="Hubro's blog" />
  11. <link rel="icon" href="favicon.ico" type="image/x-icon" />
  12. <link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
  13. <title>hubro.net</title>
  14. <link rel="alternate" title="Blog RSS" href="/rss2.aspx" type="application/rss+xml" />
  15. <link rel="stylesheet" rev="stylesheet" href="/skin/nicky/main.css" type="text/css" media="all" />
  16. <script language="javascript" type="text/javascript" src="/js/base.js"></script>
  17. </head>
  18. <body id="bodyview">
  19. <Acme:top runat="server"/>
  20. <div id="main">
  21.   <div id="leftframe">
  22.     <!--列表循环开始--------------------------------------------------------------------------------------->
  23.     <!--temp:loop for=index id=index_list-->
  24.     <div class="mainindex">
  25.       <h1><a href="/item/{--id--}">{--title[UNHTML]--}</a></h1>
  26.       <h2><img src="/skin/nicky/weather/hn2_{--weather--}.gif" alt="Weather"/>{--addtime--} author: {--username--}</h2>
  27.       <div  class="tag_item">Tags:{--tags--}</div>
  28.       <div class="maincontent">{--content[UBB&C_CONTENT,5]--}
  29.         <div class="readall"><a href="/item/{--id--}"><br/>
  30.           More..</a></div>
  31.       </div>
  32.       <div class="clear"></div>
  33.       <p class="views">Category:<a href="/category/{--classid--}"> {--classname--} </a> | <a href="/item/{--id--}#comment">Comments:{--comment--}</a> | <a href="/item/{--id--}#trackbacks">TrackBacks:{--trackback--}</a> [<a href="/admin/Publish.aspx?id={--id--}">Modify</a>]</p>
  34.       <p></p>
  35.     </div>
  36.     <!--temp:loop-->
  37.     <div id="pagelist">{--temp:page for=index_list--}</div>
  38.   </div>
  39.   <!--right-->
  40.   <div id="rightframe">
  41.     {--include:category--}
  42.     {--include:calendar--}
  43.     {--include:new_reply--}
  44.     {--include:new_item--}
  45.     {--include:archives--}
  46.     {--include:top_tags--}
  47.     {--include:statistics--}
  48.     {--include:link--}
  49.     <div align="center">
  50.       <script type="text/javascript"><!--
  51. google_ad_client = "pub-2574632228537424";
  52. google_ad_width = 180;
  53. google_ad_height = 60;
  54. google_ad_format = "180x60_as_rimg";
  55. google_cpa_choice = "CAAQs8X8zwEaCF3TsUAWCLVXKPu_93M";
  56. //--></script>
  57.       <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
  58. </script>
  59.       <br />
  60.       <br />
  61.       <script type="text/javascript"><!--
  62. google_ad_client = "pub-2574632228537424";
  63. google_ad_width = 160;
  64. google_ad_height = 600;
  65. google_ad_format = "160x600_as";
  66. google_ad_type = "text_image";
  67. //2007-01-27: blog_right
  68. google_ad_channel = "8640930590";
  69. google_color_border = "ffffff";
  70. google_color_bg = "ffffff";
  71. google_color_link = "0000CC";
  72. google_color_url = "008000";
  73. google_color_text = "000000";
  74. //--></script>
  75.       <script type="text/javascript"
  76.   src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
  77. </script>
  78.     </div>
  79.     <!---end of rightbar-->
  80.   </div>
  81.   <div id="footer">
  82.     <div class="footercon">
  83.       {--include:foot--}
  84.     </div>
  85.   </div>
  86. </div>
  87. </body>
  88. </html>
复制代码

运行效果
服务器不稳定,可能会出错
http://www.hubro.net/transfer.aspx?t_name=index
测试程序
说明
  1. 要运行,先添加标签,再写模版,数据库连接在web.config修改
  2. template_list.aspx                 数据源管理
  3. template_file_edit.aspx                模版管理
  4. Transfer.aspx                        转换模版
  5. test.aspx                         标签测试

  6. 标签用法

  7. 基本循环
  8.         for 定义的数据源
  9.         <!--temp:loop for=top_tags-->
  10.                 <a href="/tags/{--name--}/">{--name--}({--total--})</a>
  11.         <!--temp:loop-->
  12.         带分页的循环
  13.         <!--temp:loop for=index id=index_list-->
  14.                 {--title[UNHTML]--}
  15.         <!--temp:loop-->
  16.         <div id="pagelist">{--temp:page for=index_list--}</div>
  17.         包含处理,名称为模版名称
  18.         {--include:archives--}

  19. 标签
  20.         全局标签
  21.         {--S:PATH--},当前程序路径
  22.         {--S:DATE--},当前日期,如2007-4-20
  23.         {--S:NOW--},当前完整时间
  24.         {--S:TIME--},当前时间部份,18:40
  25.         {--S:YEAR--},当前年
  26.         {--S:MONTH--},当前月
  27.         循环内部标签处理
  28.         [--字段[type]--]
  29.         UBB,处理为UBB
  30.         UNHTML,处理为UNHTML
  31.         C_STRING,截断长度的字符串如"C_STRING,20"
  32.         取前20个字符
  33.         C_CONTENT,截行,如"C_CONTENT,5"
  34.         取前5行
  35.         TIME,格式化时间,系统写法,如"TIME,yyyy-MM"
  36.         URLENCODE,进行URL编码
  37.         URLDECODE,进行URL解码
  38.         SPLIT,分割字符,如:SPLIT,"\,","<a href=$1>$1</a>"
  39.         把此字符按","号分割,并循环,如果是","号,要写成"\,"

  40. template_file目录内模版为我的BLOG模版,可以参照这个写
  41. 运行效果
  42. http://www.hubro.net/transfer.aspx?t_name=文件名(不要扩展名)
复制代码

SourceToHTML源文件

源码说明:
标签设置存取
没有使用数据库存,通过序列化的类存为文本文件,在目录templates以.config扩展名存取
模版文件也一样,为了加快效率,使用的缓存,使用前先重建缓存
模版文件放在template_file目录下

[ 本帖最后由 hubro 于 2007-5-29 10:35 编辑 ]
附件: 你需要登录才可以下载或查看附件。没有帐号?注册

阿会楠

银牌会员

帖子
522
体力
2212
威望
1
居住地
广东省 广州市
发表于 2007-5-24 15:38:11 |显示全部楼层
希望楼主能给出详细的例子
hubro 楼主

Hi 阿洛瓦

钻石会员

帖子
4323
体力
9030
威望
3
发表于 2007-5-24 17:20:57 |显示全部楼层

回复 #2 ahuinan 的帖子

写好的代码涉及到的东西太多,类序列化,算法...
有点复杂,估计更不会看
我会给一个调试好的组件
hubro 楼主

Hi 阿洛瓦

钻石会员

帖子
4323
体力
9030
威望
3
发表于 2007-5-25 15:24:34 |显示全部楼层
模版最终生成页面
http://www.hubro.net/transfer.aspx?t_name=index
简单的列表都能生成
帖子
75
体力
153
威望
0
居住地
浙江省 杭州市
发表于 2007-5-25 18:02:34 |显示全部楼层
对不起,你访问的页面发生错误,错误信息如下:
NT AUTHORITY\NETWORK SERVICE
5do8 
帖子
3865
体力
6060
威望
105
发表于 2007-5-25 20:00:30 |显示全部楼层
1:分离成MVC,你所在的设计层都在V.
2:V层的模型编程就应该是不依赖数据库的,你创建的模板还是在C这层的.非常容易造成混乱和代码的不可维护.
3:方案:XSLT.你所的要实现的功能一个for-each就搞定了.
哇哈哈哈,看我的头像。
5do8 
帖子
3865
体力
6060
威望
105
发表于 2007-5-25 20:05:51 |显示全部楼层
1:你说微处理可以采用定义param参数,容易实现.
2:无论那种编程语言做引擎,都是不如XSL的灵活,特别是.NET,开源的也不多,自己写没那精力
3:你这样写出来的模板效率是低下的
哇哈哈哈,看我的头像。
hubro 楼主

Hi 阿洛瓦

钻石会员

帖子
4323
体力
9030
威望
3
发表于 2007-5-25 20:16:31 |显示全部楼层
模版是给不会编程的人用的
如是我,我就不用这样用模版了
MVC不太现实,特殊情况要特殊对待,就像存储过程,你能把它转换成对象么
XSL,有几个人会用XSL,如果都会用,早就是XML的天下了
效率低下,不可避免,要省资源,这个生成HTML很方便的,加载模版
另,这个不是新技术,蓝色的内容系统大概也是这样处理的,虽然是ASP的
hubro 楼主

Hi 阿洛瓦

钻石会员

帖子
4323
体力
9030
威望
3
发表于 2007-5-25 20:21:50 |显示全部楼层
我的设计层也不光只是在V
虽然少了那么一层,但我觉得我的处理很好的
cjj 

阳光锈了

荣誉管理  

帖子
5898
体力
21028
威望
117
居住地
浙江省 嘉兴市
发表于 2007-5-25 22:07:03 |显示全部楼层
模板的功能越简单越好.

或者是功能强大的编译型模板,即编译生成.net源文件
hubro 楼主

Hi 阿洛瓦

钻石会员

帖子
4323
体力
9030
威望
3
发表于 2007-5-26 15:09:25 |显示全部楼层
过份追求强大估计会弄成跟.NET控件一样,没意义了

迷城

版主  

帖子
3471
体力
7983
威望
16
发表于 2007-5-26 20:18:02 |显示全部楼层
看不懂程序,但是对于模板还是很感兴趣。
5do8 
帖子
3865
体力
6060
威望
105
发表于 2007-5-26 23:28:20 |显示全部楼层
hubro,正则在大容量的替换下面是非常慢的.
哇哈哈哈,看我的头像。
hubro 楼主

Hi 阿洛瓦

钻石会员

帖子
4323
体力
9030
威望
3
发表于 2007-5-27 09:32:06 |显示全部楼层
不是替换慢,是正则查找慢,我没有用正则查找很多字符

子小孙

高级会员

帖子
296
体力
785
威望
0
发表于 2007-5-27 13:20:09 |显示全部楼层
.net 有人会去用模板吗?好像我也有段时间想做点.net 模板的东东,不过后来没弄,浮躁,呵呵

但我现在觉得.net模板没什么用,要不然早出来一大堆了。

模板解决了什么问题?Theme实现不了?
印象中模板是php.asp里才用得东西

[ 本帖最后由 sfbasic 于 2007-5-27 13:26 编辑 ]
三百六十行,行行出BUG
hubro 楼主

Hi 阿洛瓦

钻石会员

帖子
4323
体力
9030
威望
3
发表于 2007-5-27 13:55:47 |显示全部楼层

回复 #15 sfbasic 的帖子

修行不够,还没觉悟...
hubro 楼主

Hi 阿洛瓦

钻石会员

帖子
4323
体力
9030
威望
3
发表于 2007-5-28 14:12:29 |显示全部楼层
最近几天内更新源码

娃哈哈.COM

荣誉管理

帖子
14176
体力
34852
威望
62
居住地
天津市 南开区
发表于 2007-5-28 14:44:20 |显示全部楼层
一直在想,怎么能实现页面的样式更换呢…………

不光颜色,结构什么的都可以变,可以让人自己设计页面的…………
哇嘎嘎……
毛绒玩具的卖~~~
hubro 楼主

Hi 阿洛瓦

钻石会员

帖子
4323
体力
9030
威望
3
发表于 2007-5-28 16:36:26 |显示全部楼层

回复 #18 萧萧小雨 的帖子

这就如此...
帖子
6
体力
22
威望
0
发表于 2007-6-1 13:34:53 |显示全部楼层
我是这样实现的:
<loop=news,20>
这里是列表
</loop>

娃哈哈.COM

荣誉管理

帖子
14176
体力
34852
威望
62
居住地
天津市 南开区
发表于 2007-6-11 08:46:22 |显示全部楼层
这样好是好,可是代码实现相当麻烦偶…………

得去检查语法…………
哇嘎嘎……
毛绒玩具的卖~~~
帖子
1
体力
2
威望
0
发表于 7 天前 |显示全部楼层
很好很强大...   虽然浪费了你10个积分 , 会好好研究的.!   不过mvc确实会比模版  方便很多

海之極

银牌会员  

帖子
3877
体力
2992
威望
1
居住地
广东省 广州市
发表于 6 天前 |显示全部楼层
鼓励楼主
但是还是觉得有点蛋疼
招.net开发/产品策划/前端开发/网站编辑/商务推广BD/测试工程师
您需要登录后才可以回帖 登录 | 注册


Archiver|手机版|blueidea.com ( 京ICP备05002321号 )    

GMT+8, 2012-7-27 12:14 , Processed in 0.110898 second(s), 8 queries , Gzip On, Memcache On.

Powered by Discuz! X2

© 2001-2011 Comsenz Inc.

回顶部