<?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
?>
|