分类:
2008-05-29 22:18:44
前段时间,一直比较关心PHP的模板技术的我,接到了客户的要求:全站利用模板技术,可以控制多模板,这个项目要求有强大的后台,主要是多模板,难点就在模板的导入和识别并且生成上,我仔细考察了PHP的模板核心技术,无外乎查找字符串开始,然后定义替换变量,替换成数据,然后并成输出页输出,牵扯到的缓存我就不再说了.
我们来看看这种方式的生成方式的缺点:如果要"多样式"的显示数据,当然我先不说CSS,不能真正的把数据和表示分离,无外乎利用CSS样式表方式显示而已,我们现在接到的这个项目不但要求CSS样式表的可选化,而且要求数据显示的"多方式",打个比方,看下图:
我们下面为了容易描述期间,我这样表示各个部分:A,B,C,D,E,F,G这6个区可以表示数据显示区域,从设计者角度考虑,有全局(div控制A-G),TOP(A),LEFT(B),RIGHT(C,D,E,F)和FOOTER(G),当然,您可以分的更细一些,这么显示,可以用div控制的,但这不是模板技术,请明白,多样式表不叫模板,这和模板无关,所谓的模板,就是只与"数据布局"相关,在A数据我们另外可以表示成一个导航,如果您喜欢的话.这在传统的模板技术中会这样写:
...
{$SITE_TOP$}//cjjer制作
...
替换的时候replace()的是{$ 和$}符号中的变量,这在数据简单的时候,比方只是一个导航,而我们如果要的是一个很复杂的数据显示的时候,那就很难控制了,因为把一个很大量输出数据放在一个变量中很难保证不出错.
另外,传统的模板(在PHP中)是这样的,获取模板的文件,加载,显示,这没什么问题,问题就在当web项目(不完全是网站)非常复杂的时候,很容易替换错误和模板单调,虽然可以用CSS控制一些显示,但很难控制数据的布局,比方,E区我今天不想要了,你改模板,重新加载文件... ?
有没有更加容易的解决方案?有.
我提出了这样一种观点:
模板页为 XML文档 ,模板节点加载已有模块 ,加载"仿XML数据"生成文件 (原谅我,这么说我觉得已经非常容易了)下面我就这种模板技术详谈.
先看看我说的模块是什么东西,大家都知道,HTML中的
以下为引用的内容: &%format%& |
这里我把这个模板节点定义成 加载控制全局的HTML源了,再看这个标签topdata:
如果这个节点被加载,生成的文件里面会将topdata节点替换成如上的HTML文档模板,这就是模块
这里的模块也可以是XML文档,重复加载模块,也可以是终数据.
当这些还有模块节点的XML模板被加载以后,就被程序识别,对应的加载成HTML二级模块,然后提出我们的"仿XML 数据"标记中的数据,正则替换对应的节点,生成文件,这里的"仿XML数据"是这种方式的数据:
以下为引用的内容: {%TITLE%}<%=cjjer_hometitle%>{%/TITLE%} |
这里,您可能马上理解了我说的"仿XML数据"了,这种加载数据的方式也是XML分析节点,然后直接正则替换,当然可以include文件的(ASP,PHP).
好了,现在您想必概念已经很清楚了,(不清楚的话重新看上面的话,或看如下的例子)
我就举个举个简单的例子说明一下(format_index.XML):
以下为引用的内容:
|
模块:
//format,就是最上面的那个,不列举了 //home_bigFlash //format_two //site_footer
以下为引用的内容:
差不多应该加载的模板和模块就这点吧(都是可以重用的.)
现在是程序处理:
<% '匹配模板中的数据项 Dim Matches,Match 'geturlXML 传入参数模板名称,返回模板的内容,失败的时候返回 null public Function gettpldata(url,mode) Function update_ASPfile(id)
以下为引用的内容:
'根据输入判断输出是名称还是数据
Function geturlXML(outfile,mode)
geturlXML=False
If outfile="" Then Exit Function
Dim tab
Select Case killint(mode,0,0,2)
Case 0:tab="szd_tpl"
Case 1:tab="szd_content"
End Select
Set rs=conn.execute("select ["&tab&"] FROM szd_ASP where [szd_link]='"&outfile&"'")
If rs.eof And rs.bof Then
Exit Function
else
geturlXML=rs(tab)
End If
End Function
'提取include文件到原始的数据项中
Function getincludefile(x)
Dim regXML,HTML
HTML=""
Set regXML=new regexp
regXML.ignorecase=True
regXML.global=True
regXML.pattern="()"
Dim Matches,Match
Set Matches = regXML.Execute(x)
For Each Match in Matches
HTML=HTML&match.value
Next
getincludefile=HTML
End Function
'获取模板项,先判断输出,返回值是 HTML 形式的模板,参数是模板的名称
Function gettpl(url)
Dim mudule_file,XML_file,ASP_file
XML_file=url
ASP_file=gettpldata(XML_file,0)'由模板名称获取模板的内容
Dim loadXML,parseXML,nodes,node
Set loadXML = Server.CreateObject("MSXML2.DOMDocument")
loadXML.async=false
parseXML=server.mappath("../"&gettpldata(XML_file,10)&XML_file)'装载本地的XML文档,先到数据库取到路径
loadXML.load parseXML
Set nodes = loadXML.selectNodes("//*")
for each node in nodes
ASP_file=insertASPinHTML(ASP_file,gettpldata(node.nodename,1),node.nodename)'加载模块到模板,输出HTML模板
Next
gettpl=ASP_file
End function
'把data中的数据传入HTML文件当中去
Function tpltodata(HTML,data)
Dim regXML
Set regXML=new regexp
regXML.ignorecase=True
regXML.global=True
regXML.pattern="({%)([a-zA-Z][A-Za-z0-9_]{2,60})(%})(.[^\[]*)({%/)\2(%})"
Set Matches = regXML.Execute(data)
For Each Match in Matches
HTML=Replace(HTML,"{%"®XML.Replace(match.value,"$2")&"%}",regXML.Replace(match.value,"$4"))
Next
tpltodata=HTML
End Function
Function geturlXML(outfile)
geturlXML=Null
If outfile="" Then Exit Function
Set rs=conn.execute("select [szd_tpl] FROM szd_ASP where [szd_link]='"&outfile&"'")
If rs.eof And rs.bof Then
Exit Function
else
geturlXML=rs("szd_tpl")
End If
End Function
'Set rs=server.CreateObject("server.adodbrecordset")
If Len(url)<1 Then Exit Function
Dim szd_keytpl
Select Case mode
Case 0:Set rs=conn.execute("select [szd_content] from szd_tpl where [szd_link]='"&url&"'")
Case 10:Set rs=conn.execute("select [szd_url] from szd_tpl where [szd_link]='"&url&"'")
Case 1:Set rs=conn.execute("select [szd_content] from szd_keytpl where [szd_key]='"&url&"'")
End Select
If Not(rs.eof And rs.bof) Then
szd_keytpl=rs(0)
Else
szd_keytpl="
End If
gettpldata=szd_keytpl
End Function
'加载标记的模块到 XML 格式的模板中,输出HTML格式的模板,ASP:XML格式模板,HTML:导入的模块,XMLs:当前标记
Function insertASPinHTML(ASP,HTML,XMLs)
Dim regXML,temp,temps,tempASP,tempASP_e
Set regXML=new regexp
regXML.ignorecase=True
regXML.global=True
regXML.pattern="(\<"&XMLs&"\>)(.[^\[]*)(\<\/"&XMLs&"\>)"
temp=regXML.Replace(ASP,"$2")
Dim Matches,Match
Set Matches = regXML.Execute(ASP)
For Each Match in Matches
HTML=Replace(HTML,"(&"&XMLs&"&)",regXML.Replace(match.value,"$2"))
ASP=Replace(ASP,Match.Value,HTML)
next
temps=Replace(HTML,"(&"&XMLs&"&)",temp)
insertASPinHTML=ASP
End Function
Dim update_ASPfile_return
update_ASPfile_return=False
id=killint(id,0,0,14)
If id=0 Then Exit Function
Set rs=conn.execute("select [szd_level],[szd_content],[szd_tpl],[szd_link] from szd_ASP where id="&id&"")
If rs.eof And rs.bof Then Exit Function
Dim tpl_level,tpl_content,tpl_tpl,HTML_content,ASP_file_now
tpl_level=rs(0)
tpl_content=rs(1)
tpl_tpl=rs(2)
ASP_file_now=rs(3)
If Len(tpl_tpl)<4 Or tpl_level=1 Or IsNull(tpl_tpl) Then
HTML_content=tpl_content
Else
HTML_content=gettpl(tpl_tpl)
If Not isnull(HTML_content) Then
HTML_content=getincludefile(tpl_content)&tpltodata(HTML_content,tpl_content)
'response.write("
"&server.HTMLencode(getincludefile(tpl_content))&"
")
Else
HTML_content=tpl_content
'response.write("
"&server.HTMLencode(HTML_content)&"
")
End If
End If
If writeto("../",ASP_file_now,HTML_content,2) Then update_ASPfile_return=True
update_ASPfile=update_ASPfile_return
End Function
%>
生成文件:
运行代码框
[Ctrl+A 全部选择 提示:你可先修改部分代码,再按运行]
这里,我的模块用了div,是利于样式表的使用.
主要思路如图:
其他的就不再说了,不知道说明白了.