Created
January 19, 2011 09:07
-
-
Save Sija/785894 to your computer and use it in GitHub Desktop.
XML manipulation class found in dark corners of my hdd
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* | |
* @mainpage | |
* | |
* This library is free software; you can redistribute it and/or | |
* modify it under the terms of the GNU Lesser General Public | |
* License as published by the Free Software Foundation; either | |
* version 2.1 of the License, or (at your option) any later version. | |
* | |
* This library is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
* Lesser General Public License for more details. | |
* | |
*/ | |
/** | |
* @class EasyXMLNode | |
* @brief Basic EasyXML construct - it wraps DOMElement, and gives access to | |
* it's children nodes and attributes. Serialization is also supported. | |
* | |
* @author Dariusz "njoy" Paciorek | |
* @author Zbigniew "ShaXbee" Mandziejewicz | |
* @author Sijawusz Pur Rahnama | |
* @version 1.0 | |
* @date 01-2007 | |
*/ | |
class EasyXMLNode implements ArrayAccess { | |
//! Attributes | |
protected $_root; | |
protected $_node; | |
//! Used for serialization | |
protected static $_serializeRoot; | |
/** | |
* @brief Construct | |
* | |
* @param $root | |
* @param $node | |
*/ | |
public function __construct(DOMDocument $root, DOMNode $node) { | |
$this->_root = $root; | |
$this->_node = $node; | |
} | |
/** | |
* @brief Add node child | |
* | |
* @param $name | |
* @param $value | |
* @return EasyXMLNode | |
*/ | |
public function addChild($name, $value = null) { | |
if ($value) { | |
$node = $this->_root->createElement($name, $value); | |
} else { | |
$node = $this->_root->createElement($name); | |
} | |
$node = $this->_node->appendChild($node); | |
return new self($this->_root, $node); | |
} | |
/** | |
* @brief Remove child from node | |
* | |
* @param $name | |
*/ | |
public function removeChild($name = null) { | |
if ($name) { | |
$node = $this->getElementByTagName($name); | |
$this->_node->removeChild($node); | |
} else { | |
$node = $this->_node->cloneNode(false); | |
$parent = $this->_node->parentNode; | |
$parent->removeChild($this->_node); | |
$parent->appendChild($node); | |
} | |
} | |
/** | |
* @brief Load xml into node | |
* | |
* @param $xmlData | |
*/ | |
public function loadXMLString($xmlData) { | |
$fragment = $this->_root->createDocumentFragment(); | |
$fragment->appendXML($xmlData); | |
$fragment->formatOutput = true; | |
$node = $this->_node->cloneNode(false); | |
$node->appendChild($fragment); | |
$parent = $this->_node->parentNode; | |
$parent->removeChild($this->_node); | |
$parent->appendChild($node); | |
} | |
/** | |
* @brief Return node or document as XML | |
* | |
* @return string | |
*/ | |
public function asXML() { | |
if ($this->_node->isSameNode($this->_node)) { | |
return $this->_root->saveXML(); | |
} else { | |
return $this->_root->saveXML($this->_node); | |
} | |
return null; | |
} | |
/** | |
* ArrayAccess method. Set node attribute | |
*/ | |
public function offsetSet($key, $value) { | |
$this->_node->setAttribute($key, $value); | |
} | |
/** | |
* ArrayAccess .Get node attribute | |
*/ | |
public function offsetGet($key) { | |
return $this->_node->getAttribute($key); | |
} | |
/** | |
* ArrayAccess. Remove node attribute | |
*/ | |
public function offsetUnset($key) { | |
$this->_node->removeAttribute($key); | |
} | |
/** | |
* ArrayAccess . Check for node attribute exists | |
*/ | |
public function offsetExists($key) { | |
return $this->_node->hasAttribute($key); | |
} | |
/** | |
* @brief Return node | |
* | |
* @return object | |
*/ | |
public function getNode() { | |
return $this->_node; | |
} | |
/** | |
* @brief Return node with given name | |
* | |
* @param $name | |
* @return mixed | |
*/ | |
protected function getElementByTagName($name) { | |
$result = null; | |
$node = $this->_node->firstChild; | |
while ($node && !$result) { | |
if ($node->localName == $name || $node->nodeName == $name) { | |
$result = $node; | |
} | |
$node = $node->nextSibling; | |
} | |
return $result; | |
} | |
/** | |
* @brief Execute Xpath query on current node | |
* | |
* @param $query xpath query to execute | |
* @return EasyXMLResult | |
*/ | |
public function xpath($query) { | |
$xpath = new DOMXpath($this->_root); | |
$entries = @$xpath->query($query, $this->_node); | |
if ($entries && !$entries->length) { | |
$entries = null; | |
} | |
return ($entries ? new EasyXMLResult($this->_root, $entries) : false); | |
} | |
/** | |
* @brief Returns true if any node exists under given name or name and key | |
* | |
* @param $name | |
* @return bool | |
*/ | |
public function __isset($name) { | |
$node = $this->_node->firstChild; | |
while ($node) { | |
if ($name == $node->localName || $name == $node->nodeName) { | |
return true; | |
} | |
$node = $node->nextSibling; | |
} | |
return false; | |
} | |
/** | |
* @brief Get node by name or by name and key | |
* | |
* @param $name | |
* @return object | |
*/ | |
public function __get($name) { | |
$result = Array(); | |
$node = $this->_node->firstChild; | |
while ($node) { | |
if ($name == $node->localName || $name == $node->nodeName) { | |
$result[] = $node; | |
} | |
$node = $node->nextSibling; | |
} | |
return new EasyXMLResult($this->_root, $result); | |
} | |
/** | |
* @brief Set node value | |
* | |
* @param $name | |
* @param $value | |
*/ | |
public function __set($name, $value) { | |
$this->__unset($name); | |
if ($value instanceof self) { | |
$this->_node->appendChild($value->getNode()); | |
} else { | |
$node = $this->addChild($name); | |
$node->loadXMLString($value); | |
} | |
} | |
/** | |
* @brief Routes DOM method calls to underlaying DOMElement $node | |
*/ | |
public function __call($func, $args) { | |
if (method_exists($this->_node, $func)) { | |
return call_user_func_array(Array($this->_node, $func), $args); | |
} | |
} | |
/** | |
* @brief Removes node(s) with given name - called on unset($obj->$name) | |
* | |
* @param $name | |
*/ | |
public function __unset($name) { | |
$result = Array(); | |
$node = $this->_node->firstChild; | |
while ($node) { | |
if ($node->localName == $name || $node->nodeName == $name) { | |
$result[] = $node; | |
} | |
$node = $node->nextSibling; | |
} | |
foreach ($result as $node) { | |
$this->_node->removeChild($node); | |
} | |
} | |
/** | |
* @brief Return node as XML or node value | |
* | |
* @return string | |
*/ | |
public function __toString() { | |
if ($this->_node->hasChildNodes() && $this->_node->childNodes->length == 1 && $this->_node->firstChild->nodeType == XML_TEXT_NODE) { | |
return $this->_node->firstChild->nodeValue; | |
} else { | |
return $this->_root->saveXML($this->_node); | |
} | |
} | |
/** | |
* @brief Convert node to Array | |
* | |
* @param $node Node to convert | |
* @return Array with node attributes, childs and value | |
*/ | |
static protected function toArray($node) { | |
$attributes = Array(); | |
if ($node->nodeType == XML_ELEMENT_NODE) { | |
$name = $node->nodeName; | |
} | |
if (!$node instanceof DOMDocument) { | |
$nodes = $node->attributes; | |
if ($node->hasAttribute('xmlns')) { | |
$attributes['xmlns'] = $node->getAttribute('xmlns'); | |
} | |
for ($i = 0; $i < $nodes->length; ++$i) { | |
$attr = $nodes->item($i); | |
$attributes[$attr->name] = $attr->value; | |
} | |
} | |
$childs = Array(); | |
$nodes = $node->childNodes; | |
for ($i = 0; $i < $nodes->length; ++$i) { | |
$node = $nodes->item($i); | |
if ($node->nodeType == XML_ELEMENT_NODE) { | |
$childs[] = self::toArray($node); | |
} else if ($node->nodeType == XML_TEXT_NODE) { | |
$value = $node->nodeValue; | |
} | |
} | |
return compact('name', 'childs', 'attributes', 'value'); | |
} | |
/** | |
* @brief Converts current node to Array | |
* | |
* @return Array with node attributes, childs and value | |
*/ | |
public function getArray() { | |
return self::toArray($this->_node); | |
} | |
/** | |
* @brief Unserialize serialized xml document | |
* | |
* @param $node | |
* @param $data | |
*/ | |
protected static function fromArray($node, & $data) { | |
extract($data); | |
if (isset($value)) { | |
$textNode = self::$_serializeRoot->createTextNode($value); | |
$node->appendChild($textNode); | |
} | |
foreach ($childs as & $child) { | |
$newNode = self::$_serializeRoot->createElement($child['name']); | |
$node->appendChild($newNode); | |
self::fromArray($newNode, $child); | |
} | |
if (!$node instanceof DOMDocument) { | |
foreach ($attributes as $key => & $value) { | |
$node->setAttribute($key, $value); | |
} | |
} | |
} | |
} | |
/** | |
* @class EasyXMLResult | |
* @brief Queries result container, returned by EasyXMLNode::__get and | |
* EasyXMLNode::xpath | |
* | |
* @author Dariusz "njoy" Paciorek | |
* @author Zbigniew "ShaXbee" Mandziejewicz | |
* @author Sijawusz Pur Rahnama | |
* @version 1.0 | |
* @date 01-2007 | |
*/ | |
class EasyXMLResult extends EasyXMLNode implements Countable { | |
//! Array $data. Store nodes | |
protected $_data; | |
/** | |
* @brief Construct. Creates result object | |
*/ | |
public function __construct(DOMDocument $root, $data) { | |
$this->_root = $root; | |
if ($data instanceof DOMNodeList) { | |
$result = Array(); | |
foreach ($data as $row) { | |
$result[] = $row; | |
} | |
$data = $result; | |
} | |
$this->_node = count($data) ? $data[0] : null; | |
$this->_data = $data; | |
} | |
/** | |
* Check for node(s) with given index or node attribute | |
*/ | |
public function offsetExists($key) { | |
if (is_numeric($key)) { | |
return isset($this->_data[$key]); | |
} else { | |
return parent::offsetExists($key); | |
} | |
} | |
/** | |
* @brief Return node(s) with given index or node attribute | |
* | |
* @param $key | |
* @return mixed | |
*/ | |
public function offsetGet($key) { | |
if (is_numeric($key)) { | |
if (isset($this->_data[$key])) { | |
return new EasyXMLNode($this->_root, $this->_data[$key]); | |
} | |
} else { | |
return parent::offsetGet($key); | |
} | |
return null; | |
} | |
/** | |
* @brief Remove node | |
* | |
* @param $key | |
*/ | |
public function offsetUnset($key) { | |
if (is_numeric($key)) { | |
if (isset($this->_data[$key])) { | |
$this->data[$key]->parentNode->removeChild($this->_data[$key]); | |
} | |
} else { | |
return parent::offsetUnset($key); | |
} | |
} | |
/** | |
* @brief Return number of nodes | |
* | |
* @return integer | |
*/ | |
public function count() { | |
return count($this->_data); | |
} | |
} | |
/** | |
* @class EasyXML | |
* @brief DOMDocument wrapper, root for EasyXMLNode's | |
* | |
* @author Dariusz "njoy" Paciorek | |
* @author Zbigniew "ShaXbee" Mandziejewicz | |
* @author Sijawusz Pur Rahnama | |
* @version 1.0 | |
* @date 01-2007 | |
*/ | |
class EasyXML extends EasyXMLNode { | |
//! Serialization data | |
protected $_serialData; | |
/** | |
* @brief Construct | |
* | |
* @param $xmlData | |
*/ | |
public function __construct($xmlData = null) { | |
if ($xmlData) { | |
$this->_root = @DOMDocument::loadXML($xmlData); | |
} else { | |
$this->_root = new DOMDocument('1.0', 'utf-8'); | |
} | |
$this->_node = $this->_root; | |
$this->_root->formatOutput = true; | |
$this->_root->preserveWhiteSpace = false; | |
} | |
/** | |
* @brief Create new EasyXML object and load XML data from file | |
* | |
* @param $fileName XML File | |
* @return EasyXML | |
*/ | |
static public function loadXMLFile($fileName) { | |
if (file_exists($fileName)) { | |
$data = file_get_contents($fileName); | |
return new EasyXML($data); | |
} | |
return null; | |
} | |
/** | |
* @brief Serialization handler - called on serialize($obj); | |
* @return List of fields to serialize | |
*/ | |
public function __sleep() { | |
$this->_serialData = self::toArray($this->_node); | |
return Array('_serialData'); | |
} | |
/** | |
* @brief Unserialization handler - called on $obj = unserialize($data); | |
* Restores child nodes and document | |
*/ | |
public function __wakeup() { | |
$this->_node = new DOMDocument('1.0', 'utf-8'); | |
$this->_node->formatOutput = true; | |
$this->_root = $this->_node; | |
self::$_serializeRoot = $this->_node; | |
self::fromArray($this->_node, $this->_serialData); | |
// cleanup after unserialization | |
self::$_serializeRoot = null; | |
$this->_serialData = null; | |
} | |
/** | |
* @brief Return document as XML | |
* | |
* @return string | |
*/ | |
public function __toString() { | |
return $this->_root->saveXML(); | |
} | |
} | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// create object from string | |
$xml = new EasyXML('<root><check>someValue</check></root>'); | |
// or from file | |
$xml = EasyXML::loadXMLFile('file.xml'); | |
// set innerText of <check/> to given string, creates tag if not exists | |
$xml->root->check = '<someOtherValue/>'; | |
// set attribute value | |
$xml->root['attribute'] = 'attributeValue'; | |
// remove attribute | |
unset($xml->root['attribute']); | |
// add some <domain/> tags as children | |
$domain = $xml->root->check->addChild('domain'); | |
$otherDomain = $xml->root->check->addChild('domain'); | |
$domain['name'] = 'aqq.pl'; | |
// remove all <domain/> tags from given node | |
unset($xml->root->check->domain); | |
// use DOM-alike methods | |
$xml->root->firstChild; | |
$xml->root->hasAttribute('test'); | |
// you can use string to define tags | |
$xml->root->check = '<domain>aqq</domain><domain>bqq</domain>'; | |
// serialize it for later | |
$data = serialize($xml); | |
// get it in array format | |
$xml->getArray(); | |
// that works too! :) | |
$xml->xpath('//check'); | |
// print xml string | |
echo $xml; | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment