<?php
/**
* Node class file
* @author Mathieu Lachance <lachance.mathieu@poincomm.com>
* @link http://www.mathieulachance.com/
* @copyright Copyright (c) 2007 Mathieu Lachance
* @license http://creativecommons.org/licenses/by/2.5/ca/
* @version 2.0 2007-03-15 15h45
*/
/**
* Class Node
* The Node class is used to generate a tree architecture.
* Each Node contains :
* - a name, wich is not necessarly unique to the tree, the $name protected property
* - the reference of his parent, the $parent protected property
* - an integer indexed array containing all the references of the child nodes, the $child protected property
*
* When adding a new Node with the addChild method, the node class generate a public user defined property called
* as same as the new Node name.
* Therefore, this kind of dynamic property can be accessed freely with the powerfull syntax :
* - $tree->nodeName->... when there is only one node named nodeName
* - $tree->nodeName[index]->... when there is more than one node named nodeName
*
* Moreover, each node can be exported as xml with the use of the export method.
* They can be re-imported from xml with the combine use of SimpleXML extension and the import method.
* - TO DO : find a better way than using SimpleXML extension
*/
class Node
{
/**
* @var string $name the node name
*/
protected $name = null;
/**
* @var Node $parent a reference to the parent node
*/
protected $parent = null;
/**
* @var array $children an integer indexed array containing all the references to the child nodes
*/
protected $children = null;
/**
* @var int $count the number of child nodes
*/
protected $count = null;
/**
* Constructor
* @param string $name the node name
*/
public function __construct($name = null){
$this->name = (string)$name; // ensure the $name is a string an assign it to the node name
$this->children = array(); // initialise the childs array
$this->count = 0; // initialise the count of the childs array
}
/**
* Wether :
* - create a public user defined property called by the node $n name and
* assign the node $n to this user defined property
* - append the node $n to the public user defined property called by the node $n name
* @param Node $n the node to append
*/
public function addChild(Node $n){
$n->parent = $this; // assign the parent node to the node $n
$name = $n->name; // get the node name
if (!(isset($this->$name))) { // check wether the public user defined property $name is already defined
$this->$name = $n; // assign the node $n to the user defined property $name
}
else{
if (!(is_array($this->$name))){ // if the public user defined property $name is not an array containing nodes
$this->$name = array($this->$name); // convert the user defined property as an array
}
array_push($this->$name, $n); // append the new node $n to the user defined property
}
array_push($this->children, $n); // append the new node $n to the childs array
$this->count++; // increments $this->count the number of child nodes
return $n;
}
/**
* @return string $name the node name
*/
public function getName(){
return $this->name;
}
/**
* @return Node $parent the reference to the parent node
*/
public function getParent(){
return $this->parent;
}
/**
* @return array $children the integer indexed array containing all the references to the child nodes
*/
public function getChildren(){
return $this->children;
}
/**
* @return int $count the number of child nodes
*/
public function getChildrenCount(){
return $this->count;
}
/**
* @return bool wether : true if there is no child contained in the children array, else false
*/
public function isEmpty(){
return ($this->count == 0);
}
/**
* export the node and all his childs to an xml format
* @param $level the node indentation deep
* @return string $x the xml output of the node
*/
public function export($level = null){
$level = (int)$level;
// if it's the root level element
$ws = str_repeat(" ", $level); // calculate the whitespace, TO DO : this one could be a constant
if ($this->count == 0){ // if the current node is empty
return "$ws<$this->name/>\n"; // return a closing tag of the current node name as the xml output
}
$x = "$ws<$this->name>\n"; // open an tag of the current node name
foreach($this->children as $child){ // for each child of the current node
$x .= $child->export($level+1); // export the child node
}
$x .= "$ws</$this->name>\n"; // close the opened tag of the current node name
return $x; // return the xml output of the current node
}
/**
* @return the xml output of the node
*/
public function __toString(){
return $this->export();
}
/**
* import all xml nodes from a SimpleXMLElement
* @param SimpleXMLElement $sxe the xml fragment of the last import method iteration
* @param Node $p the parent node reference of the last import method iteration
*/
public function import(SimpleXMLElement $sxe, Node $p = null){
$this->name = $sxe->getName(); // reasign the node name with the root element of the SimpleXMLElelment
$this->parent = $p; // assign the parent node
if (count($sxe->children()) > 0){ // if the xml node is not empty
foreach($sxe->children() as $child){ // for each children
$n = new Node($child->getName()); // create the new node
$this->addChild($n); // append the new node
$n->import($child, $this); // now import all nodes from the child element of the SimpleXMLElement
}
}
}
}
/* start of benchmark */
$start = microtime(true);
/* export test */
$n = new Node("html");
$n->addChild(new Node("head"));
$n->head->addChild(new Node("meta"));
$n->head->addChild(new Node("meta"));
$n->addChild(new Node("body"));
$n->body->addChild(new Node("div"));
$n->body->addChild(new Node("div"));
$n->body->div[1]->addChild(new Node("span"));
echo $n->export(); // ouput : <html><head><meta /><meta /></head><body><div /><div><span /></div></body></html>
/* import test */
$x = new SimpleXMLElement($n->export());
$n = new Node();
$n->import($x);
echo $n->export(); // ouput : <html><head><meta /><meta /></head><body><div /><div><span /></div></body></html>
/* serialization test */
$n = serialize($n);
$n = unserialize($n);
echo $n->export(); // ouput : <html><head><meta /><meta /></head><body><div /><div><span /></div></body></html>
/* end of benchmark */
$end = microtime(true);
echo $end - $start; // ouput : 0.00128698348999
?>
|