拿youdiancms的channellist 来举例
<navigationlist id="n" channelid='$T4'>
<a class="a{$i}" href="{$n.ChannelUrl}" target="{$n.ChannelTarget}">
<li>
<div class="ChannelIcon"><img src="{$n.ChannelIcon}" title="{$n.ChannelName}" alt="{$n.ChannelName}" /></div>
<div class="ChannelName">{$n.ChannelName}</div>
</li>
</a>
</navigationlist>
参看thinkphp3.0的第13章
13.5.4 标签库驱动
系统的标签库驱动扩展目录位于Extend/Driver/TagLib目录下面,命名规范是:
TagLib+标签库名称(首字母大写)
目前已经提供了Html标签库驱动支持,标签库驱动扩展必须继承TagLib类,例如我们扩展一个Test标签库:
Class TagLibTest extends TagLib{}
首先需要定义标签库的标签定义,标签定义包含了所有标签库中支持的所有标签,定义方式如下:
protected $tags = array(
// 定义标签
'input'=>array('attr'=>'type,name,id,value','close'=>0), // input标签
);
在 App\Core\Extend\Driver\TagLib 里面有个
TagLibYouDian.class.php
那么这个标签库的名字就是YouDian
protected $tags=array(
'navigationlist' => array('attr'=>'id,channelid,channelmodelid,offset,length,key,mod,depth,empty,idlist,showhidden,field', 'level'=>4, 'alias'=>'channellist')
);
定义了一个自定义的标签 navigationlist 有很多属性 'attr'=>'id,channelid,channelmodelid,offset,length,key,mod,depth,empty,idlist,showhidden,field'
'level'=>4 嵌套级别
'alias'=>'channellist' 别名
现在要定义解析这个navigationlist的方法 标签的方法前面要加上 _
public function _navigationlist($attr, $content){
//首先通过parseXmlAttr来解析navigationlist得到tags所有属性
$tag = $this->parseXmlAttr($attr,'navigationlist');
$channelid = !empty($tag['channelid']) ? $tag['channelid'] : 0;
$channelmodelid = ( isset($tag['channelmodelid']) && is_numeric($tag['channelmodelid']) ) ? $tag['channelmodelid'] : -1;
$idlist = !empty($tag['idlist']) ? trim($tag['idlist']) : -1;
$id = $tag['id'];
$empty = isset($tag['empty'])?$tag['empty']:'';
$key = !empty($tag['key'])?$tag['key']:'i';
$mod = isset($tag['mod'])?$tag['mod']:'2';
$depth = isset($tag['depth']) ? $tag['depth'] : '1';
$offset = ( isset($tag['offset']) && is_numeric($tag['offset']) ) ? "offset='".$tag['offset']."'" : '';
$length = isset($tag['length']) ? "length='".$tag['length']."'" : '';
$showhidden = isset($tag['showhidden']) ? trim($tag['showhidden']) : 0; //默认不显示隐藏频道
$isshow = ($showhidden == 0) ? 1 : -1;
$field = !empty($tag['field']) ? trim($tag['field']) : '';
if('$' == substr($channelid, 0, 1)) {
$channelid = $this->autoBuildVar(substr($channelid,1));
}
if('$' == substr($channelmodelid, 0, 1)) {
$channelmodelid = $this->autoBuildVar(substr($channelmodelid,1));
}
if('$' == substr($idlist, 0, 1)) {
$idlist = $this->autoBuildVar(substr($idlist,1));
}
$parseStr = "<volist name=':get_navigation($channelid,$depth,\"$idlist\",$isshow,$channelmodelid,-1,\"$field\")' id='$id' empty=\"$empty\" key='$key' mod='$mod' $offset $length>$content</volist>";
return $parseStr;
}
('50','TAGLIB_PRE_LOAD','YouDian',NULL,'config','1','0')
在ThinkTemplate.class.php中的parse函数会处理 TAGLIB_PRE_LOAD
// 预先加载的标签库 无需在每个模板中使用taglib标签加载 但必须使用标签库XML前缀
if(C('TAGLIB_PRE_LOAD')) {
$tagLibs = explode(',',C('TAGLIB_PRE_LOAD'));
foreach ($tagLibs as $tag){
$this->parseTagLib($tag,$content);
}
}
模板中就可以使用 TagLibYouDian。不用再开头使用<taglib name='YouDian' />去申请了
就是说比如input 如果是需要解析为test的空间,那么就需要 <test:input 这样的标记
ThinkTemplate.class.php 解析模板 content
通过fetch函数取得文件
public function fetch($templateFile,$templateVar) {
$this->tVar = $templateVar;
$templateCacheFile = $this->loadTemplate($templateFile);
// 模板阵列变量分解成为独立变量
extract($templateVar, EXTR_OVERWRITE);
//载入模版缓存文件
include $templateCacheFile;
}
继续进入loadTemplate继续进入compiler进入parse 后优先先解析 TAGLIB_LOAD 再解析 TAGLIB_PRE_LOAD 这里就解析navigationlist 这里调用了TagLibYouDian.class.php 的_navigationlist函数
$parseStr = "<volist name=':get_navigation($channelid,$depth,\"$idlist\",$isshow,$channelmodelid,-1,\"$field\")' id='$id' empty=\"$empty\" key='$key' mod='$mod' $offset $length>$content</volist>";
解析出来以后 还不是已经处理好的纯html语言。而是带有内置volist的模板
接下来继续解析TAGLIB_BUILD_IN
// 内置标签库 无需使用taglib标签导入就可以使用 并且不需使用标签库XML前缀
$tagLibs = explode(',',C('TAGLIB_BUILD_IN'));
foreach ($tagLibs as $tag){
$this->parseTagLib($tag,$content,true);
}
最后解析tagName
//解析普通模板标签 {tagName}
$content = preg_replace('/('.$this->config['tmpl_begin'].')(\S.+?)('.$this->config['tmpl_end'].')/eis',"\$this->parseTag('\\2')",$content);
就是说是按次序来的。前面的解析可以返回 能让后面解析的标签语句。
_navigationlist里面的content就是 标签内部的内容
<a class="a{$i}" href="{$n.ChannelUrl}" target="{$n.ChannelTarget}">
<li>
<div class="ChannelIcon"><img src="{$n.ChannelIcon}" title="{$n.ChannelName}" alt="{$n.ChannelName}" /></div>
<div class="ChannelName">{$n.ChannelName}</div>
</li>
</a>
前面通过youdian的解析 navigationlist 变成了
volist name=":get_navigation(xxx xxx xxx)"这里就是通过 函数获取数据集
<volist name=':get_navigation($T4,1,"-1",1,-1,-1,"")' id='n' empty="" key='i' mod='2'>
<a class="a{$i}" href="{$n.ChannelUrl}" target="{$n.ChannelTarget}">
<li>
<div class="ChannelIcon">
<img src="{$n.ChannelIcon}" title="{$n.ChannelName}" alt="{$n.ChannelName}" />
</div>
<div class="ChannelName">{$n.ChannelName}</div>
</li>
</a>
</volist>
又变成了TP自己的的volist标签
name和id必选 name是模板变量, 一般是二维数组 id是循环变量 key是当前的key变量从1开始递增
进入volist的content是
<a class="a{$i}" href="{$n.ChannelUrl}" target="{$n.ChannelTarget}">
<li>
<div class="ChannelIcon"><img src="{$n.ChannelIcon}" title="{$n.ChannelName}" alt="{$n.ChannelName}" /></div>
<div class="ChannelName">{$n.ChannelName}</div>
</li>
</a>
解析以后是
<?php
$_result=get_navigation($T4,1,"-1",1,-1,-1,"");
if(is_array($_result)):
$i = 0;
$__LIST__ = $_result;
if( count($__LIST__)==0 ) :
echo "" ;
else:
foreach($__LIST__ as $key=>$n):
$mod = ($i % 2 );++$i;
?>
<a class="a<?php echo ($i); ?>" href="<?php echo ($n[" ChannelUrl"]); ?>" target="
<?php echo ($n["ChannelTarget"]); ?>">
<li>
<div class="ChannelIcon"><img src="<?php echo ($n[" ChannelIcon"]); ?>" title="
<?php echo ($n["ChannelName"]); ?>" alt="
<?php echo ($n["ChannelName"]); ?>" /></div>
<div class="ChannelName">
<?php echo ($n["ChannelName"]); ?>
</div>
</li>
</a>
<?php
endforeach;
endif;
else:
echo "" ;
endif;
?>
经过整理以后是下面的样子
$_result=get_navigation($T4,1,"-1",1,-1,-1,"");
if(is_array($_result))
{
$i = 0;
$__LIST__ = $_result;
if( count($__LIST__)==0 )
{
echo "" ;
}
else
{
foreach($__LIST__ as $key=>$n)
{
$mod = ($i % 2 );++$i;
/*content部分开始*/
<a class="a<?php echo ($i); ?>" href="<?php echo ($n[" ChannelUrl"]); ?>" target="
<?php echo ($n["ChannelTarget"]); ?>">
<li>
<div class="ChannelIcon"><img src="<?php echo ($n[" ChannelIcon"]); ?>" title="
<?php echo ($n["ChannelName"]); ?>" alt="
<?php echo ($n["ChannelName"]); ?>" />
</div>
<div class="ChannelName">
<?php echo ($n["ChannelName"]); ?>
</div>
</li>
</a>
/*content部分结束*/
}
}
else{
echo "" ;
}
youdian所有的channel都再youdian_channel数据库内
通过get_navigation取得了 ParentID为23的所有子id 然后输出了样式