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编码
jscodejs编码
replace要替换的字符|替换的字符
trip去除多余空格
fmtnum格式化数字 类型|长度|是否截短 1.填充整型,前补0,2.填充小数,后补0,3.转化16进制格式,4.十六进制转换十进制
url1.内容页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}
var=
[from=//省略时为1
to=
[step=//省略时为1
{foreach:}{/foreach}
{@var.name}
{@var.value}
var=
name=//注册的obj
{loop:}{loopelse}{/loop}
{@name.}
name=/已注册的,recordset
[count=/与limit同用时优先级较高
[limit=/a,b表示从recordset的第a行开始显示b条,只有一个值则等同于count
{sql:}{sqlelse}{/sql}
{@name.}
{@name.@index}/当前索引
name=
table=
[count=/显示数量,最多100行
[where=/不含where,完整的条件语句,字段名以$p$开头
[field=/以,分割字段名
[limit=/a,b 起始,长度,必须是数值,如果只有一个值,则表示查询前N条
[order=/以,分割排序值
局部不缓存
<nocache>
</nocache>
该标不可嵌套,不可用在其它标签内部
局部长缓存,不受全局缓存时间影响,但当全局缓存未过期时不会更新
该功能针对需要复杂解析或多次读取数据但一般不会更新的部分进行缓存
<cache name="" [time=""]>
</cache>
name属性必须,且所有局部缓存不能同名
time以小时计,省略时永久缓存,除非清除缓存
==============================沧桑的分隔线====================================
以下是解析类的源码
'**********************************'ASP模板引擎'用法:Set var=new sTemplate'[var.prop=vars]'[var.assign name,value]'var.display tplpath'作者:shirne'日期:2011/9/10'**********************************Class sTemplatePrivate oData, oType, oReg, oSql, oStm, oFsoPrivate sApp, sTpl, sExt, sHtm, sFmtPrivate iStart,iQuery'开始运行时间PrivatehtmPath,aCache,chePathPublic bHtm,filePath,iChe,sChrPrivate Sub Class_InitializeiStart= Timer()sApp= AppPathsTpl= AppPath & TEMPLATE_PATH & "default/"sExt= ".html"sChr= "gb2312"'编码sFmt= "\w\d\/\\\-\[\]\.\u00A1-\uFFFF"'变量格式化允许的字符,不能有}iChe= CACHE_TIME'缓存时间以秒计bHtm= HTML_OPEN'是否生成静态,生成静态时必须指定filepathiQuery= 0'自定义的sql查询次数htmPath= AppPath&"html/"'静态文件路径chePath= AppPath&"cache/"'缓存文件路径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 htmPathCheckPath chePathEnd SubPrivate Sub Class_TerminateoData.RemoveAlloType.RemoveAllsHtm= ""Set oData= NothingSet oType= NothingSet oStm= NothingSet oFso= NothingSet oReg= NothingEnd Sub'注册变量或obj或数组Public Sub assign(sName,obj)If oData.Exists(sName) ThenoData(sName)=objoType(sName)=vType(obj)ElseoData.Add sName,objoType.Add sName,vType(obj)End IfEnd Sub'显示Public Sub Display(fTpl)Dim n,i,j,k,fPathfPath,iTmpj= -1fPath= chePath&URLEncode(GetFileStr)&".cache"If iChe>0 Then'获取缓存If oFso.FileExists(Server.MapPath(fPath)) ThenSet f=oFso.GetFile(Server.MapPath(fPath))If DateDiff("s",f.DateLastModified,Now)<iChe ThensHtm=ReadFile(fPath)End IfEnd IfEnd IfIf sHtm="" ThensHtm= ReadFile(sTpl&fTpl)sHtm= include(sHtm)If InStr(sHtm,"<nocache>")>0 Theni=InStr(sHtm,"<nocache>")j=0ReDim aCache(0)Do Until i<1ReDim 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+1LoopEnd IfsHtm= getCache(sHtm)sHtm= iReplace(sHtm)sHtm= analyTpl(sHtm)'sHtm= iReplace(sHtm)If iChe>0 TheniTmp=sHtmIf j>-1 Theni=1For k=0 To ji=InStr(i,iTmp,"<nocache>")n=InStr(i,iTmp,"</nocache>")If i<0 Or n<0 Then Exit ForiTmp=Replace(iTmp,Mid(iTmp,i+9,n-i-10),aCache(k))i=nNextsHtm= Replace(sHtm,"<nocache>","")sHtm= Replace(sHtm,"</nocache>","")End IfSaveFile fPath,iTmpEnd IfElseIf InStr(sHtm,"<nocache>")>0 ThensHtm= iReplace(sHtm)sHtm= analyTpl(sHtm)'sHtm= iReplace(sHtm)sHtm= Replace(sHtm,"<nocache>","")sHtm= Replace(sHtm,"</nocache>","")End IfEnd IfIf CBol(bHtm) ThenCheckPath(getDir(htmPath&filePath))SaveFile htmPath&filePath,sHtmEnd Ifj=CCur(Timer()-iStart)If j<1 Then j="0"&jsHtm=Replace(sHtm,"{#ExecuteTime}","Processed in "&j&" second(s), "&iQuery&" queries:")Echo sHtmEnd SubPublic Sub ClearCacheOn Error Resume NextIf oFso.FolderExists(Server.MapPath(chePath)) ThenoFso.DeleteFolder Server.MapPath(chePath)End IfIf Err Then cErr 32End SubPrivate Function getCache(sCont)Dim i,ii,iiii=InStr(sCont,"<cache")If i<1 ThengetCache=sContElseDim j,sLabel,sTmp,oAtt,cPath,sTempDoii=InStr(i,sCont,"</cache>")If ii<1 Then cErr 16j=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") ThenCheckPath chePath&"global/"cPath=chePath&"global/"&oAtt("name")&".cache"If oFso.FileExists(Server.MapPath(cPath)) ThenIf oAtt.Exists("time") ThenIf DateDiff("h",(oFso.getFile(Server.MapPath(cPath))).DateLastModified,Now)<oAtt("time") ThensTmp=ReadFile(cPath)End IfElsesTmp=ReadFile(cPath)End IfEnd IfIf sTmp="" ThensTmp=sTempsTmp= iReplace(sTmp)sTmp= analyTpl(sTmp)SaveFile cPath,sTmpEnd IfsCont=Replace(sCont,"<cache"&sLabel&">"&sTemp&"</cache>",sTmp)i=InStr(i+Len(sTmp),sCont,"<cache")sTmp=""Elsei=InStr(ii,sCont,"<cache")End IfLoop Until i<1getCache=sContEnd IfEnd FunctionPrivate Function GetFileStr() Dim strTemps strTemps = strTemps & Request.ServerVariables("URL") If Trim(Request.QueryString) <> "" Then strTemps = strTemps & "?" & Trim(Request.QueryString) ElsestrTemps = strTemps End IfGetFileStr = strTemps End FunctionPrivate Function include(sContent)Dim Matches, Match, iinclude=sContenti=0oReg.Pattern="\{include\s*\(([\'\""])?([\w\.\d\/\\]+)\1\)\}"DoSet Matches=oReg.Execute(sContent)For Each Match In Matchesinclude=Replace(include,Match.Value,ReadFile(sTpl&Match.SubMatches(1)))Nexti=i+1Loop While Matches.Count>0 And i<5'最深5层包含If Matches.Count>0 Theninclude=oReg.Replace(include,"")End IfEnd FunctionPrivate Sub SaveFile(ByVal tpl,html)tpl = Server.MapPath(tpl)oStm.Type= 2oStm.Mode= 3oStm.CharSet= sChroStm.OpenoStm.WriteText htmloStm.SetEOSoStm.SaveToFile tpl,2oStm.CloseEnd SubPrivate Function ReadFile(ByVal tpl)tpl = Server.MapPath(tpl)oStm.Type= 2oStm.Mode= 3oStm.CharSet= sChroStm.OpenIf oFso.FileExists(tpl) ThenoStm.LoadFromFile tplReadFile=oStm.ReadTextoStm.FlushoStm.CloseElsecErr 1End IfEnd FunctionPrivate Function iReplace(sHtm)Dim n, oMth, Match, iTmpoReg.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,SiteName)oReg.Pattern="\{\$SiteTitle\}":sHtm=oReg.Replace(sHtm,SiteTitle)oReg.Pattern="\{\$SiteDesc\}":sHtm=oReg.Replace(sHtm,SiteDesc)oReg.Pattern="\{\$SiteKeyWords\}":sHtm=oReg.Replace(sHtm,SiteWords)oReg.Pattern="\{\$CopyRight\}":sHtm=oReg.Replace(sHtm,CopyRight)oReg.Pattern="\{\$SiteURL\}":sHtm=oReg.Replace(sHtm,SiteURL)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"&SiteName&"$2")oReg.Pattern="(\{[^{]+)\$SiteTitle([^}]*\})":sHtm=oReg.Replace(sHtm,"$1"&SiteTitle&"$2")oReg.Pattern="(\{[^{]+)\$SiteDesc([^}]*\})":sHtm=oReg.Replace(sHtm,"$1"&SiteDesc&"$2")oReg.Pattern="(\{[^{]+)\$SiteKeyWords([^}]*\})":sHtm=oReg.Replace(sHtm,"$1"&SiteWords&"$2")oReg.Pattern="(\{[^{]+)\$CopyRight([^}]*\})":sHtm=oReg.Replace(sHtm,"$1"&CopyRight&"$2")oReg.Pattern="(\{[^{]+)\$SiteURL([^}]*\})":sHtm=oReg.Replace(sHtm,"$1"&SiteURL&"$2")For Each n In oDataIf oType(n)=0 ThenoReg.Pattern="\{var\:"&n&"((?:\|["& sFmt &"]+)*)?\}"Set oMth=oReg.Execute(sHtm)For Each Match In oMthIf Match.SubMatches.Count>0 ThensHtm=Replace(sHtm,Match.Value,fmtVar(oData(n),Match.SubMatches(0)))ElsesHtm=Replace(sHtm,Match.Value,oData(n))End IfNext'替换标签内变量oReg.Pattern="\{[^{]+@var:"&n&"[^}]*\}"Set oMth=oReg.Execute(sHtm)For Each Match In oMthsHtm=Replace(sHtm,Match.Value,Replace(Match.Value,"@var:"&n,oData(n)))NextEnd IfNextoReg.Pattern="\{\$([\d\w]+)\.([\d\w]+)((?:\|["& sFmt &"]+)*)?\}"Set oMth=oReg.Execute(sHtm)For Each Match In oMthIf 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 oMthIf 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)))NextiReplace=sHtmEnd Function'解析模板Private Function analyTpl(ByVal sCont)Dim i,sTag,sLabel,iEnd,iDiv,sTemp,ilayerDim iPos,iRtn,iTmp,j,k,l,ii,iii,oAtt,sTmp,sLbli=InStr(sCont,"{")Do While i>0'标签的内容sLabel=Mid(sCont,i+1,InStr(i,sCont,"}")-i-1)ii=InStr(sLabel,":")If ii>0 Then'跳过其它标签'标签名sTag=Left(sLabel,ii-1)If InStr("|if|fn|for|foreach|loop|sql|","|"&sTag&"|")>0 Then'标签结束位置iEnd=InStr(i,sCont,"{/"&sTag&"}")If iEnd <1 Then cErr(3)'标签模板sTemp=Mid(sCont,i+Len(sLabel)+2,iEnd-i-Len(sLabel)-2)'是否存在嵌套iDiv=InStr(sTemp,"{"&sTag&":")ilayer=0Do While iDiv>0ilayer=ilayer+1 '层数加1iEnd=InStr(iEnd+1,sCont,"{/"&sTag&"}")If iEnd<1 Then cErr 3sTemp=Mid(sCont,i+Len(sLabel)+2,iEnd-i-Len(sLabel)-2)iDiv=InStr(iDiv+1,sTemp,"{"&sTag&":")Loop'将变量缓存,以防后期被改变sTmp=sTempsLbl=sLabelEnd IfiRtn=""'解析返回值Select Case sTagCase "if"If ilayer=0 Then'无嵌套时执行解析If InStr(sTemp,"{elseif:")>0 TheniTmp=Split(sTemp,"{elseif:")k=UBound(iTmp)If judge(Mid(sLabel,4)) TheniRtn=iTmp(0)ElseFor j=1 To kIf judge(Left(iTmp(j),InStr(iTmp(j),"}")-1)) TheniRtn=Mid(iTmp(j),InStr(iTmp(j),"}")+1)End IfNextEnd IfIf iRtn="" And InStr(iTmp(k),"{else}")>0 TheniRtn=analyTpl(Split(iTmp(k),"{else}")(1))ElseiRtn=analyTpl(iRtn)End IfElseIf InStr(sTemp,"{else}")>0 TheniTmp=Split(sTemp,"{else}")If judge(Mid(sLabel,4)) TheniRtn=analyTpl(iTmp(0))ElseiRtn=analyTpl(iTmp(1))End IfElseIf judge(Mid(sLabel,4)) TheniRtn=analyTpl(sTemp)End IfEnd IfElse'有嵌套时循环解析sTemp=Replace(sTemp,"{else}","{elseif:1=1}")ii=InStr(sTemp,"{elseif:")k=InStr(sTemp,"{if:")If judge(Mid(sLabel,4)) ThenIf ii<0 TheniRtn=analyTpl(sTemp)ElseIf k>ii Then'隐含条件 ii>0iRtn=analyTpl(Mid(sTemp,ii-1))Else'隐含条件ii>0,k<iiiDiv=InStr(sTemp,"{/if}")Do Until InStr(k+1,Left(sTemp,iDiv),"{if:")<1k=InStr(k+1,sTemp,"{if:")iDiv=InStr(iDiv+1,sTemp,"{/if}")If iDiv<1 Then cErr(12)LoopiDiv=InStr(iDiv,sTemp,"{elseif:")If iDiv>0 TheniRtn=analyTpl(Left(sTemp,iDiv-1))ElseiRtn=analyTpl(sTemp)End IfEnd IfElseIf ii>0 Then'不存在else或elseif,则整段已经被抛弃If k<ii Then'隐含条件k>0iDiv=InStr(sTemp,"{/if}")Do Until InStr(k+1,Left(sTemp,iDiv),"{if:")<1k=InStr(k+1,sTemp,"{if:")iDiv=InStr(iDiv+1,sTemp,"{/if}")If iDiv<1 Then cErr(12)Loopii=InStr(iDiv,sTemp,"{elseif:")End IfIf 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前有ifDo Until InStr(k+1,Left(sTemp,iDiv),"{if:")<1k=InStr(k+1,sTemp,"{if:")iDiv=InStr(iDiv+1,sTemp,"{/if}")If iDiv<1 Then cErr(12)Loopii=InStr(iDiv,sTemp,"{elseif:")End IfIf ii<1 Then Exit DosLabel=Mid(sTemp,ii+8,InStr(ii,sTemp,"}")-ii-8)Loop'寻找当前内容段作为返回If ii>0 Theniii=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前有ifDo Until InStr(k+1,Left(sTemp,iDiv),"{if:")<1k=InStr(k+1,sTemp,"{if:")iDiv=InStr(iDiv+1,sTemp,"{/if}")If iDiv<1 Then cErr(12)Loopii=InStr(iDiv,sTemp,"{elseif:")End IfIf ii<1 TheniRtn=analyTpl(Mid(sTemp,iii+1))ElseiRtn=analyTpl(Mid(sTemp,iii+1,ii-2))End IfEnd IfEnd IfEnd IfEnd IfCase "fn"Set oAtt=analyLabel(sLabel)If oAtt.Exists("func") ThenSet k=GetRef(oAtt("func"))If oAtt.Exists("args") Thenii=Split(oAtt("args"),",")If oAtt.Exists("argtype") Theniii=Split(oAtt("argtype")&",,,,,",",")Elseiii=Split(",,,,,",",")End IfFor j=0 To UBound(ii)Select Case LCase(iii(5))Case "i"ii(j)=parseInt(ii(j))Case "f"If IsNumeric(ii(j)) Then ii(j)=CDbl(ii(j)) Else ii(j)=0Case "b"ii(j)=CBol(ii(j))Case Elseii(j)=decode(ii(j),True)End SelectIf j>4 Then Exit ForNextSelect Case UBound(ii)Case 0iRtn=k(sTemp,ii(0))Case 1iRtn=k(sTemp,ii(0),ii(1))Case 2iRtn=k(sTemp,ii(0),ii(1),ii(2))Case 3iRtn=k(sTemp,ii(0),ii(1),ii(2),ii(3))Case 4iRtn=k(sTemp,ii(0),ii(1),ii(2),ii(3),,ii(4))End SelectElseiRtn=k(sTemp)End IfiRtn=analyTpl(iRtn)End IfCase "for"Set oAtt=analyLabel(sLabel)If oAtt.Exists("var") And oAtt.Exists("to") ThenoAtt("to")=parseInt(oAtt("to"))If oAtt.Exists("from") Then oAtt("from")=parseInt(oAtt("from")) Else oAtt.Add "from",1If oAtt.Exists("step") Then k=ParseInt(oAtt("step")) Else k=1For j=ParseInt(oAtt("from")) To ParseInt(oAtt("to")) Step kk = Replace(sTemp,"{@"&oAtt("var")&"}",j)oReg.Pattern="(\{[^\{]+)@"&oAtt("var")&"([^\.\}]*\})"iRtn = iRtn & oReg.Replace(k,"$1"&j&"$2")NextiRtn=analyTpl(iRtn)End IfCase "foreach"Set oAtt=analyLabel(sLabel)If oAtt.Exists("var") And oAtt.Exists("name") ThenIf oData.Exists(oAtt("name")) ThenIf oType(oAtt("name"))=2 Or oType(oAtt("name"))=4 ThenFor Each j In oData(oAtt("name"))k=Replace(sTemp,"{@"&oAtt("var")&".name}",j)k=Replace(k,"{@"&oAtt("var")&".value}",j)oReg.Pattern="(\{[^\{]+)@"&oAtt("var")&"\.name([^\}]*\})"k = oReg.Replace(k,"\1"&j&"\2")oReg.Pattern="(\{[^\{]+)@"&oAtt("var")&"\.value([^\}]*\})"iRtn = iRtn & oReg.Replace(k,"$1"&oData(oAtt("name"))(j)&"$2")NextiRtn=analyTpl(iRtn)End IfEnd IfEnd IfCase "loop"Set oAtt=analyLabel(sLabel)If oAtt.Exists("name") ThenIf oData.Exists(oAtt("name")) ThenFor ii=1 To Len(sTemp)l=InStr(ii,sTemp,"{loopelse}")If l>0 TheniDiv=InStr(ii,sTemp,"{loop:")If iDiv>l Or iDiv<1 ThensTemp=Left(sTemp,l-1)&Replace(sTemp,"{loopelse}","{loopelseMARK}",l,1)Exit ForElseii=InStr(ii,sTemp,"{/loop}")Do Until iDiv<1If ii<1 Then cErr(13)iDiv=InStr(iDiv+1,sTemp,"{loop:")If iDiv>0 Then ii=InStr(ii+1,sTemp,"{/loop}")LoopEnd IfEnd IfNextIf oType(oAtt("name"))=3 ThenIf oAtt.Exists("limit") ThenIf InStr(oAtt("limit"),",")<1 Then oAtt("limit")="1,"&oAtt("limit")oAtt("limit")=Split(oAtt("limit"),",")oAtt("limit")(0)=parseInt(oAtt("limit")(0))k=parseInt(oAtt("limit")(1))Elsek=oData(oAtt("name")).RecordCountEnd IfIf oAtt.Exists("count") Then k=ParseInt(oAtt("count"))If k>100 Then k=100'最多输出100条iii=Split(sTemp&"{loopelseMARK}","{loopelseMARK}")If oData(oAtt("name")).EOF TheniRtn=iii(1)Elseii=oData(oAtt("name")).AbsolutePosition'记录rscordset起始位置If oAtt.Exists("limit") ThenIf oData(oAtt("name")).RecordCount>oAtt("limit")(0) ThenoData(oAtt("name")).AbsolutePosition=oAtt("limit")(0)ElseoData(oAtt("name")).AbsolutePosition=oData(oAtt("name")).RecordCountEnd IfEnd IfFor j=1 To kiRtn=iRtn & Replace(Replace(subReplace(iii(0),oData(oAtt("name")),oAtt("name")),"{@"&oAtt("name")&".@index}",j),"@"&oAtt("name")&".@index",j)oData(oAtt("name")).MoveNextIf oData(oAtt("name")).EOF Then oData(oAtt("name")).AbsolutePosition=ii:Exit ForNextEnd IfiRtn=analyTpl(iRtn)End IfEnd IfEnd IfCase "sql"Set oAtt=analyLabel(sLabel)If oAtt.Exists("name") And oAtt.Exists("table") ThenIf LCase(oAtt("table"))<>"admin" ThenFor ii=1 To Len(sTemp)l=InStr(ii,sTemp,"{sqlelse}")If l>0 TheniDiv=InStr(ii,sTemp,"{sql:")If iDiv>l Or iDiv<1 ThensTemp=Left(sTemp,l-1)&Replace(sTemp,"{sqlelse}","{sqlelseMARK}",l,1)Exit ForElseii=InStr(ii,sTemp,"{/sql}")Do Until iDiv<1If ii<1 Then cErr(14)iDiv=InStr(iDiv+1,sTemp,"{sql:")If iDiv>0 Then ii=InStr(ii+1,sTemp,"{/sql}")LoopEnd IfEnd IfNextSet k=New MakeSQLk.Table(oAtt("table"))If oAtt.Exists("field") Then k.field(Split(oAtt("field"),","))If oAtt.Exists("where") Then k.where(Array(decode(oAtt("where"),True)))If oAtt.Exists("limit") ThenIf InStr(oAtt("limit"),",")<1 Then oAtt("limit")="1,"&oAtt("limit")oAtt("limit")=Split(oAtt("limit"),",")k.limit oAtt("limit")(0),oAtt("limit")(1)End IfIf oAtt.Exists("order") Then k.order(Split(oAtt("order"),","))Set l=k.CreateSQL("select",True)iQuery=iQuery+1iii=Split(sTemp&"{sqlelseMARK}","{sqlelseMARK}")If l.EOF TheniRtn=iii(1)ElseIf oAtt.Exists("count") Then ii=ParseInt(oAtt("count")) Else ii=l.RecordCountIf ii>100 Then ii=100'最多输出100条For j=1 To iiiRtn=iRtn & Replace(Replace(subReplace(iii(0),l,oAtt("name")),"{@"&oAtt("name")&".@index}",j),"@"&oAtt("name")&".@index",j)l.MoveNextIf l.EOF Then Exit ForNextEnd IfiRtn=analyTpl(iRtn)End IfEnd IfCase ElseiRtn="{"End Select'sCont= Replace(sCont,"{"&sLbl&"}"&sTmp&"{/"&sTag&"}",iRtn)sCont= Left(sCont,i-1)& Replace(sCont,"{"&sLbl&"}"&sTmp&"{/"&sTag&"}",iRtn,i,1)i=i+Len(iRtn)Elsei=i+Len(sLabel)+1End Ifi=InStr(i,sCont,"{")LoopanalyTpl=sContEnd Function'获取obj健值Private Function getValue(sObj,sKey,sFlt)getValue=""Select Case sObjCase "query"getValue=Request.QueryString(sKey)Case "form"getValue=Request.Form(sKey)Case "cookie"getValue=Request.Cookies(sKey)Case "server"getValue=Request.ServerVariables(sKey)Case "session"getValue=Session(sKey)Case ElseIf oData.Exists(sObj) ThenIf oType(sObj)=2 ThenIf oData(sObj).Exists(sKey) Then getValue=oData(sObj)(sKey)ElseIf oType(sObj)=4 ThengetValue=oData(sObj)(sKey)ElseIf oType(sObj)=3 ThenIf Not IsEmpty(oData(sObj)(sKey)) Then getValue=oData(sObj)(sKey)End IfEnd IfIf IsNull(getValue) Then getValue=""End SelectIf sFlt<>"" ThengetValue=fmtVar(getValue,sFlt)End IfEnd Function'替换obj值Private Function subReplace(ByVal Tpl,obj,oName)Dim oMth,MatchoReg.Pattern="\{@"& oName &"\.([\w\d]+)((?:\|["& sFmt &"]+)*)?\}"Set oMth=oReg.Execute(Tpl)For Each Match In oMthIf Match.SubMatches.Count<2 ThenTpl=Replace(Tpl,Match.Value,obj(Match.SubMatches(0)))ElseTpl=Replace(Tpl,Match.Value,fmtVar(obj(Match.SubMatches(0)),Match.SubMatches(1)))End IfNext'替换标签内变量oReg.Pattern="\{[^{]+@"& oName &"\.([\w\d]+)[^}]*\}"Set oMth=oReg.Execute(Tpl)For Each Match In oMthTpl=Replace(Tpl,Match.Value,_Replace(Match.Value,"@"&oName&"."&Match.SubMatches(0),_obj(Match.SubMatches(0))))NextsubReplace=TplEnd Function'判断if条件Private Function judge(str)Dim oMth,a,b,cjudge=TrueoReg.Pattern="^\s*([\w\d]*)\s*(\=|\<|\>|\>=|\<=|\<\>|\!\=|\=\=)\s*([\w\d]*)\s*$"Set oMth=oReg.Execute(str)If oMth.Count<1 Thenjudge=CBol(str)Elsea=oMth(0).SubMatches(0)b=oMth(0).SubMatches(1)c=oMth(0).SubMatches(2)If (IsNumeric(a) Or a="") And (IsNumeric(c) Or c="") Thena=parseInt(a)c=ParseInt(c)End IfSelect Case bCase "=","=="If a<>c Then judge=FalseCase "<>","!="If a=c Then judge=FalseCase ">"If a<=c Then judge=FalseCase "<"If a>=c Then judge=FalseCase ">="If a<c Then judge=FalseCase "<="If a>c Then judge=FalseEnd SelectEnd IfEnd Function'格式化变量Private Function fmtVar(var,fmt)Dim iTmp,d,fiTmp=Split(fmt&"|||||","|")fmtVar=varSelect Case LCase(iTmp(1))Case "fmtdate"'格式化日期"YYYY"If IsDate(var) Thend=CDate(var)If LCase(iTmp(2))="kindly" Thenf = Replace(LCase(iTmp(2)),"kindly",FmtTime(d,False))Elsef = Replace(LCase(iTmp(2)),"yyyy",Year(d))f = Replace(f, "yy",Right(Year(d),2))f = Replace(f, "mm",Right("00"&Month(d),2))f = Replace(f, "m",Month(d))f = Replace(f, "dd",Right("00"&Day(d),2))f = Replace(f, "d",Day(d))f = Replace(f, "hh",Right("00"&Hour(d),2))f = Replace(f, "h",Hour(d))f = Replace(f, "nn",Right("00"&Minute(d),2))f = Replace(f, "n",Minute(d))f = Replace(f, "ss",Right("00"&Second(d),2))f = Replace(f, "s",Second(d))f = Replace(f, "www",weekdayname(weekday(d)))f = Replace(f, "ww",Right(weekdayname(weekday(d)),1))f = Replace(f, "w",weekday(d))End IffmtVar=fEnd IfCase "cutstr"d=parseInt(iTmp(2))fmtVar=CutString(fmtVar,d,iTmp(3))Case "lcase"fmtVar=LCase(fmtVar)Case "ucase"fmtVar=UCase(fmtVar)Case "fmtnum"iTmp(3)=ParseInt(iTmp(3))If iTmp(2)="1" ThenfmtVar=parseInt(fmtVar)If iTmp(3)=0 Or (iTmp(3)<Len(fmtVar) And CBol(iTmp(4))) Then iTmp(3)=Len(fmtVar)fmtVar=Right(String("0",iTmp(3))&fmtVar,iTmp(3))ElseIf iTmp(2)="2" ThenIf iTmp(3)=0 Or (iTmp(3)<Len(fmtVar) And CBol(iTmp(4))) Then iTmp(3)=Len(fmtVar)fmtVar=Left(fmtVar&String("0",iTmp(3)),iTmp(3))ElseIf iTmp(2)="3" ThenfmtVar=Hex(parseInt(fmtVar))If iTmp(3)=0 Or (iTmp(3)<Len(fmtVar) And CBol(iTmp(4))) Then iTmp(3)=Len(fmtVar)fmtVar=Right(String("0",iTmp(3))&fmtVar,iTmp(3))ElseIf iTmp(2)="4" ThenfmtVar=dHex(fmtVar)If iTmp(3)=0 Or (iTmp(3)<Len(fmtVar) And CBol(iTmp(4))) Then iTmp(3)=Len(fmtVar)fmtVar=Right(String("0",iTmp(3))&fmtVar,iTmp(3))End IfCase "nohtml"fmtVar=ReplaceTag(fmtVar)Case "html"fmtVar=HTMDecode(fmtVar)Case "escape"fmtVar=URLEncode(fmtVar)Case "unescape"fmtVar=URLDecode(fmtVar)Case "jscode"fmtVar=UTFEncode(fmtVar)Case "replace"fmtVar=Replace(fmtVar,iTmp(2),iTmp(3))Case "trip"fmtVar=html2txt(fmtVar)Case "filesize"fmtVar=convertSize(fmtVar)Case "url"fmtVar=HTMDecode(fmtVar)Case "default"If fmtVar="" Or IsEmpty(fmtVar) Or IsNull(fmtVar) Then fmtVar=iTmp(2)Case "iif"If CBol(fmtVar) ThenfmtVar=iTmp(2)ElsefmtVar=iTmp(3)End IfEnd SelectIf IsNull(fmtVar) Then fmtVar=""End Function'解析标签属性Private Function analyLabel(sCont)Dim oTag,oMatch,oMthSet oTag=Server.CreateObject("Scripting.Dictionary")oReg.Pattern="\b([\w\d]+)\s*=\s*(['""])([\w\d\-\,\.\s\%\=\<\>\$]+)\2"Set oMatch=oReg.Execute(sCont)For Each oMth In oMatchIf Not oTag.Exists(oMth.SubMatches(0)) ThenoTag.Add oMth.SubMatches(0),decode(oMth.SubMatches(2),False)End IfNextSet analyLabel=oTagSet oMatch=NothingEnd FunctionPrivate Function decode(str,deep)decode=strIf InStr(str,"%")<1 Then Exit Functiondecode=Replace(decode,"%22","""")decode=Replace(decode,"%27","'")If deep Thendecode=Replace(decode,"%2C",",")decode=Replace(decode,"%25","%")End IfEnd FunctionPrivate Function CheckPath(fPath)On Error Resume NextDim path,i,cpathcpath=""path=Split(Replace(Server.MapPath(fpath),"\","/"),"/")For i=0 To Ubound(path)If cPath="" ThencPath=path(i)ElsecPath=cPath & "/" & path(i)End IfIf Not oFso.FolderExists(cPath) ThenoFso.CreateFolder(cPath)End IfIf Err ThenErr.ClearcErr 31CheckPath=FalseEnd IfNextCheckPath=TrueEnd FunctionPrivate Function vType(obj)Select Case TypeName(obj)Case "Recordset"vType=3Case "Dictionary"vType=2Case "Variant()"vType=1Case ElseIf VarType(obj)=9 ThenvType=4ElsevType=0End IfEnd SelectEnd FunctionPrivate Sub cErr(Num)If IsNumeric(Num) ThenSelect Case NumCase 1:Die "模板不存在"Case 2:Die "标签不匹配"Case 3:Die "标签未闭合"Case 4:Die "标签嵌套错误"Case 12:Die "if标签未闭合"Case 13:Die "loop标签未闭合"Case 14:Die "sql标签未闭合"Case 15:Die "nocache标签未闭合"Case 16:Die "cache标签未闭合"Case 31:Die "创建文件夹失败,请检查权限"Case 32:Die "清除缓存失败,请检查权限"Case Else:Die "未知错误"End SelectElseDie Num&"标签未闭合"End IfEnd SubEnd Class
2 楼 sunwii 2011-10-23 来学习的.
代码行90:i=InStr(k,"<nocache>")是否是手误呢??有些看不明白了. 3 楼 sunwii 2011-10-23 另外,有没有示例的模板文件??可不可以发一份给我参考.谢谢.sunwii@qq.com 4 楼 shirne 2011-10-30 sunwii 写道另外,有没有示例的模板文件??可不可以发一份给我参考.谢谢.sunwii@qq.com
不好意思,最近比较忙,有时间我会整理出来,再告诉你. 5 楼 shirne 2011-10-30 sunwii 写道来学习的.
代码行90:i=InStr(k,"<nocache>")是否是手误呢??有些看不明白了.
谢谢您读代码这么认真,确实是写错了.
应该是 InStr(k,sHtm,"<nocache>")