将ASP原生代码编译生成静态类
老早就说放弃ASP了,但这段时间以来因为工作需要,始终放不下。这不,最近又写了个东西出来,分享一下。
这个标题有点纠结,实在不知道该起个什么名字。功能上来讲,它是将原生的ASP代码编译后返回ASP执行的结果,这个结果就是打开ASP页面看到的html代码,写这个功能是忽然想到可以借这个方法生成静态,不必创建一个XMLHttp请求对原生的ASP实施静态生成
将这些文件解压到一个文件夹内
可以在浏览器访问到的
1.访问Test.asp,这个结果为直接运行ASP文件的结果
2.访问CompileTest.asp 这个结果为编译ASP文件后输出的结果,并且可以生成静态文件
用途:
1.用于ASP编写的页面生成静态
相对于传统方法生成静态文件需要用到XMLHttp组件,从外部网络访问获取到内容,再创建文件
最重要的是减少了网络延迟,解决了部分服务器不支持组件,或者不支持自身的WEB访问
对服务器压力是否有减少并没有做过测试,理论上说这种方式只是一个会话就可以生成文件,传统的方式要从web访问,至少增加了一倍的会话量
2.用于ASP模板套用及解析
ASP在这方面一直是弱项,也有不少成熟的模板引擎,但有一大部分是编译型,而不是解释型,编译型模板引擎是将ASP模板代码编译成原生的ASP代码,再执行。我之前也发布过一个解释型模板引擎,自己还是比较满意的,但不方便的是使用的人,需要另外学习模板语法,虽然简单,对于不熟悉程序的设计师来说,不如懂一点ASP就好的
必要文件:
xCompile.Class.asp
xDictionary.Class.asp
其它均为测试用文件
需要注意的问题:
1.设定好预包含文件和忽略文件
预包含文件为必须的功能性文件,不包含任何html代码输出,一般是类集或函数集
忽略的文件一般是当前的文件已经包含过的文件
2.参数问题
只考虑了Request.QueryString参数,并且只支持编译文档内的参数
不支持函数中的参数
3.其它问题欢迎反馈至 shirne@126.com
测试代码:
<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%> <!--#Include file="xDictionary.Class.asp"--> <!--#Include file="xCompile.Class.asp"--> <% Dim C Set C=New xCompile '//这个文件会被预先运行,文件路径写法不重要,比较时是按实际磁盘路径比较的 C.AddInclude "TestFunctions.asp" '//ASP中调用到这个函数的地方会被替换成字符串连接 C.AddOutFun "Echo" C.Param("param")="这是传过去的参数" '//编译文件 C.Compile "Test.asp" C.Clear '//保存编译后的文件到内容 C.SaveTo "index.html" '//输出编译后的内容 Response.Write C %>
原代码如下(老规矩,里面的一些关键字因服务器禁止,替换了个中文字符):
'+++++++++++++++++++++++++++++++++++ 'ASP编译类 '可按设定直接将ASP文件编译运行返回结果 '在原生ASP中用来生成静态文件,而不采用获取Http页面的方法 'shirne@126.com 'http://www.shirne.com '+++++++++++++++++++++++++++++++++++ Class xCompile Private Includes '预包含文件 Private Ignores '忽略的包含文件 Private OutFun '输出函数 Private strHtml '最终的HTML字符串 Private Params '参数,仅支持QueryString参数,生成静态不建议使用其它参数 Private FuncStr '定义的全局函数名 Private Classes '已加载的类列表,ASP中类不能重复加载 Private Prepared Private Sub Class_Initialize OutFun = Array("Response.Write") FuncStr = "Outer__Html__Str" Set Classes=Server.CreateObject("Scripting.Dictionary") Classes.CompareMode=1 Set Params=new xDictionary Params.Init Request.QueryString Prepared = -1 End Sub Private Sub Class_Terminate Classes.RemoveAll Set Classes= Nothing Set Params = Nothing End Sub Public Default Property Get Html Html = strHtml End Property '主要动作是处理预包含文件 Public Property Get Prepare If IsArray(Includes) Then Dim i,L:L=UBound(Includes) If Prepared>=L Then Exit Property For i=Prepared+1 To L Require Includes(i) Next Prepared = L End If End Property '添加/获取参数 Public Property Let Param(key, val) Params.Replace key,val End Property Public Property Get Param(key) Param = Params(key) End Property '添加预包含文件 Public Sub AddInclude( File) Includes = Merge(Includes,CheckTruePath(File)) End Sub '添加忽略文件 Public Sub AddIgnore( File) Ignores = Merge(Ignores,CheckTruePath(File)) End Sub '添加输出函数 Public Sub AddOutFun( Fun) OutFun = Merge(OutFun,Fun) End Sub '保存 Public Sub SaveTo( path) WriteFile path, strHtml End Sub '检查是否磁盘路径,返回磁盘路径,可接收数组 Private Function CheckTruePath( obj) If IsArray(obj) Then Dim i For i=0 To UBound(obj) If InStr(obj(i),":")<1 Then obj(i) = Server.MapPath(obj(i)) End If Next CheckTruePath = obj Else obj = obj&"" If InStr(obj,":")>0 Then CheckTruePath = obj Else If obj<>"" Then CheckTruePath = Server.MapPath(obj) End If End If End Function '编译文件 Public Sub Compile(File) '读取文件内容 strHtml = ReadFile(File) If strHtml="" Then Exit Sub End If '包含文件 strHtml = Include(strHtml,File) '去除页面指令 strHtml = RegReplace("<%@[^>]+%\>",strHtml,"") Dim arrHtml, i, j, k, l i = InStr(strHtml,"<%") If i>0 Then '存在ASP标签,则逐个解析 ReDim arrHtml(0) j = 0 k = 1 Do Until i<1 l = InStr(i+1,strHtml,"%\>") If l<1 Then Err.Raise 7,"ASP语法错误,不正确的闭合标签" ReDim Preserve arrHtml(j+1) arrHtml(j) = FuncStr &" = "& FuncStr &" &"""&EscapeHtml(Mid(strHtml,k,i-k))&"""" arrHtml(j+1)=Mid(strHtml,i+2,l-i-2) If Left(arrHtml(j+1),1)="=" Then arrHtml(j+1) = FuncStr &" = "& FuncStr &" &"& EscapeAsp(Mid(arrHtml(j+1),2)) Else arrHtml(j+1) = EscapeAsp(arrHtml(j+1)) End If j = j + 2 k = l + 2 i = InStr(l+1,strHtml,"<%") Loop '最后的html内容 ReDim Preserve arrHtml(j) arrHtml(j) = FuncStr &" = "& FuncStr &" &"""&EscapeHtml(Mid(strHtml,l+2))&"""" strHtml = Join(arrHtml,vbCrLf) '过滤类 strHtml = FilterClass(strHtml) '过滤Sub strHtml = FilterSub(strHtml) '过滤Function strHtml = FilterFunction(strHtml) '执行预包含文件 PrePare 'Response.Write "Function "& FuncStr &"(Param)" & vbCrLf & strHtml & vbCrLf &"End Function" ExecuteGlobal "Function "& FuncStr &"(Param)" & vbCrLf & strHtml & vbCrLf &"End Function" strHtml = Eval(FuncStr&"(Params)") End If End Sub '清理处理后的内容 Sub Clear Dim i strHtml = xTrim(strHtml,Chr(32)&Chr(9)&Chr(10)&Chr(13)) '清理多余的空格 i = InStr(strHtml,Chr(32) & Chr(32)) While i>0 strHtml = Replace(strHtml,Chr(32) & Chr(32),Chr(32)) i = InStr(strHtml,Chr(32) & Chr(32)) Wend '清理多余的空行 i = InStr(strHtml,vbCrLf & vbCrLf) While i>0 strHtml = Replace(strHtml,vbCrLf & vbCrLf,vbCrLf) i = InStr(strHtml,vbCrLf & vbCrLf) Wend End Sub Private Function Require(File) Dim html, absPath html = ReadFile(File) absPath = Mid(File,Len(Server.MapPath("/"))) html = Include(html,absPath) Dim arrHtml, i, j, k, l i = InStr(html,"<%") If i>0 Then '存在ASP标签,则逐个解析,否则忽略该文件 ReDim arrHtml(0) j = 0 k = 1 Do Until i<1 l = InStr(i+1,html,"%\>") If l<1 Then Err.Raise 7,"ASP语法错误,不正确的闭合标签" ReDim Preserve arrHtml(j+1) arrHtml(j) = "" '忽略所有非asp内容 arrHtml(j+1)=Mid(html,i+2,l-i-2) j = j + 2 k = l + 2 i = InStr(l+1,html,"<%") Loop ExecuteGlobal Join(arrHtml,vbCrLf) End If End Function Private Function EscapeHtml( html) If InStr(html,"""")>0 Then html = Replace(html,"""","""""") If InStr(html,vbCrLf)>0 Then html = Replace(html,vbCrLf,"""& vbCrLf &""") If InStr(html,Chr(10))>0 Then html = Replace(html,Chr(10),"") If InStr(html,Chr(13))>0 Then html = Replace(html,Chr(13),"") 'If InStr(html,"&""""&")>0 Then html = Replace(html,"&""""&","&") EscapeHtml = Replace(html,Chr(0),"") End Function Private Function EscapeAsp( html) Dim i For i=0 To UBound(OutFun) If InStr(1,html,OutFun(i),1)>0 Then html = RegReplace("\b"& OutFun(i) &"\b",html,FuncStr &" = "& FuncStr &" &") End If Next If InStr(1,html,"Request.QueryString(",1)>0 Then html = RegReplace("\bRequest\.QueryString\(",html,"Param(") End If EscapeAsp = html End Function '包含入文件 Private Function Include(html,ByVal path) Dim Matches,Match,iHtml, iPath, oHtml, lastIndex Set Matches=REObject("<!--\s*#include\s+(file|virtual)=""([^*?<>=:""|]+)""\s*-->","gi").Execute(html) If Matches.Count>0 Then lastIndex = 1 For Each Match In Matches oHtml = oHtml & Mid(html,lastIndex,Match.FirstIndex+1-lastIndex) If StrComp(Match.SubMatches(0),"file",1)=0 Then iPath = getDir(path) & Match.SubMatches(1) ElseIf StrComp(Match.SubMatches(0),"virtual",1)=0 Then iPath = Match.SubMatches(1) Else iPath = "" End If If CheckNeedInclude(iPath) Then iHtml = ReadFile(iPath) iHtml = Include(iHtml,iPath) oHtml = oHtml & iHtml End If lastIndex = Match.FirstIndex+Match.Length+1 Next oHtml = oHtml & Mid(html, lastIndex) Include = oHtml Else Include = html End If End Function '检查是否需要包含 Private Function CheckNeedInclude(ByVal path) CheckNeedInclude = True If path="" Then CheckNeedInclude = False:Exit Function path = CheckTruePath(path) Dim i '先检查预包含文件 If IsArray(Includes) Then For i=0 To UBound(Includes) If StrComp(Includes(i),path,1)=0 Then CheckNeedInclude = False Exit Function End If Next End If '再检查忽略含文件 If IsArray(Ignores) Then For i=0 To UBound(Ignores) If StrComp(Ignores(i),path,1)=0 Then CheckNeedInclude = False Exit Function End If Next End If End Function Private Function FilterClass( html) Dim Matches,Match,ClassName,oHtml,LastIndex Set Matches=REObject("\bClass\s+([\w\d\_]+)\b[\s\S]+?\bEnd\s+Class\b","ig").Execute(html) If Matches.Count>0 Then LastIndex = 1 For Each Match In Matches oHtml = oHtml & Mid(html,LastIndex,Match.FirstIndex+1-LastIndex) ClassName = Match.SubMatches(0) If Classes.Exists(ClassName)=False Then '直接执行类代码,没有处理类内部的属性,函数等功能的输出,尽量事先处理好 ExecuteGlobal Match.Value Classes.Add ClassName,1 End If LastIndex = Match.FirstIndex+Match.Length+1 Next oHtml = oHtml & Mid(html, lastIndex) FilterClass = oHtml Else FilterClass = html End If End Function Private Function FilterSub( html) Dim Matches,Match,SubName,SubStr,oHtml,LastIndex Set Matches=REObject("\bSub\s+([\w\d\_]+)\b[\s\S]+?\bEnd\s+Sub\b","ig").Execute(html) If Matches.Count>0 Then LastIndex = 1 For Each Match In Matches oHtml = oHtml & Mid(html,LastIndex,Match.FirstIndex+1-LastIndex) SubName = Match.SubMatches(0) SubStr = Match.Value '这里替换没有排除字符串内部的关键字 SubStr = RegReplace("\bSub\b",SubStr,"Function") '将Sub替换成Function ExecuteGlobal RegReplace("\b"& FuncStr &"\b",SubStr,SubName) LastIndex = Match.FirstIndex+Match.Length+1 Next oHtml = oHtml & Mid(html, lastIndex) FilterSub = oHtml Else FilterSub = html End If End Function Private Function FilterFunction( html) Dim Matches,Match,FunctionName,FunctionStr,oHtml,LastIndex Set Matches=REObject("\bFunction\s+([\w\d\_]+)\b[\s\S]+?\bEnd\s+Function\b","ig").Execute(html) If Matches.Count>0 Then LastIndex = 1 For Each Match In Matches oHtml = oHtml & Mid(html,LastIndex,Match.FirstIndex+1-LastIndex) FunctionName = Match.SubMatches(0) FunctionStr = Match.Value '这里替换没有排除字符串内部的关键字,函数名起特殊一点一般可以避免 ExecuteGlobal RegReplace("\b"& FuncStr &"\b",FunctionStr,FunctionName) LastIndex = Match.FirstIndex+Match.Length+1 Next oHtml = oHtml & Mid(html, lastIndex) FilterFunction = oHtml Else FilterFunction = html End If End Function End Class这里是我用到的版本的原代码,下面这个压缩包里与这个代码有点差别,就是将类中用到的几个常用函数也封装进来了,方便大家测试,另外还有一个里面用到的xDictionary类
注:改善后的新版地址:解析原生ASP代码的模板引擎(完善版)