<?php /** * XMLElement 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-10 15h45 */
/** * Class XMLElement * The XMLElement class is used to generate an xml tree architecture. * This xml tree architecture is similar to the SimpleXMLElement class embeded by default within PHP5. * Each XMLElement contains : * - all the properties inherited from the Node class, $name, $parent, $children, $count * - an entity, the $entity protected property * - a mapped array containing all the attributes of the xml element, the $attributes protected property * - a possible prefix of the xml element entity, the $prefix protected property * - the possible text content of the xml element, the $text protected property * note : only empty xml element (without child elements) can define this property * * For more information please refer to the Node class documentation. */ class XMLElement extends Node { const XML_DECLARATION = "<?xml version=\"1.0\"?>\n"; /** * @var string $entity the entity of the xml element */ protected $entity = null; /** * @var array $attributes a mapped array containing all the attributes of the xml element */ protected $attributes = null; /** * @var string $prefix the possible prefix of the xml element entity */ protected $prefix = null; /** * @var string $text the possible text content of the xml element */ protected $text = null; /** * Constructor * @param string $entity the xml element entity * @param array $attributes a possible mapped array containing all the xml element attributes * @param string $prefix a possible prefix for the xml element entity * @todo : add a param for the possible text content ? */ public function __construct($entity = null, $attributes = null, $prefix = null){ parent::__construct((string)$entity); $this->prefix = (string)$prefix; $this->attributes = (array)$attributes; } /** * Assign to the mapped array $attributes the value $value at the index $name * @param string $name the name of the attribute * @param string $value the value of the attribute */ public function addAttribute($name, $value){ $this->attributes[(string)$name] = (string)$value; } /** * Assign all the attributes contained in the $map parameter * @param array $map an array containing all the attributes to assign to the xml element */ public function addAttributes($map){ if (!(is_array($map))) { throw new Exception("must pass a mapped array"); } foreach ($map as $name => $value){ $this->addAttribute($name, $value); } } /** * Overload the node addChild method to ensure that no child can be assigned * if the $text property is not null * @param string $entity the xml element entity * @param array $attributes a possible mapped array containing all the xml element attributes * @param string $prefix a possible prefix for the xml element entity * @throws Exception if the $text property is not null */ public function addChild($entity, $attributes = null, $prefix = null){ if ($this->text != null){ throw new Exception("Can only add element to non text element"); } return parent::addChild(new XMLElement($entity, $attributes, $prefix)); } /** * @return string $prefix the possible prefix of the xml element entity */ public function getPrefix(){ return $this->prefix; } /** * @return string / null the $text property */ public function getText(){ return $this->text; } /** * @param string $text the string to be assign to the $text property * @throws Exception if the xml element is not empty */ public function setText($text){ if (!($this->isEmpty())){ throw new Exception("Can only add text element to empty node"); } $this->text = (string)$text; } /** * Overload the node export method to integrate : * - the possible prefix of the entity * - the attributes of the xml element * @param int $level the xml element indentation * @return string $x the xml output */ public function export($level = null){ $level = (int)$level; $ws = str_repeat(" ", $level); // calculate the whitespace indentation ((string)$this->prefix != "") ? $pr = "$this->prefix:" : $pr = ""; // generate the prefix string $at = ""; // generate the attributes string foreach ($this->attributes as $n => $v){ $at .= " $n=\"$v\""; } if ($this->isEmpty()){ // if the current node is empty if ($this->text == null){ // return a closing tag of the current node name as the xml output return "$ws<$pr$this->name$at/>\n"; } return "$ws<$pr$this->name$at>$this->text</$pr$this->name>\n"; } $x = "$ws<$pr$this->name$at>\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</$pr$this->name>\n"; // close the opened tag of the current node name return $x; // return the xml output of the current node } public function __toString(){ return self::XML_DECLARATION . $this->export(); } /** * Overload the import method to integrate : * - the possible prefix of the entity * - the attributes of the xml element * @param DomNode $d the xml fragment of the last import method iteration * @param XMLElement $p the parent node reference of the last import method iteration */ public function import(DomNode $d, XMLElement $p = null){ $this->name = $d->nodeName; // assign the node name with the root element of the DomNode $this->parent = $p; // assign the parent node $this->entity = $this->name; // assign the node entity as same as node name $this->prefix = $d->prefix; // assign the node prefix if ($d->hasAttributes()){ // if the node contains any attributes foreach($d->attributes as $a){ // for each attributes $this->addAttribute($a->name, $a->value); // append attribute } } if ($d->hasChildNodes()){ // if the xml node is not empty foreach($d->childNodes as $child){ // for each children switch($child->nodeType){ // switch the node type case XML_ELEMENT_NODE : // if it is an XML ELEMENT NODE $n = new XMLElement(); // create the new XMLElement $n->import($child, $this); // import all nodes contained in the child node break; case XML_TEXT_NODE : // if it is a XML TEXT NODE if (trim($child->textContent)){ // if the content is not empty $this->text = trim($child->textContent); // trim whitespaces and assign the content } break; case XML_CDATA_SECTION_NODE : // if the child is an XML CDATA SECTION NODE if (trim($child->textContent)){ // if the content is not empty $this->text = "<![CDATA[" . trim($child->textContent) . "]]>"; // trim whitespaces and assign the content } break; } } } } }
// exemple : $n = new XMLElement("people"); $n->addAttribute("xmlns:p", "http://example.org/ns"); $n->addAttribute("xmlns:t", "http://example.org/test"); $n->addChild("person", array("t:id"=>"1"), "p"); $n->person->setText("John Doe"); $n->addChild("person", array("t:id"=>"2","a:addr"=>"123 Street" ,"xmlns:a"=>"http://example.org/addr"), "p"); $n->person[1]->setText("<![CDATA[Susie Q. Public]]>"); echo $n;
/* output : <?xml version="1.0"?> <people xmlns:p="http://example.org/ns" xmlns:t="http://example.org/test"> <p:person t:id="1">John Doe</p:person> <p:person t:id="2" a:addr="123 Street" xmlns:a="http://example.org/addr"><![CDATA[Susie Q. Public]]></p:person> </people> */
$d = new DomDocument(); $d->loadXML($n->export()); echo $d->saveXML(); /* output : <?xml version="1.0"?> <people xmlns:p="http://example.org/ns" xmlns:t="http://example.org/test"> <p:person t:id="1">John Doe</p:person> <p:person xmlns:a="http://example.org/addr" t:id="2" a:addr="123 Street"><![CDATA[Susie Q. Public]]></p:person> </people> <?xml version="1.0"?> */
$n->import($d->documentElement); echo $n; /* output : <people xmlns:p="http://example.org/ns" xmlns:t="http://example.org/test"> <p:person t:id="1">John Doe</p:person> <p:person t:id="2" a:addr="123 Street" xmlns:a="http://example.org/addr"><![CDATA[Susie Q. Public]]></p:person> </people> */
?>
|