欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

ASP模板引擎实现

程序员文章站 2022-06-10 16:49:25
模板引擎说明: 1.此模板引擎由个人独立完成,转载或使用请联系 2.引擎内部使用了其它函数及操作类,暂时不能直接使用 3.发出来是想分享一下自己的解析思路,希望有兴趣的朋友点评一下 以下是说明...

模板引擎说明:
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 
    &nbsp