ASP模板引擎实现
模板引擎说明:
1.此模板引擎由个人独立完成,转载或使用请联系
2.引擎内部使用了其它函数及操作类,暂时不能直接使用
3.发出来是想分享一下自己的解析思路,希望有兴趣的朋友点评一下
以下是说明
==============================沧桑的分隔线====================================
模板对象属性
bhtm //是否生成静态
filepath //指定静态文件路径,包括文件名,生成静态时必须指定
相对于htmpath的路径
iche //缓存时间,以秒计,不指定时从常量内取值,0时不缓存
schr //模板文件的编码,默认gb2312
全局变量
//开始替换一次,最后替换一次
{$变量名}
{$apppath} /程序根目录
{$filepath} /上传文件目录
{$template} /当前模板目录
{$source} /当前模板资源目录
{$sitename}
{$sitetitle}
{$sitedesc}
{$sitekeywords}
{$siteurl}
{$lang} //当前语言
在标签内使用 $变量名
//变量
{$query.}
{$form.}
{$cookie.}
{$server.}
{$session.}
以上变量不区分大小写
{$obj.key} /注册的obj变量的key值.
变量格式
{var:} //直接注册的变量
{$obj.key} //注册的obj的属性
{@} //循环内变量
支持变量格式化,以|分割每一个参数,不需使用引号,函数名不区分大小写
fmtdate 格式化日期 kindly/yyyy-mm-dd hh:nn:ss www,不是日期格式将原样输出
cutstr 截取化字符串 长度|尾符
lcase
ucase
nohtml 去除html标签
html 输出html格式
ubb 将ubb转为html
escape 编码
jscode js编码
replace 要替换的字符|替换的字符
trip 去除多余空格
fmtnum 格式化数字 类型|长度|是否截短 1.填充整型,前补0,2.填充小数,后补0,3.转化16进制格式,4.十六进制转换十进制
url 1.内容页url,2.列表页url | 类别|id/page
default 默认值.字符串为空时
iif 真|假 /会先强制转换布尔
filesize将数值转换为磁盘空间计量
以下标签名小写
自定义变量(通过assign注册的字符串或数字)
{var:}
//开始读取包含
包含文件,相对于当前模板文件夹,可包含子目录
{include(fiename)}
以下标签带有属性,属性必须使用"或'包括,属性内的'使用%27,"使用%22代替
属性名最好使用小写
有[]或[的地方表示该属性可有可无,没有则表示该属性必须指定值
函数 用于对标签内容使用指定函数解析
{fn: func="" [args="" [argtype=""]]}{/fn}
函数必须为自定义函数,必须返回字符串,不能使用系统函数
函数参数个数必须符合要求,最多5个参数
第一个参数为标签内容
如果需要其它的参数,使用args=""属性.
参数用,隔开,参数内的,使用%2c表示,%使用%25表示
argtype指定对应位置的参数格式,可使用s-字符串,i-整型,f-浮点型,b-布尔型, ,分隔
不指定时默认全部以字符串传递
判断 //可嵌套
{if:}{elseif:}{else}{/if}
循环 //可嵌套
{for:}{/for}
}
var=
[from= //省略时为1
to=
[step= //省略时为1
{foreach:}{/foreach}
}
}
var=
name= //注册的obj
{loop:}{loopelse}{/loop}
.}
name= /已注册的,recordset
[count= /与limit同用时优先级较高
[limit= /a,b表示从recordset的第a行开始显示b条,只有一个值则等同于count
{sql:}{sqlelse}{/sql}
.}
} /当前索引
name=
table=
[count= /显示数量,最多100行
[where= /不含where,完整的条件语句,字段名以$p$开头
[field= /以,分割字段名
[limit= /a,b 起始,长度,必须是数值,如果只有一个值,则表示查询前n条
[order= /以,分割排序值
局部不缓存
<nocache>
</nocache>
该标不可嵌套,不可用在其它标签内部
局部长缓存,不受全局缓存时间影响,但当全局缓存未过期时不会更新
该功能针对需要复杂解析或多次读取数据但一般不会更新的部分进行缓存
<cache name="" [time=""]>
</cache>
name属性必须,且所有局部缓存不能同名
time以小时计,省略时永久缓存,除非清除缓存
==============================沧桑的分隔线====================================
以下是解析类的
vbscript代码
'**********************************
'asp模板引擎
'用法: set var=new stemplate
' [var.prop=vars]
' [var.assign name,value]
' var.display tplpath
'作者: shirne
'日期: 2011/9/10
'**********************************
class stemplate
private odata, otype, oreg, osql, ostm, ofso
private sapp, stpl, sext, shtm, sfmt
private istart,iquery '开始运行时间
private htmpath,acache,chepath
public bhtm,filepath,iche,schr
private sub class_initialize
istart = timer()
sapp = apppath
stpl = apppath & template_path & "default/"
sext = ".html"
schr = "gb2312" '编码
sfmt = "\w\d\/\\\-\[\]\.\u4000-\u9000" '变量格式化允许的字符,不能有}
iche = cache_time '缓存时间以秒计
bhtm = html_open '是否生成静态,生成静态时必须指定filepath
iquery = 0 '自定义的sql查询次数
htmpath = apppath&"html/"&lang&"/" '静态文件路径
chepath = apppath&"cache/"&lang&"/" '缓存文件路径
set odata = server.createobject("scripting.dictionary") '存放注册数据
set otype = server.createobject("scripting.dictionary") '存放数据类型
set ostm = server.createobject("adodb.stream")
set ofso = server.createobject("scripting.filesystemobject")
set oreg = reobject("",true,true,true)
checkpath htmpath
checkpath chepath
end sub
private sub class_terminate
odata.removeall
otype.removeall
shtm = ""
set odata = nothing
set otype = nothing
set ostm = nothing
set ofso = nothing
set oreg = nothing
end sub
'注册变量或obj或数组,重复注册会替换掉旧的
public sub assign(sname,obj)
if odata.exists(sname) then
odata(sname)=obj
otype(sname)=vtype(obj)
else
odata.add sname,obj
otype.add sname,vtype(obj)
end if
end sub
'显示
public sub display(ftpl)
dim n,i,j,k,fpathfpath,itmp
j = -1
fpath = chepath&urlencode(getfilestr)&".cache"
if iche>0 then '获取缓存
if ofso.fileexists(server.mappath(fpath)) then
set f=ofso.getfile(server.mappath(fpath))
if datediff("s",f.datelastmodified,now)<iche then
shtm=readfile(fpath)
end if
end if
end if
if shtm="" then
shtm = readfile(stpl&ftpl)
shtm = include(shtm)
if instr(shtm,"<nocache>")>0 then
i=instr(shtm,"<nocache>")
j=0
redim acache(0)
do until i<1
redim preserve acache(j)
k=instr(i,shtm,"</nocache>")
if k<1 then cerr(15)
acache(j)=mid(shtm,i+9,k-i-10)
i=instr(k,"<nocache>")
if i>0 then j=j+1
loop
end if
shtm = getcache(shtm)
shtm = ireplace(shtm)
shtm = analytpl(shtm)
'shtm = ireplace(shtm)
if iche>0 then
itmp=shtm
if j>-1 then
i=1
for k=0 to j
i=instr(i,itmp,"<nocache>")
n=instr(i,itmp,"</nocache>")
if i<0 or n<0 then exit for
itmp=replace(itmp,mid(itmp,i+9,n-i-10),acache(k))
i=n
next
shtm = replace(shtm,"<nocache>","")
shtm = replace(shtm,"</nocache>","")
end if
savefile fpath,itmp
end if
else
if instr(shtm,"<nocache>")>0 then
shtm = ireplace(shtm)
shtm = analytpl(shtm)
'shtm = ireplace(shtm)
shtm = replace(shtm,"<nocache>","")
shtm = replace(shtm,"</nocache>","")
end if
end if
if cbol(bhtm) then
checkpath(getdir(htmpath&filepath))
savefile htmpath&filepath,shtm
end if
j=ccur(timer()-istart)
if j<1 then j="0"&j
shtm=replace(shtm,"{#executetime}","processed in "&j&" second(s), "&iquery&" queries:")
echo shtm
end sub
public sub clearcache
on error resume next
if ofso.folderexists(server.mappath(chepath)) then
ofso.deletefolder server.mappath(chepath)
end if
if err then cerr 32
end sub
private function getcache(scont)
dim i,ii,iii
i=instr(scont,"<cache")
if i<1 then
getcache=scont
else
dim j,slabel,stmp,oatt,cpath,stemp
do
ii=instr(i,scont,"</cache>")
if ii<1 then cerr 16
j=instr(i,scont,">")
slabel=mid(scont,i+6,j-i-6)
stemp=mid(scont,j+1,ii-j-1)
set oatt=analylabel(slabel)
if oatt.exists("name") then
checkpath chepath&"global/"
cpath=chepath&"global/"&oatt("name")&".cache"
if ofso.fileexists(server.mappath(cpath)) then
if oatt.exists("time") then
if datediff("h",(ofso.getfile(server.mappath(cpath))).datelastmodified,now)<oatt("time") then
stmp=readfile(cpath)
end if
else
stmp=readfile(cpath)
end if
end if
if stmp="" then
stmp=stemp
stmp = ireplace(stmp)
stmp = analytpl(stmp)
savefile cpath,stmp
end if
scont=replace(scont,"<cache"&slabel&">"&stemp&"</cache>",stmp)
i=instr(i+len(stmp),scont,"<cache")
stmp=""
else
i=instr(ii,scont,"<cache")
end if
loop until i<1
getcache=scont
end if
end function
private function getfilestr()
dim strtemps
strtemps = strtemps & request.servervariables("url")
if trim(request.querystring) <> "" then
strtemps = strtemps & "?" & trim(request.querystring)
else
strtemps = strtemps
end if
getfilestr = strtemps
end function
private function include(scontent)
dim matches, match, i
include=scontent
i=0
oreg.pattern="\{include\s*\(([\'\""])?([\w\.\d\/\\]+)\1\)\}"
do
set matches=oreg.execute(scontent)
for each match in matches
include=replace(include,match.value,readfile(stpl&match.submatches(1)))
next
i=i+1
loop while matches.count>0 and i<5 '最深5层包含
if matches.count>0 then
include=oreg.replace(include,"")
end if
end function
private sub savefile(byval tpl,html)
tpl = server.mappath(tpl)
ostm.type = 2
ostm.mode = 3
ostm.charset= schr
ostm.open
ostm.writetext html
ostm.seteos
ostm.savetofile tpl,2
ostm.close
end sub
private function readfile(byval tpl)
tpl = server.mappath(tpl)
ostm.type = 2
ostm.mode = 3
ostm.charset= schr
ostm.open
if ofso.fileexists(tpl) then
ostm.loadfromfile tpl
readfile=ostm.readtext
ostm.flush
ostm.close
else
cerr 1
end if
end function
private function ireplace(shtm)
dim n, omth, match, itmp
oreg.pattern="\{\$apppath\}":shtm=oreg.replace(shtm,apppath)
oreg.pattern="\{\$filepath\}":shtm=oreg.replace(shtm,apppath & file_up_path)
oreg.pattern="\{\$template\}":shtm=oreg.replace(shtm,stpl)
oreg.pattern="\{\$source\}":shtm=oreg.replace(shtm,stpl&"resource/")
oreg.pattern="\{\$sitename\}":shtm=oreg.replace(shtm,eval("sitename"&lang))
oreg.pattern="\{\$sitetitle\}":shtm=oreg.replace(shtm,eval("sitetitle"&lang))
oreg.pattern="\{\$sitedesc\}":shtm=oreg.replace(shtm,eval("sitedesc"&lang))
oreg.pattern="\{\$sitekeywords\}":shtm=oreg.replace(shtm,eval("sitewords"&lang))
oreg.pattern="\{\$copyright\}":shtm=oreg.replace(shtm,eval("copyright"&lang))
oreg.pattern="\{\$siteurl\}":shtm=oreg.replace(shtm,siteurl)
oreg.pattern="\{\$lang\}":shtm=oreg.replace(shtm,lang)
oreg.pattern="(\{[^{]+)\$apppath([^}]*\})":shtm=oreg.replace(shtm,"$1"&apppath&"$2")
oreg.pattern="(\{[^{]+)\$filepath([^}]*\})":shtm=oreg.replace(shtm,"$1"&apppath & file_up_path&"$2")
oreg.pattern="(\{[^{]+)\$template([^}]*\})":shtm=oreg.replace(shtm,"$1"&stpl&"$2")
oreg.pattern="(\{[^{]+)\$source([^}]*\})":shtm=oreg.replace(shtm,"$1"&stpl&"resource/"&"$2")
oreg.pattern="(\{[^{]+)\$sitename([^}]*\})":shtm=oreg.replace(shtm,"$1"&eval("sitename"&lang)&"$2")
oreg.pattern="(\{[^{]+)\$sitetitle([^}]*\})":shtm=oreg.replace(shtm,"$1"&eval("sitetitle"&lang)&"$2")
oreg.pattern="(\{[^{]+)\$sitedesc([^}]*\})":shtm=oreg.replace(shtm,"$1"&eval("sitedesc"&lang)&"$2")
oreg.pattern="(\{[^{]+)\$sitekeywords([^}]*\})":shtm=oreg.replace(shtm,"$1"&eval("sitewords"&lang)&"$2")
oreg.pattern="(\{[^{]+)\$copyright([^}]*\})":shtm=oreg.replace(shtm,"$1"&eval("copyright"&lang)&"$2")
oreg.pattern="(\{[^{]+)\$siteurl([^}]*\})":shtm=oreg.replace(shtm,"$1"&siteurl&"$2")
oreg.pattern="(\{[^{]+)\$lang([^}]*\})":shtm=oreg.replace(shtm,"$1"&lang&"$2")
for each n in odata
if otype(n)=0 then
oreg.pattern="\{var\:"&n&"((?:\|["& sfmt &"]+)*)?\}"
set omth=oreg.execute(shtm)
for each match in omth
if match.submatches.count>0 then
shtm=replace(shtm,match.value,fmtvar(odata(n),match.submatches(0)))
else
shtm=replace(shtm,match.value,odata(n))
end if
next
'替换标签内变量
oreg.pattern="\{[^{]+@var:"&n&"[^}]*\}"
set omth=oreg.execute(shtm)
for each match in omth
shtm=replace(shtm,match.value,replace(match.value,"@var:"&n,odata(n)))
next
end if
next
oreg.pattern="\{\$([\d\w]+)\.([\d\w]+)((?:\|["& sfmt &"]+)*)?\}"
set omth=oreg.execute(shtm)
for each match in omth
if match.submatches.count<=2 then itmp="" else itmp=match.submatches(2)
shtm=replace(shtm,match.value,getvalue(match.submatches(0),match.submatches(1),itmp))
next
'替换标签内变量
oreg.pattern="\{[^{]+\$([\d\w]+)\.([\d\w]+)[^}]*\}"
set omth=oreg.execute(shtm)
for each match in omth
if match.submatches.count<=2 then itmp="" else itmp=match.submatches(2)
shtm=replace(shtm,match.value,_
replace(match.value,"$"&match.submatches(0)&"."&match.submatches(1),_
getvalue(match.submatches(0),match.submatches(1),itmp)))
next
ireplace=shtm
end function
'解析模板
private function analytpl(byval scont)
dim i,stag,slabel,iend,idiv,stemp,ilayer
dim ipos,irtn,itmp,j,k,l,ii,iii,oatt,stmp,slbl
i=instr(scont,"{")
do while i>0
'标签的内容
slabel=mid(scont,i+1,instr(i,scont,"}")-i-1)
if instr(slabel,":")>0 then '跳过其它标签
'标签名
stag=left(slabel,instr(slabel,":")-1)
'标签结束位置
iend=instr(i,scont,"{/"&stag&"}")
if iend <1 then cerr stag
'标签模板
stemp=mid(scont,i+len(slabel)+2,iend-i-len(slabel)-2)
'是否存在嵌套
idiv=instr(stemp,"{"&stag&":")
ilayer=0
do while idiv>0
ilayer=ilayer+1 '层数加1
iend=instr(iend+1,scont,"{/"&stag&"}")
if iend<1 then cerr stag
stemp=mid(scont,i+len(slabel)+2,iend-i-len(slabel)-2)
idiv=instr(idiv+1,stemp,"{"&stag&":")
loop
'将变量缓存,以防后期被改变
stmp=stemp
slbl=slabel
irtn="" '解析返回值
select case stag
case "if"
if ilayer=0 then '无嵌套时执行解析
if instr(stemp,"{elseif:")>0 then
itmp=split(stemp,"{elseif:")
k=ubound(itmp)
if judge(mid(slabel,4)) then
irtn=itmp(0)
else
for j=1 to k
if judge(left(itmp(j),instr(itmp(j),"}")-1)) then
irtn=mid(itmp(j),instr(itmp(j),"}")+1)
end if
next
end if
if irtn="" and instr(itmp(k),"{else}")>0 then
irtn=analytpl(split(itmp(k),"{else}")(1))
else
irtn=analytpl(irtn)
end if
elseif instr(stemp,"{else}")>0 then
itmp=split(stemp,"{else}")
if judge(mid(slabel,4)) then
irtn=analytpl(itmp(0))
else
irtn=analytpl(itmp(1))
end if
else
if judge(mid(slabel,4)) then
irtn=analytpl(stemp)
end if
end if
else '有嵌套时循环解析
stemp=replace(stemp,"{else}","{elseif:1=1}")
ii=instr(stemp,"{elseif:")
k=instr(stemp,"{if:")
if judge(mid(slabel,4)) then
if ii<0 then
irtn=analytpl(stemp)
elseif k>ii then '隐含条件 ii>0
irtn=analytpl(mid(stemp,ii-1))
else '隐含条件ii>0,k<ii
idiv=instr(stemp,"{/if}")
do until instr(k+1,left(stemp,idiv),"{if:")<1
k=instr(k+1,stemp,"{if:")
idiv=instr(idiv+1,stemp,"{/if}")
if idiv<1 then cerr(12)
loop
idiv=instr(idiv,stemp,"{elseif:")
if idiv>0 then
irtn=analytpl(left(stemp,idiv-1))
else
irtn=analytpl(stemp)
end if
end if
elseif ii>0 then '不存在else或elseif,则整段已经被抛弃
if k<ii then '隐含条件k>0
idiv=instr(stemp,"{/if}")
do until instr(k+1,left(stemp,idiv),"{if:")<1
k=instr(k+1,stemp,"{if:")
idiv=instr(idiv+1,stemp,"{/if}")
if idiv<1 then cerr(12)
loop
ii=instr(idiv,stemp,"{elseif:")
end if
if ii>0 then '与上面ii>0不同,如果首段if排除后已经没有else,也抛弃
slabel=mid(stemp,ii+8,instr(ii,stemp,"}")-ii-8)
do until judge(slabel) '当前elseif内标签不为真
k=instr(ii,stemp,"{if:")
idiv=instr(ii,stemp,"{/if}")
ii=instr(ii+1,stemp,"{elseif:")
if k>0 and k<ii then '下一个else前有if
do until instr(k+1,left(stemp,idiv),"{if:")<1
k=instr(k+1,stemp,"{if:")
idiv=instr(idiv+1,stemp,"{/if}")
if idiv<1 then cerr(12)
loop
ii=instr(idiv,stemp,"{elseif:")
end if
if ii<1 then exit do
slabel=mid(stemp,ii+8,instr(ii,stemp,"}")-ii-8)
loop
'寻找当前内容段作为返回
if ii>0 then
iii=instr(ii,stemp,"}") '定位当前标签结束位置
k=instr(ii,stemp,"{if:")
idiv=instr(ii,stemp,"{/if}")
ii=instr(ii,stemp,"{elseif:")
if k>0 and k<ii then '下一个else前有if
do until instr(k+1,left(stemp,idiv),"{if:")<1
k=instr(k+1,stemp,"{if:")
idiv=instr(idiv+1,stemp,"{/if}")
if idiv<1 then cerr(12)
loop
ii=instr(idiv,stemp,"{elseif:")
end if
if ii<1 then
irtn=analytpl(mid(stemp,iii+1))
else
 
下一篇: 女人肾虚的症状有哪些,有哪些危害呢