首先taglib需要读取某一个文件,具体的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public function parse( $file ) { $htmlContents = file_get_contents ( $file ); //此处本来可以使用$dom->loadHTMLFile($file)来完成 //但是因为xml格式较为严格,所以此处使用xml来解析 $xmlContents = '<?xml version="1.0" encoding="utf-8"?><root>' . $htmlContents . '</root>' ; file_put_contents ( $file , $xmlContents ); //将即将处理的文件变为xml文件 try { $this ->_dom = new DOMDocument(); $this ->_dom->load( $file ); $contents = $this ->_parseTag( $this ->_dom->documentElement); return $contents ; } catch (DOMException $e ) { echo $e ->getMessage(); } } |
由于XML需要一个根节点,所以我们使用了<root></root>。
注意,这个地方的$file是一个路径,它是已经经过ViewChecker处理的文件,并不是通过display()调用得到的这个文件了。
这个函数只是将整个HTML代码构建成为一个DOM树,这个树的具体处理过程交给了_parseTag这个protected的方法处理。
好,我们再看看_parseTag的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | protected function _parseTag( $element ) { $contents = "" ; if ( $element ->hasChildNodes()) { foreach ( $element ->childNodes as $childNode ) { if (XML_TEXT_NODE === $childNode ->nodeType) { if ( '' !== trim( $childNode ->nodeValue)) { //文本节点 return $childNode ->nodeValue; } } else { $tagName = $childNode ->nodeName; $tagAttr = array (); if ( $childNode ->hasAttributes()) { //抓取这个节点的所有属性 foreach ( $childNode ->attributes as $attr ) { $tagAttr [ $attr ->nodeName] = $attr ->nodeValue; } } $contents .= $this ->_parseTagStart( $tagName , $tagAttr ); $contents .= $this ->_parseTag( $childNode ); $contents .= $this ->_parseTagEnd( $tagName ); } } } else { //文本节点 return $element ->nodeValue; } return $contents ; } |
由于视图文件只是第一次解析的时候才会经过如此复杂的处理,如果后面没有改动,第二次调用的会是已经被解析的内容,所以这个地方我没有过多的考虑效率。
这个函数实际上就是将标签一个个的取出来,标签名为$tagName,标签的所有属性为$tagAttr,然后传递给$this->_parseTagStart和$this->_parseTag,$this->_parseTagEnd即可。
为什么在_parseTagStart和_parseTagEnd中间会有一个_parseTag呢,这是为了递归的调用,因为一个标签中间可能会有其他的标签,如:
现在的ul标签中间就有两个li标签。
那么_parseTagStart处理一个标签的什么内容呢,现在我们以一个具体的标签举例:
<li id = "li" class = "test"></li>
那么_parseTagStart会处理<li id = "li" class = "test">,而</li>会交给_parseTagEnd处理。
这两个函数都会首先判定这个标签是否需要解析,因为除了标签库定义的标签,HTML本身也定义了很多标签,这些标签是不需要处理的,所以我们需要定义一个变量,这个变量存储所有要解析的标签和它们的属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | protected $_tags = array ( 'foreach' => array ( 'attr' => 'from|item|key' ), 'if' => array ( 'attr' => 'condition' ), 'elseif' => array ( 'attr' => 'condition' ), 'else' => array ( 'attr' => '' ), 'include' => array ( 'attr' => 'file|type' ), 'print' => array ( 'attr' => 'name|type' ), 'for' => array ( 'attr' => 'start|end|loop' ), 'switch' => array ( 'attr' => 'name' ), 'case' => array ( 'attr' => 'name' ), 'default' => array ( 'attr' => '' ), 'break' => array ( 'attr' => '' ), 'continue' => array ( 'attr' => '' ), 'while' => array ( 'attr' => 'condition|loop|start' ), 'isset' => array ( 'attr' => 'name' ), 'set' => array ( 'attr' => 'name|value' ), 'flash' => array ( 'attr' => 'id|class|value|width|height' ), 'page' => array ( 'attr' => 'currentPage|totalPages|totalRecords|href|isAjax|pageRange' ) ); |
好,现在就直接贴出_parseTagStart的代码了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | protected function _parseTagStart( $tagName , $tagAttr = array ()) { if ( $this ->_isInTagLib( $tagName )) { $method = '_parse' .(ucfirst( $tagName ). 'Start' ); return $this -> $method ( $tagName , $tagAttr ); //调用相应的解析函数 } else { //非标签库的标签 if ( '#comment' === $tagName ) { //注释 $tag = '<!-- ' ; } else { $tag = '<' . $tagName ; foreach ( $tagAttr as $attr => $val ) { $tag .= ' ' . $attr . ' = "' . $val . '"' ; } if (! $this ->_isSpecialHtmlTag( $tagName )) { $tag .= '>' ; } else { $tag .= '/>' ; } } return $tag ; } } |
对于_parseTagEnd也很类似:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | protected function _parseTagEnd( $tagName ) { if ( $this ->_isInTagLib( $tagName )) { $method = '_parse' .(ucfirst( $tagName ). 'End' ); if (!method_exists( $this , $method )) { return $this ->_parseUniversalTagEnd( $tagName ); } else { return $this -> $method ( $tagName ); } } else { //非标签库的标签 if ( '#comment' === $tagName ) { //注释 return ' -->' ; } else { if (! $this ->_isSpecialHtmlTag( $tagName )) { return '</' . $tagName . '>' ; } else { return '' ; } } } } |
那么现在假设存在一个标签foreach在标签库中,我们只需要定义一个_parseForeachStart和_parseForeachEnd处理即可。
taglib这个类不会定义完所有的标签,用户需要扩展标签的时候,只需要继承taglib,然后覆盖$_tags即可。
建议在用户自定义的标签库这个类里面使用$_myTags这个变量存储用户自定义的标签,然后在__construct函数中将$_myTags也加入到$_tags变量中。
那么现在我直接贴出foreach这个标签的处理函数,首先是_parseForeachStart:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | protected function _parseForeachStart( $tagName , $tagAttr = array ()) { if (! array_key_exists ( 'from' , $tagAttr ) || ! array_key_exists ( 'item' , $tagAttr )) { $this ->_log( 'foreach标签必须含有from和item两个属性' ); return '' ; } if (! $this ->_isTagAttrLegal( $tagName , $tagAttr )) { //如果存在不合法的标签,直接返回空串 return '' ; } $tag = '<?php if(isset(' . $tagAttr [ 'from' ]. ')): ' ; $tag .= 'foreach(' . $tagAttr [ 'from' ]. ' as ' ; if ( array_key_exists ( 'key' , $tagAttr )) { $tag .= '$' . $tagAttr [ 'key' ]. '=>' ; } $tag .= '$' . $tagAttr [ 'item' ]. '): ?>' ; return $tag ; } |
好吧,视图这一块儿就说完了。
给大家说声不好意思啊,的确视图这一块儿说得太匆忙了,而且不具体,的确是因为最近没有时间了,马上就要回去了,回去之后没有网了,我不想等到下学期再写,下学期我再将这些内容更细致的讲解一下了。
那这学期就说这么多了,这个系列就下学期再更新了,祝大家新年快乐!
联系客服