- 在线时间
- 4067 小时
- 专家
- 0
- UID
- 54137
- 注册时间
- 2003-6-23
- 帖子
- 4323
- 精华
- 0
- 积分
- 9045
- 离线
- 0 天
- 帖子
- 4323
- 体力
- 9030
- 威望
- 3
|
发表于 2007-5-24 14:26:47
|显示全部楼层
引言
在传统的模版处理里,都是一些简单的替换,定义好一个标签$title$,然后把这个换成动态的内容,小到一个字符串,大到一个列表
问题来了,如果是列表,这个列表是要我们用程序来循环的,也就是说,这个列表在你的模版里是改不了的,有更好的办法?
定义这个循环?在我见过的一些内容处理中,就算这些是能被定义的,但也是写死的,意味着,这个循环只能单独对这个模块有用,其它的得另写了
没有更好的办法?
我们需要自定义的循环的列表模版
要让模版列表有循环功能,只能手动来处理了,可以根据特定的标识,得到哪部份要循环
简单结构如下
- loop
- //something
- end loop
复制代码
可以把它定义为这样,temp:loop只是随便起的名字
- <!--temp:loop-->
- //要循环的内容
- <!--temp:loop-->
复制代码
对于这样的循环,怎么和数据源关联上,怎么循环
给它加一个ID
- <!--temp:loop id=news-->
- //要循环的内容
- <!--temp:loop-->
复制代码
取出模版里这个循环用正则可以很方便办到
得到这段代码,再匹配到这个循环的id是news和中间循环的内容
我们根据news值生成数据源,遍历每一行
这样完成了一个循环模版的处理过程,news是一个参数,当然可以定义其它的参数,可以先把它存好,再调用对应的
自定义的数据源
在上面知道这个循环的id是news,我们定义一个为对应为news的数据源,数据源多针对的数据库,也就是SQL语句的不同
不同的SQL语句得到不同的数据源,还有哪些参数,该显示哪些字段
对于这些参数,可以先存起来,如果有一个循环的id是news,则找到这些参数,生成DATATABLE,供循环使用,这样数据源和循环就分离了
字段显示
得到数据源和要循环的内容,剩下的就是把要循环的内容里的特殊标记替换成相应的字段值就行了
字段,可以直接替换,如果有个标记是{--field--}
替换为
- //DataRow dr....
- str=str.Replace("{--field--}",dr["field"].ToString());
复制代码
在上面数据源的参数里,对字段作了限制,如只能使用哪些字段,在这也可以体现,只替换存在的字段
综合上面,这个循环可以循环为
- <table width="200" border="1">
- <tr>
- <td>id</td>
- <td>title</td>
- </tr>
- <!--temp:loop id="news"-->
- <tr>
- <td>{--id--}</td>
- <td>{--title--}</td>
- </tr>
- <!--temp:loop-->
- </table>
复制代码
综上,一个简单的自定义循环完成了,当然还有很多细节
对列表进行分页和接收参数
上面实现了简单的列表,大多时候,是要对列表进行分页
我们增加对应的分页标签
为了使分页标签能随意放,不能循环标签直接关联,不放在里面,放在外面,增加一个特殊标记
{--temp:page for=news--}
for=news,用这来指定对应的循环
在为news的数据源,定义时,增加一个属性,是否分页
在处理循环时,如果当前循环对的是news,如果它的分页属性是true,根据当前的数据,索引页(REQUEST)生成分页
因为分页标签的位置可能不和循环在一起如下面所示
- <table width="200" border="1">
- <tr>
- <td>id</td>
- <td>title</td>
- </tr>
- <!--temp:loop id="news"-->
- <tr>
- <td>{--id--}</td>
- <td>{--title--}</td>
- </tr>
- <!--temp:loop-->
- </table>
- <div>{--temp:page for=news--}</div>
复制代码
它在外面,我们处理标签时得到的代码也只是循环标签之间的(包函标签),所以不能直接替换,可以这样做
在循环标签后面加上一段代码,记录这个循环的分页信息,过后再处理分页,处理后如下
- <table width="200" border="1">
- <tr>
- <td>id</td>
- <td>title</td>
- </tr>
- <!--这个循环标签已处理这,应该是具体的HTML代码-->
- <!--temp:loop id="news"-->
- <tr>
- <td>{--id--}</td>
- <td>{--title--}</td>
- </tr>
- <!--temp:loop-->
- {--temp:page for=news count=30 page=2 pagesize=10--}
- </table>
- <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语句是
- select * from news where class=10
复制代码
我们处理成这样
- select * from news where class=@class
复制代码
剩下的就是解析这个@class了
可以看作这个参数key是@class,value要我们来定义
value是传递过来的,但是由哪个key传递过来的
再定个规则
意思是说@class是由class这个参数传递过来
投入使用
遍历定义的参数则
- for(分割参数规则数组,循环)
- {
- 取出对应的key,value
- 生成的SQL语句为:select * from news where class=Request[value]
- }
复制代码
完成参数传递
字段处理
对于字段显示,不仅仅是停留在直接输出上就行了,比如对于标题,不想让它以HTML显示,或要截断到前几个字符
怎样在匹配字段时,把这些要执行的操作也加上去
可以这样写
- {--title[UNHTML]--}
- {--title[CUT_STRING,30]--}
复制代码
在方括号里定义要处理的方法,逗号分割所需的参数,取得括号里的参数,再进行枚举处理
甚至可以一回处理多个
- {--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>"
把此字符按","号分割,并循环,如果是","号,要写成"\,"
一般字符处理,差不多了
对大容量字符,更高效替换
一般进行替换操作都这样
- str=str.replace(字符串一,字符串二)
复制代码
不难发现一个问题,如果str要循环替换很多次,下一次替换时会累加上上次替换的内容,并且全遍历一次,如果字符串二很多,替换的过程就像阶梯效果,越来越大,所以速度越来越慢
要解决这个问题只能找另外的方法替换这种表达方式
如何以更高效率代替这种操作
思路如下,每次替换完后,在下次替换时先排除这次替换的内容,累加本次替换的内容
算法如下
- Regex r;
- Match m;
- string sDetail=Textbox1.Text;
- //sDetail=sDetail.Replace(" ","#");
- r = new Regex(@"(<.+?>)",RegexOptions.IgnoreCase);
- int last_i=0;
- string str2=sDetail;
- string str1="";
- long t1=DateTime.Now.Ticks;
- for (m = r.Match(sDetail); m.Success; m = m.NextMatch())
- {
-
- int n=m.Groups[1].Length;//匹配长度
- str2=str2.Substring(last_i,str2.Length-last_i);//去掉上次后的结果
- int k=str2.IndexOf(m.Groups[1].ToString());//当前位置
- string this_v=str2.Substring(k,n);//当前匹配的值
- string str3=str2.Substring(0,k+n);//当前得到的值
- str1+=str3.Replace(m.Groups[1].ToString(),rps);
- //Response.Write("当前字符:"+Server.HtmlEncode(str2)+",当前匹配字符:"+Server.HtmlEncode(this_v)+""+"<br>");
- last_i=k+n;//记录当前匹配的位置
- }
复制代码
完整文章和实例测试
http://www.hubro.net/item/915/
模版重利用
不管标签怎么简单,模版多了,写起来还是很累了,HTML文件不能像动态文件一样include,怎么处理好呢
HTML文件不能include,我们就在处理前include,定义标签:
定义了一个名为top的include文件,我们找出名为top的模版,读取代码,替换掉,形成完整的文件再处理
形成的最终模版
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
- <head>
- <meta http-equiv="Content-Language" content="zh-cn" />
- <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
- <meta http-equiv="pragma" content="no-cache" />
- <meta name="robots" content="all" />
- <meta name="author" content="Nicky" />
- <meta name="Copyright" content="www.w3cn.org" />
- <meta name="description" content="Hubro's blog" />
- <link rel="icon" href="favicon.ico" type="image/x-icon" />
- <link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
- <title>hubro.net</title>
- <link rel="alternate" title="Blog RSS" href="/rss2.aspx" type="application/rss+xml" />
- <link rel="stylesheet" rev="stylesheet" href="/skin/nicky/main.css" type="text/css" media="all" />
- <script language="javascript" type="text/javascript" src="/js/base.js"></script>
- </head>
- <body id="bodyview">
- <Acme:top runat="server"/>
- <div id="main">
- <div id="leftframe">
- <!--列表循环开始--------------------------------------------------------------------------------------->
- <!--temp:loop for=index id=index_list-->
- <div class="mainindex">
- <h1><a href="/item/{--id--}">{--title[UNHTML]--}</a></h1>
- <h2><img src="/skin/nicky/weather/hn2_{--weather--}.gif" alt="Weather"/>{--addtime--} author: {--username--}</h2>
- <div class="tag_item">Tags:{--tags--}</div>
- <div class="maincontent">{--content[UBB&C_CONTENT,5]--}
- <div class="readall"><a href="/item/{--id--}"><br/>
- More..</a></div>
- </div>
- <div class="clear"></div>
- <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>
- <p></p>
- </div>
- <!--temp:loop-->
- <div id="pagelist">{--temp:page for=index_list--}</div>
- </div>
- <!--right-->
- <div id="rightframe">
- {--include:category--}
- {--include:calendar--}
- {--include:new_reply--}
- {--include:new_item--}
- {--include:archives--}
- {--include:top_tags--}
- {--include:statistics--}
- {--include:link--}
- <div align="center">
- <script type="text/javascript"><!--
- google_ad_client = "pub-2574632228537424";
- google_ad_width = 180;
- google_ad_height = 60;
- google_ad_format = "180x60_as_rimg";
- google_cpa_choice = "CAAQs8X8zwEaCF3TsUAWCLVXKPu_93M";
- //--></script>
- <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
- </script>
- <br />
- <br />
- <script type="text/javascript"><!--
- google_ad_client = "pub-2574632228537424";
- google_ad_width = 160;
- google_ad_height = 600;
- google_ad_format = "160x600_as";
- google_ad_type = "text_image";
- //2007-01-27: blog_right
- google_ad_channel = "8640930590";
- google_color_border = "ffffff";
- google_color_bg = "ffffff";
- google_color_link = "0000CC";
- google_color_url = "008000";
- google_color_text = "000000";
- //--></script>
- <script type="text/javascript"
- src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
- </script>
- </div>
- <!---end of rightbar-->
- </div>
- <div id="footer">
- <div class="footercon">
- {--include:foot--}
- </div>
- </div>
- </div>
- </body>
- </html>
复制代码
运行效果
服务器不稳定,可能会出错
http://www.hubro.net/transfer.aspx?t_name=index
测试程序
说明
- 要运行,先添加标签,再写模版,数据库连接在web.config修改
- template_list.aspx 数据源管理
- template_file_edit.aspx 模版管理
- Transfer.aspx 转换模版
- test.aspx 标签测试
- 标签用法
- 基本循环
- for 定义的数据源
- <!--temp:loop for=top_tags-->
- <a href="/tags/{--name--}/">{--name--}({--total--})</a>
- <!--temp:loop-->
- 带分页的循环
- <!--temp:loop for=index id=index_list-->
- {--title[UNHTML]--}
- <!--temp:loop-->
- <div id="pagelist">{--temp:page for=index_list--}</div>
- 包含处理,名称为模版名称
- {--include:archives--}
- 标签
- 全局标签
- {--S:PATH--},当前程序路径
- {--S:DATE--},当前日期,如2007-4-20
- {--S:NOW--},当前完整时间
- {--S:TIME--},当前时间部份,18:40
- {--S:YEAR--},当前年
- {--S:MONTH--},当前月
- 循环内部标签处理
- [--字段[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>"
- 把此字符按","号分割,并循环,如果是","号,要写成"\,"
- template_file目录内模版为我的BLOG模版,可以参照这个写
- 运行效果
- http://www.hubro.net/transfer.aspx?t_name=文件名(不要扩展名)
复制代码
SourceToHTML源文件
源码说明:
标签设置存取
没有使用数据库存,通过序列化的类存为文本文件,在目录templates以.config扩展名存取
模版文件也一样,为了加快效率,使用的缓存,使用前先重建缓存
模版文件放在template_file目录下
[ 本帖最后由 hubro 于 2007-5-29 10:35 编辑 ] |
附件: 你需要登录才可以下载或查看附件。没有帐号?注册
|