(转)浅谈dedecms模板引擎工作原理及自定义标签

理解织梦模板引擎有什么意义?一方面可以更好地自定义标签。更多在于了解织梦系统,理解模板引擎是理解织梦工作原理的第一步。理解织梦会使我们写php代码时更顺手,同时能学习一些php代码的组织方式。

这似乎不是那么简单,如果你只想学习自定义标签,可以看一下“是否需要自定义标签”和““扩展标签””就够了。

一解析式引擎

如果你还没用过dedecms的标签,先用一下,也可以看一下“dedecms网页模板编写”。熟悉一下memberlist这个标签,下面会以这个标签为例。

织梦提供的模板分析引擎有解析式和编译式两种,由于现在主要使用前者,这里也只讨论前者。

先来写个模板解析的hello world 程序

***root/test.php  封面php(root指的是根目录,以下都假设dedecms被放在了网站的根目录)

<?php
    require_once (dirname(__file__).‘/include/common.inc.php‘);
    //利用解析式模板所需的文件
    require_once (dirname(__file__).‘/include/dedetag.class.php‘);

//生成解析模板引擎类对象
$dtp=new DedeTagParse();
//设置命名空间,由于下面的标签用tianya命名空间,所以要设置一下。
$dtp->SetNameSpace(‘tianya‘);
$dtp->LoadTemplate(dirname(__file__).‘\test.tpl.htm ‘);

//把标签替换成具体的值
foreach ($dtp->CTags as $id=>$tag)
{
    if($tag->GetName()==‘my‘)
        //把id为$id的tag翻译成这是my标签<br/>
        $dtp->Assign($id,‘这是my标签<br/>‘);
    else if($tag->GetName()==‘test‘)
        $dtp->Assign($id,‘这是test标签<br/>‘);
}

//把解析好的html文本echo出来
$dtp->Display();
?>

***root/test.tpl.htm 网页模板

    {tianya:my att1=1 att2=‘2‘}
        [field:my/]
    {/tianya:my}
    {tianya:test att1=1 att2=‘2‘}
        [field:test/]
    {/tianya:test}

执行root/test.php就能查看结果

由上面的例子可以看出解析式模板运作的套路

1php文件调用网页模板,并显示。

2htm文件提供网页的大体框架,等待数据来完善网页的具体内容,称为网页模板。

上面的代码就是把第一个标签(my标签)显示为这是my标签<br/>;第二个标签显示为这是test标签<br/>。

上面的代码是怎么办妥的

更改***root/test.php如下

<?php
    require_once (dirname(__file__).‘/include/common.inc.php‘);
    //利用解析式模板所需的文件
    require_once (dirname(__file__).‘/include/dedetag.class.php‘);

$dtp=new DedeTagParse();
//设置命名空间,由于下面的标签用tianya命名空间,所以要设置一下。
$dtp->SetNameSpace(‘tianya‘);
$dtp->LoadTemplate(dirname(__file__).‘\test.tpl.htm ‘);
var_dump($dtp);    //这是查看解析结果的重要方法
?>

***root/test.tpl.htm 网页模板

    {tianya:my att1=1 att2=‘2‘}
        [field:my/]
    {/tianya:my}
    {tianya:test att1=1 att2=‘2‘}
        [field:test/]
    {/tianya:test}

可以看到$dtp对象的内部结构,其中有一个DedeTag类的数组CTagsDedeTag类的定义见root/include/ dedetag.class.php。最好不要直接用DedeTag类的字段,而用DedeTag提供的函数。比如用tag1->GetName()而不是用tag1->TagName。花一小段时间就能把DedeTag类看完,这些语法在以后自定义标签时会有用。

再看一个例子,***root/test.php

<?php
    require_once (dirname(__file__).‘/include/common.inc.php‘);
    require_once (dirname(__file__).‘/include/dedetag.class.php‘);

function lib_my($att1,$att2)
{
    return ‘这是my标签<br/>属性值‘.$att1.$att2.‘<br/>‘;
}

$dtp=new DedeTagParse();
$dtp->SetNameSpace(‘tianya‘);
$dtp->LoadTemplate(dirname(__file__).‘\test.tpl.htm‘);

foreach ($dtp->CTags as $id=>$tag)
{
    if($tag->GetName()==‘my‘)
$dtp->Assign($id , lib_my($tag->GetAtt(‘att1‘),$tag->GetAtt(‘att2‘)));
}

$dtp->Display();
?>

***root/test.htm 网页模板

    {tianya:my att1=1 att2=‘2‘}
        [field:my/]
    {/tianya:my}
    {tianya:test att1=1 att2=‘2‘}
        [field:test/]
    {/tianya:test}

会发现模板解析中有四种“势力”

在include/ DedeTagParse.class.php中定义的解析引擎类,负责读取模板,把其中的dedecms标签替换成具体html文本。DedeTagParse、SetNameSpace、LoadTemplate就是类里面的方法。

标签翻译需要一些转换规则,lib_my就是这一类根据标签的属性和具体数据得出html。

待显示的php创建编译引擎类对象,对模板进行编译,在Display时,echo出html文件。

htm模板,调用标签,用html的形式写出动态网页的效果,属于被翻译的部分。Html模板主要负责界面层次,利用封装好的标签进行内部处理。

除了这四大势力,还有一个势力视图类。include/中以arc开头的文件都是解析引擎的视图类。视图类就是封装了解析引擎类的类,仅仅加了一些函数而已。在下载的cms默认模板中,root/index.php就用了PartView这个视图类,解析了templets/default/index.htm。五大势力的关系如下图。

我们现在想象一个标签如何被解析的。我们知道,一个xml标签有四个元素:命名空间(上面的tianya,在dedecms中是dede)、标签名(my)、属性(att)、InnerText(标签之间的内容)。命名空间在SetNameSpace中指明了,标签名由if($tag->GetName()==‘my‘)这一句分配任务,属性作为函数参数使用,就差InnerText的处理。

再来看看如何处理底层模板字段([field:my/]等,field是一个关键字,在实际应用中,常常是数据库元组中的字段)

***root/test.php

<?php
    require_once (dirname(__file__).‘/include/common.inc.php‘);
    require_once (dirname(__file__).‘/include/dedetag.class.php‘);

//看完后面的代码再来看这个函数
function lib_zoo(&$ctag)
{
    //还记得刚才$dtp->CTags的结构吗?这里把$ctag作为参数传递,lib__zoo外面的代码就不用涉及太多的标签处理了
    $reval=‘这是my标签<br/>属性值‘. $ctag->GetAtt(‘att1‘).$ctag->GetAtt(‘att2‘).‘<br/>‘;
$innerText = $ctag->GetInnerText();

//底层模板字段的结构都形如[field:XX]这里把它看作以field为命名空间,[]为分隔符的标签。
    $dtp=new DedeTagParse();
    $dtp->SetNameSpace(‘field‘,‘[‘,‘]‘);
    $dtp->LoadSource($innerText);

    //不妨把$row想想成从数据库中读取出来的出来的数据
    $row[‘name’]= ‘Snoopy‘;
    $row[‘animal’]= ‘dog‘;

    //把标签替换成具体的值
    foreach ($dtp->CTags as $id=>$tag)
    {
        if($tag->GetName()==‘name‘)
            $dtp->Assign($id, $row[‘name’]);
        else if($tag->GetName()==‘animal‘)
            $dtp->Assign($id, $row[‘animal’]);
    }
    $reval.=$dtp->GetResult().‘<br/>‘;
    return $reval;
}

$dtp=new DedeTagParse();
$dtp->SetNameSpace(‘tianya‘);
$dtp->LoadTemplate(dirname(__file__).‘\test.htm‘);

foreach ($dtp->CTags as $id=>$tag)
{
    if($tag->GetName()==‘zoo‘)
    $dtp->Assign($id, lib_zoo($tag));
}

$dtp->Display();
?>

***root/test.htm

{tianya:zoo att1=1 att2=‘2‘}
     [field:name/] is a [field:animal/]
{/tianya:zoo}

可见,解析底层模板和解析标签是一样的,只不过把底层模板当作是以field为命名空间,‘[’和‘]’为边界的标签而已。

接着看一下include/taglib/memberlist.lib.php,和lib_zoo很像吧。你是不是突然懂得如何定义标签了,读memberlist.lib.php里面的代码,模仿,就能自定义标签了,可参考“扩展标签”。所以自定义标签只用在include/taglib里加入XX.lib.php文件,里面定义lib_XX函数即可。快点去试一试。

***把root/index.php(默认模板根目录中的)里面的

$pv->SetTemplet($cfg_basedir . $cfg_templets_dir . "/" . $row[‘templet‘]);

改成$pv->SetTemplet($cfg_basedir .‘/test.htm‘);

在root/test.htm使用自定义标签吧

是否需要自定义标签

笔者刚学织梦标签时,第一个感觉就是之梦的标签比较抽象,不够好用。比如说刚才的zoo的问题,我就会定义一个zoo标签。后来才发现应该用定义频道的方法解决,可参考“dedecms中自定义数据模型”这篇文章。另外,标签也有一些弱点,在开发中会慢慢体会到。

上面讲了五大势力的关系、一个标签的解析过程和如何定义标签,回忆一下看看是否对标签解析有了六七成的把握。解析式模板的运作还有很多细节,读源码是最好的学习方法。但有点难度,看自己需要的程度吧,可以跳过这一段。

***把root/index.php(默认模板根目录中的)里面的

$pv->SetTemplet($cfg_basedir . $cfg_templets_dir . "/" . $row[‘templet‘]);

改成$pv->SetTemplet($cfg_basedir .‘/test.htm‘);

编写root/test.htm

{dede:memberlist row=6 signlen=30}
<li><a href="[field:spaceurl/]" target="_blank">[field:uname/]</a></li>
{/dede:memberlist}

运行index.php

这是怎么办到的,跟踪代码自己想吧(tips:适当地var_dump一些变量,还有用一下ctrl+F)。主要看dedetag.class.php这个文件,是织梦的核心文件,还是该看一看的。

过程大概是这样的:new PartView()(include/ arc.partview.class中)调用了DedeTagParse(),SetNameSpace ()做了一些初始化工作。LoadTemplate() 一方面读取网页模板代码,另一方面调用ParseTemplet()把网页模板分解标签,属性,底层模板等,得到$pv->CTags。

Display()调用echo GetResult()的结果。GetResult()就是由分解好的标签,属性,底层模板等算出结果html。由于dedecms标记满足树形的语法规则(像html一样),所以,计算标签是一个遍历树的过程。至于每个标签的值的计算,就调用了AssignSysTag(),它处理了global等标记。对于自定义标记,通过调用IncludeFile处理,这个函数又通过了复杂的调用,最后调用了include\helpers\channelunit.helper中的MakeOneTag()的函数。

自己整理一下吧!

二 解析与网页的上下文

       后面的部分是我在写完“关于网页模板”后补上的,涉及到封面模板、列表模板和文档模板,不了解的读者可以先看看那篇文章。

通过链接,网页可以在封面页、列表页和文档页间跳转,那怎么样在页面中传递信息呢?可以用get方式。由于系统有生成功能,它会把解析的结果生成纯的html页面,不太容易看清解析的过程。不妨先不用生成功能,如在后台添加一篇文章,在发布选项处选“仅动态浏览”,之后保存,预览。看到地址栏内容形如http://localhost/plus/view.php?aid=114。

不妨细细研究这个超链接,首先是aid=114。aid指article id,是文章的编号。通过给出这个编号,通过XXX处理,就能得出文章的所有信息,再加上文档模板(就像一个格式),就能的出具体的html文档页。类似地,还有tid(type id,栏目号)、cid(channel id,频道/模型号)或其他。这是在上下文间传递的信息。

  之后说说plus/view.php。打开该文件,发现里面用aid为参数,创建了一个视图类Archives的对象(在include/arc.archives.class中定义),并调用Display函数显示。这和根目录/index.php用partview视图类对象来解析模板的道理是一样的,不过这里多附加了aid表示具体的文章(而index中的东西是通用的,不用附加上下文)。也就是说,解析封面模板、列表模板和文档模板都有建立解析引擎对象。

  另外,链接中对应php文件不一定是plus/view.php,显示文档可用plus/view.php;显示列表可用plus/list.php。我猜测之所以会有文档模板和列表模板差异就是来自于不同的视图类。

  之后,若在文章的发布选项处选“生成html”,就是调用视图类的SaveToHtml函数。得到的文章链接形如http://localhost/a/webbase/javascript-ajax/2010/0409/114.html。

时间: 2024-12-25 05:53:06

(转)浅谈dedecms模板引擎工作原理及自定义标签的相关文章

PHP模板引擎的原理与实践

0x00 模板引擎的原理 模板引擎就是在模板文件中使用一系列提前约定好的标签代替原生PHP代码,通过访问一个PHP的入口文件,会有一个PHP编译文件根据约定替换模板内标签以及标签内变量,最终将模板文件编译成一个PHP文件,然后展示到浏览器中. 模板文件 前端开发者将前端代码中的所有数据替换成与服务端开发者约定好的标签及变量名. PHP入口文件 服务端开发者将前端代码中所需要的变量注入到前端. PHP编译文件 该文件中是模板引擎中的核心,在这里我们定义了 标签 语句 等,通过读取模板文件,使用正则

javascript引擎工作原理

1. 什么是JavaScript解析引擎? 简单地说,JavaScript解析引擎就是能够“读懂”JavaScript代码,并准确地给出代码运行结果的一段程序.比方说,当你写了 var a = 1 + 1; 这样一段代码,JavaScript引擎做的事情就是看懂(解析)你这段代码,并且将a的值变为2. 学过编译原理的人都知道,对于静态语言来说(如Java.C++.C),处理上述这些事情的叫编译器(Compiler),相应地对于JavaScript这样的动态语言则叫解释器(Interpreter)

JAVA之旅(二十五)——文件复制,字符流的缓冲区,BufferedWriter,BufferedReader,通过缓冲区复制文件,readLine工作原理,自定义readLine

JAVA之旅(二十五)--文件复制,字符流的缓冲区,BufferedWriter,BufferedReader,通过缓冲区复制文件,readLine工作原理,自定义readLine 我们继续IO上个篇幅讲 一.文本复制 读写都说了,我们来看下其他的操作,我们首先来看复制 复制原理:其实就是将C盘下的文件数据存储到D盘的一个文件中 实现的步骤: 1.在D盘创建一个文件,用于存储文件中的数据 2.定义读取流和文件关联 3.通过不断的读写完成数据的存储 关闭资源 package com.lgl.hel

浅谈MySQL存储引擎-InnoDB&amp;MyISAM

存储引擎在MySQL的逻辑架构中位于第三层,负责MySQL中的数据的存储和提取.MySQL存储引擎有很多,不同的存储引擎保存数据和索引的方式是不同的.每一种存储引擎都有它的优势和劣势,本文只讨论最常见的InnoDB和MyISAM两种存储引擎进行讨论.本文中关于数据存储形式和索引的可以查看图解MySQL索引 MySQL逻辑架构图: InnoDB存储引擎 InnoDB是默认的事务型存储引擎,也是最重要,使用最广泛的存储引擎.在没有特殊情况下,一般优先使用InnoDB存储引擎. 1??.数据存储形式

Tomcat中JSP引擎工作原理

http://blog.csdn.net/linjiaxingqqqq/article/details/7164449 JSP运行环境: 执行JSP代码需要在服务器上安装JSP引擎,比较常见的引擎有WebLogic和Tomcat.把这些支持JSP的web服务器配置好后.就可以再客户端通过浏览器来访问JSP页面了.默认端口一般是7001. JSP生命周期: JSP处理请求的方法就是把这些请求都统一看做Servlet.由于这个原因,JSP的很多功能和生命周期,都由Java Servlet技术标准定义

jsp基础学习(四)----jsp引擎工作原理

JSP引擎的工作原理 当一个JSP页面第一次被访问的时候,JSP引擎将执行以下步骤:      (1)将JSP页面翻译成一个Servlet,就是一个Java文件,同时也是一个完整的Java程序.(相当于是c语言程序的预处理,补充完整所有的代码)      (2)JSP引擎调用Java编译器对这个Servlet进行编译,得到可执行文件class.(和C语言程序的编译是一样的) (3)JSP引擎调用java虚拟机来解释执行class文件,生成向客户端发送的应答,然后发送给客户端.(jsp是调用jav

php模板引擎的原理与简单实例

模板引擎其实就是将一个带有自定义标签的字符串,通过相应的规则解析,返回php可以解析的字符串,这其中正则的运用是必不可少的,所以要有一定的正则基础.总体思想,引入按规则写好的模板,传递给标签解析类(_HtmlTag)进行解析,再把解析好的字符串传递给php进行解析渲染输出首先定义了一个_HtmlTag类: class _HtmlTag{ protected $taglist = "if|elseif|else|loop|for|while|=|:=|:e|:html|:"; prote

浏览器渲染引擎工作原理

浏览器内核包括渲染引擎和JS引擎,由于js引擎越来越独立,内核就倾向于只指渲染引擎 渲染引擎是一种对HTML文档进行解析并将其显示在页面上的工具.它负责取得网页的内容(HTML.XML.图象等等).整理信息(例如加入CSS等),以及计算网页的显示方式然后会输出至显示器或打印机 渲染引擎工作流程 HTML解析器解析DOMM树(解析为DOM树上个节点,同时解析CSS样式) 渲染树结构(具有一定的视觉效果,并按照一定顺序排列在屏幕上) 布局渲染树(为每个节点分配固定坐标) 绘制DOM树(渲染引擎会遍历

博客SEO-搜索引擎工作原理简介

资源推荐 Zac出版的<SEO实战密码>是SEO入门的好书,可惜我在当当网买的电子书受DRM版权保护,无法与大家分享. 我在网上找到了此书的  了解搜索引擎  章节,非常详细,且容易理解.链接如下: http://www.21jn.net/seo/zac/zac.html 前言 SEO由英文Search Engine Optimization缩写而来,中文意译为“搜索引擎优化”.SEO是指从自然搜索结果获得网站流量的技术和过程,是在了解搜索引擎自然排名机制的基础上,对网站进行内部及外部的调整优