Location: PHPKode > scripts > UI Template > ui-template/frea/Template/Dom/Parser.php
<?php
/**
 * Parse a ui template file to ui dom
 * document
 *
 * @package frea-framework
 * @subpackage Template
 * 
 * @copyright 2009 frea-framework
 * @author Dawid Kraczkowski hide@address.com
 * @license  http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
 */
class Template_Dom_Parser
{
	
	const UTF8 			= "utf-8";
	const BOM			= "\xef\xbb\xbf";

	/**
	 * states
	 */
	const ST_DOCUMENT = 0;
	const ST_DOCTYPE = 1;
	const ST_XMLDEC = 2;
	const ST_TAGNAME = 3;
	const ST_CLOSETAG = 10;
	const ST_TAG = 4;
	const ST_ATTRNAME = 5;
	const ST_ATTREQ = 6;
	const ST_ATTRVAL = 7;
	const ST_ATTRQUOTE = 9;
	const ST_TEXT = 8;
	
	static public $states = array(
			self::ST_DOCUMENT	=> "Start of document",
			self::ST_TEXT 	 	=> "Html content",
			self::ST_TAG 		=> "Tag content",
			self::ST_TAGNAME 	=> "tagname",
			self::ST_ATTRNAME 	=> "attribute name",
			self::ST_ATTREQ 	=> "attribute value declaration",
			self::ST_ATTRQUOTE 	=> "attribute quote",
			self::ST_ATTRVAL 	=> "attribute value",
			self::ST_DOCTYPE 	=> "doctype declaration",
			self::ST_XMLDEC		=> "xml declaration",
			self::ST_CLOSETAG 	=> "closing tag",

		);
	
	public $cLine,$cChar;
	private $dom;
	private $rawstr;
	
	public $fileName;
	
	/**
	 * constructor
	 *
	 * @param string $filename
	 */
	public function __construct($filename)
	{
		$this->rawstr = file_get_contents($filename);
		$this->fileName = $filename;
	}
	/**
	 * parse the string
	 *
	 * @throws Template_Dom_Parser_Exception
	 * @return Template_Dom_Node_Document
	 */
	public function parse()
	{
		$str = $this->rawstr;
		
		//initial values
		$i = 0;
		$length = strlen($str);
		if(substr($str,0,3)==self::BOM) $i = 3;
		$this->cLine = 1;
			
		$state = self::ST_DOCUMENT ;
		$prevstate = self::ST_DOCUMENT ;
		$doctype = "";
		$content = "";
		$tagname = "";
		$attributename = "";
		$attributevalue = "";
		$attributequote = '';
		$htmlcontents = "";
		$closetag = "";
		$starttagLine = 0;

		
		$this->dom = new Template_Dom_Node_Document($this->fileName);
		$builder = $this->dom;
		for (; $i<$length; $i++) 
		{
			$this->cChar++;
			$c = $str[$i];
			if($c === "\n")
			{
				$this->cLine++;//current line increment
				$this->cChar = 1;//reset current char
			}
			//
			$prevstate = $state;
			switch($state)
			{
				case self::ST_DOCUMENT :
					/* removed
					if($c === '<' & substr($str,$i,9)=="<!DOCTYPE")
					{
						$state = self::ST_DOCTYPE ;
						$builder = $builder->appendChild(new Template_Dom_Node_Doctype());
						$i += 8;
					}*/
					if($c === '<' & substr($str,$i,4) == "<ui:")
					{
						$state = self::ST_TAGNAME;
						$starttagLine = $this->cLine;
						$tagname = "";
						$i += 3;
					}
					else
					{
						$state = self::ST_TEXT ;
						$htmlcontents .= $c;
					}
				break;
				case self::ST_DOCTYPE :
					if($c === '>')
					{
						$builder->value($doctype);
						$builder = $builder->parentNode();
						$doctype = "";
						$state = self::ST_DOCUMENT ;
					}
					else 
					{
						$doctype .= $c;
					}
				break;
				case self::ST_TEXT :
					if($c === '<' && substr($str,$i,4)=="<ui:")
					{
						
						if(strlen($htmlcontents))
						{
							$builder = $builder->appendChild(new Template_Dom_Node_Text());
							$builder->value($htmlcontents);
							$builder = $builder->parentNode();
						}
						$htmlcontents = "";
						$state = self::ST_TAGNAME;
						$tagname = "";
						$i += 3;
						
					}
					elseif($c === '<' && substr($str,$i,5) == "</ui:")
					{
						$i += 4;
						$htmlcontents = trim($htmlcontents);
						
						if(strlen($htmlcontents))
						{
							$builder = $builder->appendChild(new Template_Dom_Node_Text());
							$builder->value($htmlcontents);
							$builder = $builder->parentNode();
						}
						$htmlcontents = "";
						$state = self::ST_CLOSETAG ;
					}
					else 
					{
						$htmlcontents .= $c;
						
						//last char for full text document
						if($i+1 == $length)
						{
							$builder = $builder->appendChild(new Template_Dom_Node_Text());
							$builder->value($htmlcontents);
						}
					}
				break;
				case self::ST_CLOSETAG :
					if($c === '>')
					{
						if($builder->nodeName() != trim($closetag))
							throw new Template_Dom_Parser_Exception("Missing closing tag {$builder->nodeName()} given {$closetag} in file {$this->fileName} on line {$this->cLine}");
						$builder->onClose($this,$builder,$starttagLine,$this->cLine);
						$builder = $builder->parentNode();
						$closetag = "";
						$state = self::ST_TEXT ;
					}
					else 
					{
						$closetag .= $c;
					}
				break;
				case self::ST_TAGNAME :
					if(self::isWhiteChar($c))
					{
						if(!self::checkNames($tagname))
							throw new Template_Dom_Parser_Exception("Wrong tag name in file {$this->fileName} on line {$this->cLine}, given {$tagname}");
						$builder = $builder->appendChild(new Template_Dom_Node_Element($tagname));
						$tagname = "";
						$starttagLine = $this->cLine;
						$state = self::ST_TAG ;
					}
					elseif($c === '>')
					{
						if(!self::checkNames($tagname))
							throw new Template_Dom_Parser_Exception("Wrong tag name in file {$this->fileName} on line {$this->cLine}");
						$builder = $builder->appendChild(new Template_Dom_Node_Element($tagname));
						$tagname = "";
						$state = self::ST_TEXT ;
						
					}
					else 
					{
						$tagname .= $c;
					}
				break;
				case self::ST_TAG :
					if($c === '/' and substr($str,$i,2) == "/>")
					{
						$builder->onClose($this,$builder,$starttagLine,$this->cLine);
						$builder = $builder->parentNode();
						$i += 1;
						$state = self::ST_TEXT ;
						
					}
					elseif($c === '>')
					{
						$state = self::ST_TEXT ;
					}
					elseif(!self::isWhiteChar($c))
					{
						$attributename .= $c;
						$state = self::ST_ATTRNAME ;
					}
				break;
				case self::ST_ATTRNAME :
					if($c === '=')
					{
						$attributename = trim($attributename);
						if(!self::checkNames($attributename))
							throw new Template_Dom_Parser_Exception("Wrong attribute name in file {$this->fileName} on line {$this->cLine}, given: {$attributename}");
						
						$state = self::ST_ATTREQ ;
					}
					else 
					{
						$attributename .= $c;
					}
				break;
				case self::ST_ATTREQ :
					if($c === '\'' || $c === '"')
					{
						$attributequote = $c;
						$state = self::ST_ATTRVAL ;
					}
					elseif(!self::isWhiteChar($c))
					{
						throw new Template_Dom_Parser_Exception("Unexpeted '{$c}' sign in file {$this->fileName} on line {$this->cLine}");
					}
				break;
				case self::ST_ATTRVAL :
					if($c === $attributequote)
					{
						$builder->setAttribute($attributename,$attributevalue);
						$attributequote = '';
						$attributename = '';
						$attributevalue = '';
						$state = self::ST_TAG ;
					}
					else 
					{
						$attributevalue .= $c;
					}
				break;
				
			}

			
		}
		return $this->dom;
		
	}
	/**
	 * check if givnt tag/attribute name is valid
	 *
	 * @param string $str
	 * @return bool
	 */
	static public function checkNames($str)
	{
		return preg_match("#^[a-z][a-z0-9\\\-]#is",$str);
	}
	/**
	 * check if given char is white char
	 *
	 * @param char $c
	 * @return bool
	 */
	static public function isWhiteChar($c)
	{
		 return strpos(" \t\n\r\0", $c) !== false;
	}
	
	
}
Return current item: UI Template