Location: PHPKode > scripts > CSS Tree Class > css-tree-class/CSSTree.inc.php
<?php
	/**
	* @package CSSTree
	*/
	
	/**
	* PHP4 CSSTree class
	* with this class Cascading Style sheets may be generated using a tree
	* the nodes store the attributes and values
	*
	*<code>
	* // examples follow
	*$ddata=array("border"=>"1px solid black");
	*$ddata2=array("border"=>"2px solid silver");
	*$null=null;
	*
	*$tree = new CSSTree($null,"body",$ddata,'class');
	*$tmp=&$tree->addChild('h1',$ddata2,'pseudo');
	*$tmp=&$tree->addChild('h2',$ddata,'pseudo');
	*</code>
	*
	* TODO: comments in the css are not handled, but they may work
	*/
	
	// include the Tree class
	require_once 'Tree.inc.php';

class CSSTree extends Tree{

	/**
	* Variable declaration
	*/
	
	/**
	* properties of this Node
	* @access private
	* @var array
	*/
	var $_cssproperties;
	
	/**
	* name of this Node (class=|id=|...)
	* @access public
	* @var string
	*/
	var $tagname;

	/**
	* type of CSS ('id'|'class'|'pseudo') not implemented: useless
	* @access private
	* @var string
	*/
	//var $_type;

	/**
	* default constructor
	* 
	* creates a CSS node of type $type with $name, set properties
	* @access public
	* 
	*/
	   function CSSTree(&$_parent,$tagname,$properties=null) {
			// call the constructor of the parent class
			parent::Tree($_parent);
	   	/* we don't need this stuff
	   	switch ($type){
		   	case 'class': $this->_type='class';break;
		   	case 'id': $this->_type='id';break;
		   	case 'pseudo': $this->_type='pseudo';break;
		   	default: //raise an error, TODO: raise a real error :-)
		   				echo '!!! no valid type for CSS element type, use either of id|class|pseudo !!!';
							$this->_type='class';
		   				break;
	   	}
			*/
			// set properties, if given
			if ((!$properties==null) & (is_array($properties))){
	   		$this->_cssproperties=$properties;
	   	}
	   	else{
	   		$this->_cssproperties=array();
	   	}
	   	$this->tagname=$tagname;
	}

	/**
	* add a subclass
	* @return Tree reference to the child
	*/
	function &addChild($tagname,$properties=null) {
		$testifalreadyexists=$this->getChildByName($tagname);
		if ($testifalreadyexists!==false){return $testifalreadyexists;}
		$this->_children[]=&new CSSTree(&$this,$tagname,$properties);
		//get the automatically set id (=array key) - it is the last element now
		end($this->_children);
		$key=key($this->_children);
		$this->_children[$key]->_setId($key);
		$this->_children[$key]->level = $this->_level + 1;
		return $this->_children[$key];
	}

	/**
	* output CSS properties for this node, for use in style=""
	* @return string
	*/
	function renderCSSProperties(){
		$css='';
		foreach ($this->_cssproperties as $prop=>$value) {
				$css.=$prop.': '.$value.';';
		}
	return $css;
	}

	/**
	* output CSS for this node
	* @return string
	*/
	function renderCSS(){
		$css=' ';
		$prop=$this->renderCSSProperties();
		//skip if there are no properties
		if ($prop!=''){
			$css.=$this->tagname.'{';
			$css.=$prop;
			$css.="}\n";
		}
		return $css;
	}

	/**
	* 	get a reference child by its name, otherwise false
	*	@return CSSTree reference to the child node or false
	*
	*/
	function &getChildByName($name){
			$ret=false;
			//echo 'selecting child with name '.$name; 
			foreach ($this->_children as $child){
				if (!strcasecmp($name,$child->tagname)){
					$ret=&$this->_children[$child->getId()];
				return $ret;
				}
			}
		return $ret;
	}

	/**
	* 	Add a property to the properties 
	*	
	*/
	function setProperty($property, $value){
			$this->_cssproperties[$property]=$value;
	}		

	/**
	* output CSS for the complete tree, for use in header (<style type="text/css">) or file
	* @return string
	*/
	function renderCSSAll(){
		$root=&$this->getRoot();
		return $root->_renderCSSAll('');
	}


	/**
	* internal function returning string for one node using the (cascaded) prefix
	* @var $prefix the accumulated cascaded prefix (class/id/tag name) 
	* @return string
	* @access private
	*/
	function _renderCSSAll($prefix){
		$css='';
		// check if this is a 'virtual node' without properties,
		// then we dont need to output something 
		if (count($this->_cssproperties) != 0){
			$css.=$prefix.$this->renderCSS();
		}				
		//set prefix for the children
		$prefix.=' '.$this->tagname;
		foreach ($this->_children as $child) {
				$css.=$child->_renderCSSAll($prefix);
		}
	return $css;		
	}

	/**
	* CSS file parser, returns the css properties as (new) tree
	* @return CSSTree
	* @param string filename
	* @access public
	*/
   function parseFile($filename)  {
	/* Open File and Parse it */
    	$fp=fopen($filename,"r") or die("Error opening file $filename");
    	$css_str = fread($fp, filesize ($filename));
    	fclose($fp);
    	//echo "read: ".$css_str;
		return($this->parse($css_str));
    }
	
	/**
	* CSS string parser, returns the css properties as (new) tree
	* @return CSSTree
	* @param string cssstring
	* @access public
	*/
	function &parse($cssstring){
			$null=null;
			// new CSSTree with empty tagname
			$tree=&new CSSTree($null,'');
			// replace unnecessary white spaces with one 
			$css_str=preg_replace("/[\s]+/",' ',$cssstring);
			// divide into classes
			$css_class = explode("}", $css_str);
			//iterate through classes
			while (list($key,$val) = each ($css_class)){
				// divide into classes and their properties
				$aCSSObj=explode("{",$val);
				// find multiple definitions and create a node for any
				$classes=explode(",",$aCSSObj[0]);
				foreach ($classes as $class){
					$nesting=explode(" ",trim($class));
					$propval=explode(";",$aCSSObj[1]);
					//print_r($properties);
					// begin at root node and set nested properties
					$tmp=&$tree;
					foreach ($nesting as $newlevel){
						$tmp=&$tmp->addChild($newlevel);
					}
					//populate properties
					foreach ($propval as $prop){
						$prop=explode(":",$prop);
						$propname=trim($prop[0]);
						// do only for non-empty ones (last may be empty because of trailing ';')
						if ($propname!=''){
							$tmp->setProperty($propname,$prop[1]);
						}
					}
				}
			}
	return $tree;
	}	

	/**
	* echo the structure of the subnodes of our tree/node
	* and tell us addtitionally the name
	* @param string prefix (used for the recursive output)
	* @return void
	*/
	function echoStructure($pre='') {
		for ($i=0;$i<$this->getLevel();$i++){
			$pre.='|';//$this->getLevel();
		}
		echo $pre."+[".$this->_id.' '.$this->tagname.']';
		if (is_array($this->data)){
			foreach ($this->data as $key=>$value) {
		    		 echo '('.$key.'|'.$value.')';
	    	}
    	}
    		echo "\n";
		if ($this->numChildren()>0){
			
			foreach ($this->_children as $child) {
		    	$child->echoStructure();
			}
		}
	}

} // end class

		
?>
Return current item: CSS Tree Class