我们经常想这样 {title1 标题1} 就可以按照标题一的格式去输出数据。

有时希望 {showCom {v4_flash} $list_flash} 能够将$list_flash 的数据,按v4_flash的效果进行显示。

我们还希望 {loop $val $key $val} xxx{/loop} 能被解释成 <php foreach($val as $key=>$val){ xxx }>

{$xxx[yyy]} 能被解析成 <?php echo $xxx[‘yyy’]?> 等等。。。。。。例如如图.

需求1

 

前面说了这么多了,下面开始show 代码了。

第一部分,整体思咱与代码概要设计 先从使用者的角度开始 , 目标是 读取模版数据 ,调用解析类,设置解析引擎,然后解析生成目标文件[或缓存文件]

使用者的角度
//得到模版数据
$tplData = $CI->load->view($tpl,"",true);
//加载xtpl 类
load_class("xtpl");
$me = new xTpl();
$me->setTplCode($tplData); //加载模版数据
$me->parse($foreignConfig); //解析模版数据
//创建用户模版数据

$destFile = $_SERVER['DOCUMENT_ROOT']."/system/application/views/tpl_v4/$tpl.php";
$me->createTpl($destFile);

 

 xtpl 类的实现

 

代码
/**
* * 模版处理类
*
*/
class xTpl {
private $selfStyleName; //自定义样式名称
private $tplCode;
public $data;
public $tplParse;
private $destCode;
public $CI;

/**
* * 构造函数
*
*/
function __construct(){//默认使用liteParse 解析
$this->tplParse = new liteParse(); 
$this->CI = &get_instance();

}

function setTplCode($html){
$this->tplCode = $html;
}

function parse($config = ''){ //对数据进行解析。
$this->destCode = $this->tplParse->parse($this->tplCode,$config);
}

/**
* *
*
*/
function setData($data)
{
$this->data = $data;
}

function createTpl($destFile)
{

$this->CI->load->helper("file");
write_file(
$destFile, $this->destCode);
}
}

 

tplParse 接口,以及listParse实现类

 

代码
/**
* * 资讯处理类.
*
*/
interface tplParse
{
function parse($str = '',$cfg='');
}

/**
* * 轻量级解析器
*
*/
class liteParse implements tplParse {

private $regeVar = "((\\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(\[[a-zA-Z0-9_\"\'\$\x7f-\xff]+\])*)";
private $regeConst = "([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)";
public $cfgArr = array();
//private $strArrCfg = array();

function __construct()
{
$cfgStrReplaceArr = array();
$config = array(
//简单文字替换部分
array("rege"=>"/\s*\{loadview\s+(.+?)\}\s*/i","replacement"=>
'<?php $this->load->view("\\1"); ?>')
,array("rege"=>"/([\n\r]+)\t+/s","replacement"=>"\\1")
,array("rege"=>"/\{(\\\$[a-zA-Z0-9_\[\]\
'\"\$\x7f-\xff]+)\\s*\}/s","replacement"=>"<?=\\1?>")
,array("rege"=>"/\{else\}/i","replacement"=>"\n".'<? } else { ?>'."\n")
,array("rege"=>"/$this->regeVar/i","callback"=>"addquote")
,array("rege"=>"/\<\?\=\<\?\=$this->regeVar\?\>\?\>/i","callback"=>"removeRepeat")
,array("rege"=>"/\{else\s?if\s+(.+?)\}/i","callback"=>"parseElseIf")
,array("rege"=>"/\s*\{if\s+(.+?)\}\s*([\d\D]+?)\s*\{\/if\}\s*/i","callback"=>"parseIf")
,array("rege"=>"/\s*\{loop\s+(\S+)\s+(\S+)\}\s*(.+?)\s*\{\/loop\}\s*/i","callback"=>"parseLoop")
,array("rege"=>"/\s*\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}\s*(.+?)\s*\{\/loop\}\s*/i","callback"=>"parseKLoop")
);
$this->setCfg($config);
}
/**
* * 设置配置文件
*
* @param unknown_type $arr
*/
function setCfg($arr)
{
$this->cfgArr = $arr;
}
/**
* * 添加配置部分。
*
* @param unknown_type $foreignConfig
*/
function addCfg($foreignConfig)
{
if(is_array($foreignConfig))
{
$this->cfgArr = array_merge($foreignConfig,$this->cfgArr);
}
}


function parse($template = '',$config =''){
$this->addCfg($config); //加载外部定制的配制文件
CS_log("----最开始内容:".$template);
foreach ($this->cfgArr as $val):
if(isset($val["replacement"])) //简单文字替换模式
{
$template = preg_replace($val["rege"],$val["replacement"], $template);
}
if(isset($val["callback"])) //通过callback 模式替换
{
$template = preg_replace_callback($val["rege"], array($this,$val["callback"]), $template);
}
CS_log(
"--经过".$val["rege"]."组件解析为内容为:".$template);
endforeach;

return $template;
}




/**
* * 添加引号。将[xxx] 替换成 ['xxx'] 并且结果中 的 \" 替换成 "
*
* @param unknown_type $var
* @return unknown
*/
function addquote($matches) {

$val = $matches[1];
return str_replace("\\\"", "\"", preg_replace("/\[([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\]/s", "['\\1']", $val));
}

/**
* * 去掉重复的 <?=<?=?>?>
*/
function removeRepeat($matched)
{
$val = $matched[1];
$val = "<?=$val?>";
return str_replace("\\\"", "\"", preg_replace("/\[([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\]/s", "['\\1']", $val));
}

/***
*if 部分替换
*/
function parseIf($matched)
{
echo "coming";
$exp = $matched[1];
$statement = $matched[2];
$str = $this->stripvtags("\n<? if ( $exp ) {?>\n",$statement."\n<?}?>");
return $str;
}


/**
* * foreach ($rows as $val) 替换
*
* @param unknown_type $matched
* @return unknown
*/
function parseLoop($matched)
{
$exp = $matched[1];
$expVal = $matched[2];
$statement = $matched[3];
$str = $this->stripvtags("\n<? if(is_array($exp)) { foreach ( $exp as $expVal ) { ?>\n",$statement."\n<? } }?>");
return $str;
}


/**
* * foreach ($rows as $val) 替换
*
* @param unknown_type $matched
* @return unknown
*/
function parseKLoop($matched)
{
$exp = $matched[1];
$expKey = $matched[2];
$expVal = $matched[3];
$statement = $matched[4];
$str = $this->stripvtags("<?\n if(is_array($exp)) { foreach ( $exp as $expKey => $expVal ){ ?>\n",$statement."\n<? } }?>");
return $str;
}

/**
* * 将 else if xxx 替换为 } else if(xxx) {
*/
function parseElseIf($matched)
{
$exp = $matched[1];
$str = $this->stripvtags("\n<? } elseif ($exp) {?>\n","");
return $str;

}

/**
* **应用服务
*/
function parseShowCom($matched)
{
if(isset($matched[3])) {
$strOut = '<? $rows = '.$matched[2].'; $sClass= \''.$matched[3].'\';?>'."\n";
}
else {
$strOut= '<? $rows = '.$matched[2].'; $sClass = \'\';?>'."\n";
}
$str = $this->stripvtags($strOut,$matched[1]);
return $str;
}

/**
* *去掉因为前面变量替换 所引起的将 {$xxx} 自动转换成了 <?=$xxx?> 这样的元素混入到if 条件中所带来的附面效果。
*
* @param 表达式 $expr
* @param 描述语句 $statement
*/
function stripvtags($expr, $statement) {
$expr = str_replace("\\\"", "\"", preg_replace("/\<\?\=(\\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\[\]\"\'\x7f-\xff]*)\?\>/s", "\\1", $expr));
$statement = str_replace("\\\"", "\"", $statement);
return $expr.$statement;
}
}

 

再配合自定义组件数据

 

 

然后读取配置文件 将数据存入 $foreignConfig

调用xtpl 进行解析 $me->parse($foreignConfig);  //解析模版数据 然后生成文件。

 

第二部分:代码详解。

一 基础实现之变量替换

如何将  1 {$val} 替换成 <?php=$val;?>

   array("rege"=>"/\{(\\\$[a-zA-Z0-9_\[\]\'\"\$\x7f-\xff]+)\\s*\}/s","replacement"=>"<?=\\1?>")

如何将

{loop $rows $val}xxx{/loop}  替换成 <? if(is_array($row)) foreach($rows as $val) {?> xxx<?php }?>

{loop $rows $Key $val}xxx{/loop} 替换成 <? if(is_array($row)) foreach($rows as $key => $val) {?> xxx<?php }?>

 

代码
,array("rege"=>"/\s*\{loop\s+(\S+)\s+(\S+)\}\s*(.+?)\s*\{\/loop\}\s*/i","callback"=>"parseLoop")
,array("rege"=>"/\s*\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}\s*(.+?)\s*\{\/loop\}\s*/i","callback"=>"parseKLoop")

//实现部分
/**
* * foreach ($rows as $val) 替换
*
* @param unknown_type $matched
* @return unknown
*/
function parseLoop($matched)
{
$exp = $matched[1];
$expVal = $matched[2];
$statement = $matched[3];
$str = $this->stripvtags("\n<? if(is_array($exp)) { foreach ( $exp as $expVal ) { ?>\n",$statement."\n<? } }?>");
return $str;
}


/**
* * foreach ($rows as $val) 替换
*
* @param unknown_type $matched
* @return unknown
*/
function parseKLoop($matched)
{
$exp = $matched[1];
$expKey = $matched[2];
$expVal = $matched[3];
$statement = $matched[4];
$str = $this->stripvtags("<?\n if(is_array($exp)) { foreach ( $exp as $expKey => $expVal ){ ?>\n",$statement."\n<? } }?>");
return $str;
}

 

 

未完,待续

 

 

posted on 2011-01-28 17:59  murain  阅读(200)  评论(0编辑  收藏  举报