From 6c91102e14020e42776690eab12509af44847559 Mon Sep 17 00:00:00 2001 From: Chuck Hagenbuch Date: Sat, 15 Nov 2008 09:55:15 -0500 Subject: [PATCH] add Horde_Xml_Element to git --- framework/Xml_Element/CVS/Entries | 3 + framework/Xml_Element/CVS/Repository | 1 + framework/Xml_Element/CVS/Root | 1 + framework/Xml_Element/CVS/Template | 8 + framework/Xml_Element/lib/CVS/Entries | 1 + framework/Xml_Element/lib/CVS/Repository | 1 + framework/Xml_Element/lib/CVS/Root | 1 + framework/Xml_Element/lib/CVS/Template | 8 + framework/Xml_Element/lib/Horde/CVS/Entries | 1 + framework/Xml_Element/lib/Horde/CVS/Repository | 1 + framework/Xml_Element/lib/Horde/CVS/Root | 1 + framework/Xml_Element/lib/Horde/CVS/Template | 8 + framework/Xml_Element/lib/Horde/Xml/CVS/Entries | 2 + framework/Xml_Element/lib/Horde/Xml/CVS/Repository | 1 + framework/Xml_Element/lib/Horde/Xml/CVS/Root | 1 + framework/Xml_Element/lib/Horde/Xml/CVS/Template | 8 + framework/Xml_Element/lib/Horde/Xml/Element.php | 590 +++++++++++++++++++++ .../Xml_Element/lib/Horde/Xml/Element/CVS/Entries | 3 + .../lib/Horde/Xml/Element/CVS/Repository | 1 + .../Xml_Element/lib/Horde/Xml/Element/CVS/Root | 1 + .../Xml_Element/lib/Horde/Xml/Element/CVS/Template | 8 + .../lib/Horde/Xml/Element/Exception.php | 40 ++ .../Xml_Element/lib/Horde/Xml/Element/List.php | 123 +++++ framework/Xml_Element/package.xml | 71 +++ framework/Xml_Element/test/CVS/Entries | 1 + framework/Xml_Element/test/CVS/Repository | 1 + framework/Xml_Element/test/CVS/Root | 1 + framework/Xml_Element/test/CVS/Template | 8 + framework/Xml_Element/test/Horde/CVS/Entries | 1 + framework/Xml_Element/test/Horde/CVS/Repository | 1 + framework/Xml_Element/test/Horde/CVS/Root | 1 + framework/Xml_Element/test/Horde/CVS/Template | 8 + framework/Xml_Element/test/Horde/Xml/CVS/Entries | 1 + .../Xml_Element/test/Horde/Xml/CVS/Repository | 1 + framework/Xml_Element/test/Horde/Xml/CVS/Root | 1 + framework/Xml_Element/test/Horde/Xml/CVS/Template | 8 + .../test/Horde/Xml/Element/AllTests.php | 49 ++ .../Xml_Element/test/Horde/Xml/Element/CVS/Entries | 5 + .../test/Horde/Xml/Element/CVS/Repository | 1 + .../Xml_Element/test/Horde/Xml/Element/CVS/Root | 1 + .../test/Horde/Xml/Element/CVS/Template | 8 + .../test/Horde/Xml/Element/CountTest.php | 40 ++ .../test/Horde/Xml/Element/ElementTest.php | 249 +++++++++ .../test/Horde/Xml/Element/IteratorTest.php | 80 +++ .../test/Horde/Xml/Element/fixtures/CVS/Entries | 3 + .../test/Horde/Xml/Element/fixtures/CVS/Repository | 1 + .../test/Horde/Xml/Element/fixtures/CVS/Root | 1 + .../test/Horde/Xml/Element/fixtures/CVS/Template | 8 + .../Xml/Element/fixtures/NamespacedSample.xml | 34 ++ .../test/Horde/Xml/Element/fixtures/Sample.xml | 34 ++ 50 files changed, 1431 insertions(+) create mode 100644 framework/Xml_Element/CVS/Entries create mode 100644 framework/Xml_Element/CVS/Repository create mode 100644 framework/Xml_Element/CVS/Root create mode 100644 framework/Xml_Element/CVS/Template create mode 100644 framework/Xml_Element/lib/CVS/Entries create mode 100644 framework/Xml_Element/lib/CVS/Repository create mode 100644 framework/Xml_Element/lib/CVS/Root create mode 100644 framework/Xml_Element/lib/CVS/Template create mode 100644 framework/Xml_Element/lib/Horde/CVS/Entries create mode 100644 framework/Xml_Element/lib/Horde/CVS/Repository create mode 100644 framework/Xml_Element/lib/Horde/CVS/Root create mode 100644 framework/Xml_Element/lib/Horde/CVS/Template create mode 100644 framework/Xml_Element/lib/Horde/Xml/CVS/Entries create mode 100644 framework/Xml_Element/lib/Horde/Xml/CVS/Repository create mode 100644 framework/Xml_Element/lib/Horde/Xml/CVS/Root create mode 100644 framework/Xml_Element/lib/Horde/Xml/CVS/Template create mode 100644 framework/Xml_Element/lib/Horde/Xml/Element.php create mode 100644 framework/Xml_Element/lib/Horde/Xml/Element/CVS/Entries create mode 100644 framework/Xml_Element/lib/Horde/Xml/Element/CVS/Repository create mode 100644 framework/Xml_Element/lib/Horde/Xml/Element/CVS/Root create mode 100644 framework/Xml_Element/lib/Horde/Xml/Element/CVS/Template create mode 100644 framework/Xml_Element/lib/Horde/Xml/Element/Exception.php create mode 100644 framework/Xml_Element/lib/Horde/Xml/Element/List.php create mode 100644 framework/Xml_Element/package.xml create mode 100644 framework/Xml_Element/test/CVS/Entries create mode 100644 framework/Xml_Element/test/CVS/Repository create mode 100644 framework/Xml_Element/test/CVS/Root create mode 100644 framework/Xml_Element/test/CVS/Template create mode 100644 framework/Xml_Element/test/Horde/CVS/Entries create mode 100644 framework/Xml_Element/test/Horde/CVS/Repository create mode 100644 framework/Xml_Element/test/Horde/CVS/Root create mode 100644 framework/Xml_Element/test/Horde/CVS/Template create mode 100644 framework/Xml_Element/test/Horde/Xml/CVS/Entries create mode 100644 framework/Xml_Element/test/Horde/Xml/CVS/Repository create mode 100644 framework/Xml_Element/test/Horde/Xml/CVS/Root create mode 100644 framework/Xml_Element/test/Horde/Xml/CVS/Template create mode 100644 framework/Xml_Element/test/Horde/Xml/Element/AllTests.php create mode 100644 framework/Xml_Element/test/Horde/Xml/Element/CVS/Entries create mode 100644 framework/Xml_Element/test/Horde/Xml/Element/CVS/Repository create mode 100644 framework/Xml_Element/test/Horde/Xml/Element/CVS/Root create mode 100644 framework/Xml_Element/test/Horde/Xml/Element/CVS/Template create mode 100644 framework/Xml_Element/test/Horde/Xml/Element/CountTest.php create mode 100644 framework/Xml_Element/test/Horde/Xml/Element/ElementTest.php create mode 100644 framework/Xml_Element/test/Horde/Xml/Element/IteratorTest.php create mode 100644 framework/Xml_Element/test/Horde/Xml/Element/fixtures/CVS/Entries create mode 100644 framework/Xml_Element/test/Horde/Xml/Element/fixtures/CVS/Repository create mode 100644 framework/Xml_Element/test/Horde/Xml/Element/fixtures/CVS/Root create mode 100644 framework/Xml_Element/test/Horde/Xml/Element/fixtures/CVS/Template create mode 100644 framework/Xml_Element/test/Horde/Xml/Element/fixtures/NamespacedSample.xml create mode 100644 framework/Xml_Element/test/Horde/Xml/Element/fixtures/Sample.xml diff --git a/framework/Xml_Element/CVS/Entries b/framework/Xml_Element/CVS/Entries new file mode 100644 index 000000000..506dc156f --- /dev/null +++ b/framework/Xml_Element/CVS/Entries @@ -0,0 +1,3 @@ +D/lib//// +D/test//// +/package.xml/1.15/Fri Sep 26 12:37:16 2008// diff --git a/framework/Xml_Element/CVS/Repository b/framework/Xml_Element/CVS/Repository new file mode 100644 index 000000000..0f9672a9c --- /dev/null +++ b/framework/Xml_Element/CVS/Repository @@ -0,0 +1 @@ +framework/Xml_Element diff --git a/framework/Xml_Element/CVS/Root b/framework/Xml_Element/CVS/Root new file mode 100644 index 000000000..5d636129a --- /dev/null +++ b/framework/Xml_Element/CVS/Root @@ -0,0 +1 @@ +chuck@cvs.horde.org:/repository diff --git a/framework/Xml_Element/CVS/Template b/framework/Xml_Element/CVS/Template new file mode 100644 index 000000000..3971591f9 --- /dev/null +++ b/framework/Xml_Element/CVS/Template @@ -0,0 +1,8 @@ + +Bug: +Submitted by: +Merge after: +CVS: ---------------------------------------------------------------------- +CVS: Bug: Fill this in if a listed bug is affected by the change. +CVS: Submitted by: Fill this in if someone else sent in the change. +CVS: Merge after: N [day[s]|week[s]|month[s]] (days assumed by default) diff --git a/framework/Xml_Element/lib/CVS/Entries b/framework/Xml_Element/lib/CVS/Entries new file mode 100644 index 000000000..ae2779e30 --- /dev/null +++ b/framework/Xml_Element/lib/CVS/Entries @@ -0,0 +1 @@ +D/Horde//// diff --git a/framework/Xml_Element/lib/CVS/Repository b/framework/Xml_Element/lib/CVS/Repository new file mode 100644 index 000000000..1f30f7719 --- /dev/null +++ b/framework/Xml_Element/lib/CVS/Repository @@ -0,0 +1 @@ +framework/Xml_Element/lib diff --git a/framework/Xml_Element/lib/CVS/Root b/framework/Xml_Element/lib/CVS/Root new file mode 100644 index 000000000..5d636129a --- /dev/null +++ b/framework/Xml_Element/lib/CVS/Root @@ -0,0 +1 @@ +chuck@cvs.horde.org:/repository diff --git a/framework/Xml_Element/lib/CVS/Template b/framework/Xml_Element/lib/CVS/Template new file mode 100644 index 000000000..3971591f9 --- /dev/null +++ b/framework/Xml_Element/lib/CVS/Template @@ -0,0 +1,8 @@ + +Bug: +Submitted by: +Merge after: +CVS: ---------------------------------------------------------------------- +CVS: Bug: Fill this in if a listed bug is affected by the change. +CVS: Submitted by: Fill this in if someone else sent in the change. +CVS: Merge after: N [day[s]|week[s]|month[s]] (days assumed by default) diff --git a/framework/Xml_Element/lib/Horde/CVS/Entries b/framework/Xml_Element/lib/Horde/CVS/Entries new file mode 100644 index 000000000..02b1fd18d --- /dev/null +++ b/framework/Xml_Element/lib/Horde/CVS/Entries @@ -0,0 +1 @@ +D/Xml//// diff --git a/framework/Xml_Element/lib/Horde/CVS/Repository b/framework/Xml_Element/lib/Horde/CVS/Repository new file mode 100644 index 000000000..d29755705 --- /dev/null +++ b/framework/Xml_Element/lib/Horde/CVS/Repository @@ -0,0 +1 @@ +framework/Xml_Element/lib/Horde diff --git a/framework/Xml_Element/lib/Horde/CVS/Root b/framework/Xml_Element/lib/Horde/CVS/Root new file mode 100644 index 000000000..5d636129a --- /dev/null +++ b/framework/Xml_Element/lib/Horde/CVS/Root @@ -0,0 +1 @@ +chuck@cvs.horde.org:/repository diff --git a/framework/Xml_Element/lib/Horde/CVS/Template b/framework/Xml_Element/lib/Horde/CVS/Template new file mode 100644 index 000000000..3971591f9 --- /dev/null +++ b/framework/Xml_Element/lib/Horde/CVS/Template @@ -0,0 +1,8 @@ + +Bug: +Submitted by: +Merge after: +CVS: ---------------------------------------------------------------------- +CVS: Bug: Fill this in if a listed bug is affected by the change. +CVS: Submitted by: Fill this in if someone else sent in the change. +CVS: Merge after: N [day[s]|week[s]|month[s]] (days assumed by default) diff --git a/framework/Xml_Element/lib/Horde/Xml/CVS/Entries b/framework/Xml_Element/lib/Horde/Xml/CVS/Entries new file mode 100644 index 000000000..22b59a1f7 --- /dev/null +++ b/framework/Xml_Element/lib/Horde/Xml/CVS/Entries @@ -0,0 +1,2 @@ +D/Element//// +/Element.php/1.14/Sat Sep 27 14:56:17 2008// diff --git a/framework/Xml_Element/lib/Horde/Xml/CVS/Repository b/framework/Xml_Element/lib/Horde/Xml/CVS/Repository new file mode 100644 index 000000000..639123f8a --- /dev/null +++ b/framework/Xml_Element/lib/Horde/Xml/CVS/Repository @@ -0,0 +1 @@ +framework/Xml_Element/lib/Horde/Xml diff --git a/framework/Xml_Element/lib/Horde/Xml/CVS/Root b/framework/Xml_Element/lib/Horde/Xml/CVS/Root new file mode 100644 index 000000000..5d636129a --- /dev/null +++ b/framework/Xml_Element/lib/Horde/Xml/CVS/Root @@ -0,0 +1 @@ +chuck@cvs.horde.org:/repository diff --git a/framework/Xml_Element/lib/Horde/Xml/CVS/Template b/framework/Xml_Element/lib/Horde/Xml/CVS/Template new file mode 100644 index 000000000..3971591f9 --- /dev/null +++ b/framework/Xml_Element/lib/Horde/Xml/CVS/Template @@ -0,0 +1,8 @@ + +Bug: +Submitted by: +Merge after: +CVS: ---------------------------------------------------------------------- +CVS: Bug: Fill this in if a listed bug is affected by the change. +CVS: Submitted by: Fill this in if someone else sent in the change. +CVS: Merge after: N [day[s]|week[s]|month[s]] (days assumed by default) diff --git a/framework/Xml_Element/lib/Horde/Xml/Element.php b/framework/Xml_Element/lib/Horde/Xml/Element.php new file mode 100644 index 000000000..8f89c827d --- /dev/null +++ b/framework/Xml_Element/lib/Horde/Xml/Element.php @@ -0,0 +1,590 @@ + + * @license http://opensource.org/licenses/bsd-license.php BSD + * @category Horde + * @package Horde_Xml_Element + */ + +/** + * Wraps a DOMElement allowing for SimpleXML-like access to attributes. + * + * @method mixed TAGNAME() To get the un-wrapped value of a node, use + * method syntax ($xml_element->tagname()). This will return the + * string value of the tag if it is a single tag, an array of + * Horde_Xml_Element objects if there are multiple tags, or null if + * the tag does not exist. + * + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php BSD + * @category Horde + * @package Horde_Xml_Element + */ +class Horde_Xml_Element implements ArrayAccess +{ + /** + * @var array + */ + protected static $_namespaces = array( + 'opensearch' => 'http://a9.com/-/spec/opensearchrss/1.0/', + 'atom' => 'http://www.w3.org/2005/Atom', + 'rss' => 'http://blogs.law.harvard.edu/tech/rss', + 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns', + ); + + /** + * Get the full version of a namespace prefix + * + * Looks up a prefix (atom:, etc.) in the list of registered + * namespaces and returns the full namespace URI if + * available. Returns the prefix, unmodified, if it's not + * registered. + * + * @return string + */ + public static function lookupNamespace($prefix) + { + return isset(self::$_namespaces[$prefix]) ? + self::$_namespaces[$prefix] : + $prefix; + } + + /** + * Add a namespace and prefix to the registered list + * + * Takes a prefix and a full namespace URI and adds them to the + * list of registered namespaces for use by + * Horde_Xml_Element::lookupNamespace(). + * + * @param string $prefix The namespace prefix + * @param string $namespaceURI The full namespace URI + */ + public static function registerNamespace($prefix, $namespaceURI) + { + self::$_namespaces[$prefix] = $namespaceURI; + } + + /** + * @var DOMElement + */ + protected $_element; + + /** + * A string representation of the element, used when + * serializing/unserializing. + * + * @var string + */ + protected $_serialized; + + /** + * @var Horde_Xml_Element + */ + protected $_parentElement; + + /** + * @var array + */ + protected $_children = null; + + /** + * @var boolean + */ + protected $_appended = true; + + /** + * Horde_Xml_Element constructor. + * + * @param DOMElement | Horde_Xml_Element | string $element The DOM element, + * pre-existing Horde_Xml_Element, or XML string that we're encapsulating. + */ + public function __construct($element) + { + $this->_element = $element; + $this->__wakeup(); + } + + /** + * Get a DOM representation of the element + * + * Returns the underlying DOM object, which can then be + * manipulated with full DOM methods. + * + * @return DOMDocument + */ + public function getDom() + { + return $this->_element; + } + + /** + * Update the object from a DOM element + * + * Take a DOMElement object, which may be originally from a call + * to getDom() or may be custom created, and use it as the + * DOM tree for this Horde_Xml_Element. + * + * @param DOMElement $element + */ + public function setDom(DOMElement $element) + { + $this->_element = $this->_element->ownerDocument->importNode($element, true); + } + + /** + * Add child elements and attributes to this element from a simple + * key => value hash. Keys can be: + * + * ElementName -> <$ElementName> will be appended with + * a value of $value + * #AttributeName -> An attribute $AttributeName will be + * added to this element with a value + * of $value + * ElementName#AttributeName -> <$ElementName> will be appended to this + * element if it doesn't already exist, + * and have its attribute $AttributeName + * set to $value + * + * @param $array Hash to import into this element. + */ + public function fromArray($array) + { + foreach ($array as $key => $value) { + $element = null; + $attribute = null; + + $hash_position = strpos($key, '#'); + if ($hash_position === false) { + $element = $key; + } elseif ($hash_position === 0) { + $attribute = substr($key, 1); + } else { + list($element, $attribute) = explode('#', $key, 2); + } + + if (!is_null($element)) { + if (!is_null($attribute)) { + $this->{$element}[$attribute] = $value; + } else { + if (is_array($value)) { + $this->$element->fromArray($value); + } else { + $this->$element = $value; + } + } + } elseif (!is_null($attribute)) { + $this[$attribute] = $value; + } + } + } + + /** + * Append a child node to this element. + * + * @param Horde_Xml_Element $element The element to append. + */ + public function appendChild(Horde_Xml_Element $element) + { + $element->setParent($this); + $element->_ensureAppended(); + $this->_expireCachedChildren(); + } + + /** + * Get an XML string representation of this element + * + * Returns a string of this element's XML, including the XML + * prologue. + * + * @return string + */ + public function saveXml() + { + // Return a complete document including XML prologue. + $doc = new DOMDocument($this->_element->ownerDocument->version, + $this->_element->ownerDocument->actualEncoding); + $doc->appendChild($doc->importNode($this->_element, true)); + return $doc->saveXML(); + } + + /** + * Get the XML for only this element + * + * Returns a string of this element's XML without prologue. + * + * @return string + */ + public function saveXmlFragment() + { + return $this->_element->ownerDocument->saveXML($this->_element); + } + + /** + * Unserialization handler; handles $this->_element being an instance of + * DOMElement or Horde_Xml_Element, or parses it as an XML string. + */ + public function __wakeup() + { + if ($this->_element instanceof DOMElement) { + return true; + } + + if ($this->_element instanceof Horde_Xml_Element) { + $this->_element = $this->_element->getDom(); + return true; + } + + if ($this->_serialized) { + $this->_element = $this->_serialized; + $this->_serialized = null; + } + + if (is_string($this->_element)) { + $doc = new DOMDocument; + $doc->preserveWhiteSpace = false; + $e = error_reporting(0); + $loaded = $doc->loadXML($this->_element); + error_reporting($e); + if (!$loaded) { + throw new Horde_Xml_Element_Exception('DOMDocument cannot parse XML: ', error_get_last()); + } + + $this->_element = $doc->documentElement; + return true; + } + + throw new InvalidArgumentException('Horde_Xml_Element initialization value must be a DOMElement, a Horde_Xml_Element, or a non-empty string; ' + . (gettype($this->_element) == 'object' ? get_class($this->_element) : gettype($this->_element)) + . ' given'); + } + + /** + * Prepare for serialization + * + * @return array + */ + public function __sleep() + { + $this->_serialized = $this->saveXml(); + return array('_serialized'); + } + + /** + * Map variable access onto the underlying entry representation. + * + * Get-style access returns a Horde_Xml_Element representing the + * child element accessed. To get string values, use method syntax + * with the __call() overriding. + * + * @param string $var The property to access. + * @return mixed + */ + public function __get($var) + { + $nodes = $this->_children($var); + $length = count($nodes); + + if ($length == 1) { + if ($nodes[0] instanceof Horde_Xml_Element) { + return $nodes[0]; + } + return new Horde_Xml_Element($nodes[0]); + } elseif ($length > 1) { + if ($nodes[0] instanceof Horde_Xml_Element) { + return $nodes; + } + return array_map(create_function('$e', 'return new Horde_Xml_Element($e);'), $nodes); + } else { + // When creating anonymous nodes for __set chaining, don't + // call appendChild() on them. Instead we pass the current + // element to them as an extra reference; the child is + // then responsible for appending itself when it is + // actually set. This way "if ($foo->bar)" doesn't create + // a phantom "bar" element in our tree. + if (strpos($var, ':') !== false) { + list($ns, $elt) = explode(':', $var, 2); + $node = $this->_element->ownerDocument->createElementNS(Horde_Xml_Element::lookupNamespace($ns), $elt); + } else { + $node = $this->_element->ownerDocument->createElement($var); + } + $node = new Horde_Xml_Element($node); + $node->setParent($this); + return $node; + } + } + + /** + * Map variable sets onto the underlying entry representation. + * + * @param string $var The property to change. + * @param string $val The property's new value. + */ + public function __set($var, $val) + { + if (!is_scalar($val)) { + throw new InvalidArgumentException('Element values must be scalars, ' . gettype($val) . ' given'); + } + + $this->_ensureAppended(); + + $nodes = $this->_children($var); + if (!$nodes) { + if (strpos($var, ':') !== false) { + list($ns, $elt) = explode(':', $var, 2); + $node = $this->_element->ownerDocument->createElementNS(Horde_Xml_Element::lookupNamespace($ns), $var, $val); + $this->_element->appendChild($node); + } else { + $node = $this->_element->ownerDocument->createElement($var, $val); + $this->_element->appendChild($node); + } + + $this->_expireCachedChildren(); + } elseif (count($nodes) > 1) { + throw new Horde_Xml_Element_Exception('Cannot set the value of multiple nodes simultaneously.'); + } else { + $nodes[0]->nodeValue = $val; + } + } + + /** + * Map isset calls onto the underlying entry representation. + */ + public function __isset($var) + { + return (boolean)$this->_children($var); + } + + /** + * Get the value of an element with method syntax. + * + * Map method calls to get the string value of the requested + * element. If there are multiple elements that match, this will + * return an array of those objects. + * + * @param string $var The element to get the string value of. + * + * @return mixed The node's value, null, or an array of nodes. + */ + public function __call($var, $unused) + { + $nodes = $this->_children($var); + + if (!$nodes) { + return null; + } elseif (count($nodes) > 1) { + if ($nodes[0] instanceof Horde_Xml_Element) { + return $nodes; + } + return array_map(create_function('$e', 'return new Horde_Xml_Element($e);'), $nodes); + } else { + if ($nodes[0] instanceof Horde_Xml_Element) { + return (string)$nodes[0]; + } else { + return $nodes[0]->nodeValue; + } + } + } + + /** + * Remove all children matching $var. + */ + public function __unset($var) + { + $nodes = $this->_children($var); + foreach ($nodes as $node) { + $parent = $node->parentNode; + $parent->removeChild($node); + } + + $this->_expireCachedChildren(); + } + + /** + * Returns the nodeValue of this element when this object is used + * in a string context. + * + * @internal + */ + public function __toString() + { + return $this->_element->nodeValue; + } + + /** + * Set the parent element of this object to another + * Horde_Xml_Element. + * + * @internal + */ + public function setParent(Horde_Xml_Element $element) + { + $this->_parentElement = $element; + $this->_appended = false; + } + + /** + * Appends this element to its parent if necessary. + * + * @internal + */ + protected function _ensureAppended() + { + if (!$this->_appended) { + $parentDom = $this->_parentElement->getDom(); + if (!$parentDom->ownerDocument->isSameNode($this->_element->ownerDocument)) { + $this->_element = $parentDom->ownerDocument->importNode($this->_element, true); + } + + $parentDom->appendChild($this->_element); + $this->_appended = true; + $this->_parentElement->_ensureAppended(); + } + } + + /** + * Finds children with tagnames matching $var + * + * Similar to SimpleXML's children() method. + * + * @param string Tagname to match, can be either namespace:tagName or just tagName. + * @return array + */ + protected function _children($var) + { + if (is_null($this->_children)) + $this->_cacheChildren(); + + // Honor any explicit getters. Because Horde_Xml_Element has a __call() + // method, is_callable returns true on every method name. Use + // method_exists instead. + $varMethod = 'get' . ucfirst($var); + if (method_exists($this, $varMethod)) { + $children = call_user_func(array($this, $varMethod)); + if (is_null($children)) { + $this->_children[$var] = array(); + } elseif (!is_array($children)) { + $this->_children[$var] = array($children); + } else { + $this->_children[$var] = $children; + } + } + + if (!isset($this->_children[$var])) { + $this->_children[$var] = array(); + } + + return $this->_children[$var]; + } + + /** + * Build a cache of child nodes. + */ + protected function _cacheChildren() + { + foreach ($this->_element->childNodes as $child) { + if (!isset($this->_children[$child->localName])) + $this->_children[$child->localName] = array(); + $this->_children[$child->localName][] = $child; + + if ($child->prefix) { + if (!isset($this->_children[$child->prefix . ':' . $child->localName])) + $this->_children[$child->prefix . ':' . $child->localName] = array(); + $this->_children[$child->prefix . ':' . $child->localName][] = $child; + } + } + } + + /** + * Expire cached children. + */ + protected function _expireCachedChildren() + { + $this->_children = null; + } + + /** + * Required by the ArrayAccess interface. + * + * @internal + */ + public function offsetExists($offset) + { + if (strpos($offset, ':') !== false) { + list($ns, $attr) = explode(':', $offset, 2); + return $this->_element->hasAttributeNS(Horde_Xml_Element::lookupNamespace($ns), $attr); + } else { + return $this->_element->hasAttribute($offset); + } + } + + /** + * Required by the ArrayAccess interface. + * + * @internal + */ + public function offsetGet($offset) + { + if (strpos($offset, ':') !== false) { + list($ns, $attr) = explode(':', $offset, 2); + return $this->_element->getAttributeNS(Horde_Xml_Element::lookupNamespace($ns), $attr); + } else { + return $this->_element->getAttribute($offset); + } + } + + /** + * Required by the ArrayAccess interface. + * + * @internal + */ + public function offsetSet($offset, $value) + { + if (!is_scalar($value)) { + throw new InvalidArgumentException('Element values must be scalars, ' . gettype($value) . ' given'); + } + + $this->_ensureAppended(); + + if (strpos($offset, ':') !== false) { + list($ns, $attr) = explode(':', $offset, 2); + $result = $this->_element->setAttributeNS(Horde_Xml_Element::lookupNamespace($ns), $attr, $value); + } else { + $result = $this->_element->setAttribute($offset, $value); + } + + if ($result) { + $this->_expireCachedChildren(); + return true; + } else { + return false; + } + } + + /** + * Required by the ArrayAccess interface. + * + * @internal + */ + public function offsetUnset($offset) + { + if (strpos($offset, ':') !== false) { + list($ns, $attr) = explode(':', $offset, 2); + $result = $this->_element->removeAttributeNS(Horde_Xml_Element::lookupNamespace($ns), $attr); + } else { + $result = $this->_element->removeAttribute($offset); + } + + if ($result) { + $this->_expireCachedChildren(); + return true; + } else { + return false; + } + } + +} diff --git a/framework/Xml_Element/lib/Horde/Xml/Element/CVS/Entries b/framework/Xml_Element/lib/Horde/Xml/Element/CVS/Entries new file mode 100644 index 000000000..bd4a9dc01 --- /dev/null +++ b/framework/Xml_Element/lib/Horde/Xml/Element/CVS/Entries @@ -0,0 +1,3 @@ +/Exception.php/1.3/Tue Jul 29 15:52:47 2008// +/List.php/1.3/Tue Jul 29 15:52:47 2008// +D diff --git a/framework/Xml_Element/lib/Horde/Xml/Element/CVS/Repository b/framework/Xml_Element/lib/Horde/Xml/Element/CVS/Repository new file mode 100644 index 000000000..39c827d07 --- /dev/null +++ b/framework/Xml_Element/lib/Horde/Xml/Element/CVS/Repository @@ -0,0 +1 @@ +framework/Xml_Element/lib/Horde/Xml/Element diff --git a/framework/Xml_Element/lib/Horde/Xml/Element/CVS/Root b/framework/Xml_Element/lib/Horde/Xml/Element/CVS/Root new file mode 100644 index 000000000..5d636129a --- /dev/null +++ b/framework/Xml_Element/lib/Horde/Xml/Element/CVS/Root @@ -0,0 +1 @@ +chuck@cvs.horde.org:/repository diff --git a/framework/Xml_Element/lib/Horde/Xml/Element/CVS/Template b/framework/Xml_Element/lib/Horde/Xml/Element/CVS/Template new file mode 100644 index 000000000..3971591f9 --- /dev/null +++ b/framework/Xml_Element/lib/Horde/Xml/Element/CVS/Template @@ -0,0 +1,8 @@ + +Bug: +Submitted by: +Merge after: +CVS: ---------------------------------------------------------------------- +CVS: Bug: Fill this in if a listed bug is affected by the change. +CVS: Submitted by: Fill this in if someone else sent in the change. +CVS: Merge after: N [day[s]|week[s]|month[s]] (days assumed by default) diff --git a/framework/Xml_Element/lib/Horde/Xml/Element/Exception.php b/framework/Xml_Element/lib/Horde/Xml/Element/Exception.php new file mode 100644 index 000000000..500679f77 --- /dev/null +++ b/framework/Xml_Element/lib/Horde/Xml/Element/Exception.php @@ -0,0 +1,40 @@ + + * @license http://opensource.org/licenses/bsd-license.php BSD + * @category Horde + * @package Horde_Xml_Element + */ + +/** + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php BSD + * @category Horde + * @package Horde_Xml_Element + */ +class Horde_Xml_Element_Exception extends Exception +{ + /** + * Create an exception, filling in some details from the result of + * error_get_last if they are passed in $code_or_lasterror. + */ + public function __construct($message = null, $code_or_lasterror = 0) + { + if (is_array($code_or_lasterror)) { + if ($message) { + $message .= $code_or_lasterror['message']; + } else { + $message = $code_or_lasterror['message']; + } + + $this->file = $code_or_lasterror['file']; + $this->line = $code_or_lasterror['line']; + $code = $code_or_lasterror['type']; + } else { + $code = $code_or_lasterror; + } + + parent::__construct($message, $code); + } + +} diff --git a/framework/Xml_Element/lib/Horde/Xml/Element/List.php b/framework/Xml_Element/lib/Horde/Xml/Element/List.php new file mode 100644 index 000000000..95ca636d7 --- /dev/null +++ b/framework/Xml_Element/lib/Horde/Xml/Element/List.php @@ -0,0 +1,123 @@ + + * @license http://opensource.org/licenses/bsd-license.php BSD + * @category Horde + * @package Horde_Xml_Element + */ + +/** + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php BSD + * @category Horde + * @package Horde_Xml_Element + */ +abstract class Horde_Xml_Element_List extends Horde_Xml_Element implements Countable, Iterator +{ + /** + * Cache of list items. + * @var array + */ + protected $_listItems; + + /** + * Current index on the collection of list items for the Iterator + * implementation. + * @var integer + */ + protected $_listItemIndex = 0; + + /** + * The classname for individual list items. + * @var string + */ + protected $_listItemClassName = 'Horde_Xml_Element'; + + /** + * Ensure that $_listItems is populated by calling the concrete implementation's + * _buildItemsCache() method. + */ + public function __wakeup() + { + parent::__wakeup(); + + $this->_listItems = $this->_buildListItemCache(); + } + + /** + * Called by __wakeup to cache list items. Must be implemented in the + * extending class to return the array of list items. + * @return array + */ + abstract protected function _buildListItemCache(); + + /** + * Get the number of items in this list. + * + * @return integer Item count. + */ + public function count() + { + return count($this->_listItems); + } + + /** + * Required by the Iterator interface. + * + * @internal + */ + public function rewind() + { + $this->_listItemIndex = 0; + } + + /** + * Required by the Iterator interface. + * + * @internal + * + * @return mixed The current row, or null if no rows. + */ + public function current() + { + return new $this->_listItemClassName( + $this->_listItems[$this->_listItemIndex]); + } + + /** + * Required by the Iterator interface. + * + * @internal + * + * @return mixed The current row number (starts at 0), or null if no rows + */ + public function key() + { + return $this->_listItemIndex; + } + + /** + * Required by the Iterator interface. + * + * @internal + * + * @return mixed The next row, or null if no more rows. + */ + public function next() + { + ++$this->_listItemIndex; + } + + /** + * Required by the Iterator interface. + * + * @internal + * + * @return boolean Whether the iteration is valid + */ + public function valid() + { + return (0 <= $this->_listItemIndex && $this->_listItemIndex < count($this->_listItems)); + } + +} diff --git a/framework/Xml_Element/package.xml b/framework/Xml_Element/package.xml new file mode 100644 index 000000000..b97142ee6 --- /dev/null +++ b/framework/Xml_Element/package.xml @@ -0,0 +1,71 @@ + + + Xml_Element + pear.horde.org + Horde Xml Element object + This package provides an element object that can be used + to provide SimpleXML-like functionality over a DOM object. The main + advantage over using SimpleXML is the ability to add multiple levels + of new elements in a single call, without introducing "ghost" objects. + + + Chuck Hagenbuch + chuck + chuck@horde.org + yes + + + Jan Schneider + jan + jan@horde.org + yes + + 2008-09-25 + + 0.4.2 + 0.4.0 + + + beta + beta + + BSD + +* Avoid errors when a child node doesn't exist. + + + + + + + + + + + + + + + + + + + + 5.2.0 + + + 1.5.0 + + + + + + + + + + + diff --git a/framework/Xml_Element/test/CVS/Entries b/framework/Xml_Element/test/CVS/Entries new file mode 100644 index 000000000..ae2779e30 --- /dev/null +++ b/framework/Xml_Element/test/CVS/Entries @@ -0,0 +1 @@ +D/Horde//// diff --git a/framework/Xml_Element/test/CVS/Repository b/framework/Xml_Element/test/CVS/Repository new file mode 100644 index 000000000..d27384575 --- /dev/null +++ b/framework/Xml_Element/test/CVS/Repository @@ -0,0 +1 @@ +framework/Xml_Element/test diff --git a/framework/Xml_Element/test/CVS/Root b/framework/Xml_Element/test/CVS/Root new file mode 100644 index 000000000..5d636129a --- /dev/null +++ b/framework/Xml_Element/test/CVS/Root @@ -0,0 +1 @@ +chuck@cvs.horde.org:/repository diff --git a/framework/Xml_Element/test/CVS/Template b/framework/Xml_Element/test/CVS/Template new file mode 100644 index 000000000..3971591f9 --- /dev/null +++ b/framework/Xml_Element/test/CVS/Template @@ -0,0 +1,8 @@ + +Bug: +Submitted by: +Merge after: +CVS: ---------------------------------------------------------------------- +CVS: Bug: Fill this in if a listed bug is affected by the change. +CVS: Submitted by: Fill this in if someone else sent in the change. +CVS: Merge after: N [day[s]|week[s]|month[s]] (days assumed by default) diff --git a/framework/Xml_Element/test/Horde/CVS/Entries b/framework/Xml_Element/test/Horde/CVS/Entries new file mode 100644 index 000000000..02b1fd18d --- /dev/null +++ b/framework/Xml_Element/test/Horde/CVS/Entries @@ -0,0 +1 @@ +D/Xml//// diff --git a/framework/Xml_Element/test/Horde/CVS/Repository b/framework/Xml_Element/test/Horde/CVS/Repository new file mode 100644 index 000000000..518894b61 --- /dev/null +++ b/framework/Xml_Element/test/Horde/CVS/Repository @@ -0,0 +1 @@ +framework/Xml_Element/test/Horde diff --git a/framework/Xml_Element/test/Horde/CVS/Root b/framework/Xml_Element/test/Horde/CVS/Root new file mode 100644 index 000000000..5d636129a --- /dev/null +++ b/framework/Xml_Element/test/Horde/CVS/Root @@ -0,0 +1 @@ +chuck@cvs.horde.org:/repository diff --git a/framework/Xml_Element/test/Horde/CVS/Template b/framework/Xml_Element/test/Horde/CVS/Template new file mode 100644 index 000000000..3971591f9 --- /dev/null +++ b/framework/Xml_Element/test/Horde/CVS/Template @@ -0,0 +1,8 @@ + +Bug: +Submitted by: +Merge after: +CVS: ---------------------------------------------------------------------- +CVS: Bug: Fill this in if a listed bug is affected by the change. +CVS: Submitted by: Fill this in if someone else sent in the change. +CVS: Merge after: N [day[s]|week[s]|month[s]] (days assumed by default) diff --git a/framework/Xml_Element/test/Horde/Xml/CVS/Entries b/framework/Xml_Element/test/Horde/Xml/CVS/Entries new file mode 100644 index 000000000..71227d4f6 --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/CVS/Entries @@ -0,0 +1 @@ +D/Element//// diff --git a/framework/Xml_Element/test/Horde/Xml/CVS/Repository b/framework/Xml_Element/test/Horde/Xml/CVS/Repository new file mode 100644 index 000000000..16e615257 --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/CVS/Repository @@ -0,0 +1 @@ +framework/Xml_Element/test/Horde/Xml diff --git a/framework/Xml_Element/test/Horde/Xml/CVS/Root b/framework/Xml_Element/test/Horde/Xml/CVS/Root new file mode 100644 index 000000000..5d636129a --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/CVS/Root @@ -0,0 +1 @@ +chuck@cvs.horde.org:/repository diff --git a/framework/Xml_Element/test/Horde/Xml/CVS/Template b/framework/Xml_Element/test/Horde/Xml/CVS/Template new file mode 100644 index 000000000..3971591f9 --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/CVS/Template @@ -0,0 +1,8 @@ + +Bug: +Submitted by: +Merge after: +CVS: ---------------------------------------------------------------------- +CVS: Bug: Fill this in if a listed bug is affected by the change. +CVS: Submitted by: Fill this in if someone else sent in the change. +CVS: Merge after: N [day[s]|week[s]|month[s]] (days assumed by default) diff --git a/framework/Xml_Element/test/Horde/Xml/Element/AllTests.php b/framework/Xml_Element/test/Horde/Xml/Element/AllTests.php new file mode 100644 index 000000000..b80b1c370 --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/Element/AllTests.php @@ -0,0 +1,49 @@ + + * @license http://opensource.org/licenses/bsd-license.php BSD + * @category Horde + * @package Horde_Xml_Element + * @subpackage UnitTests + */ + +if (!defined('PHPUnit_MAIN_METHOD')) { + define('PHPUnit_MAIN_METHOD', 'Horde_Xml_Element_AllTests::main'); +} + +require_once 'PHPUnit/Framework/TestSuite.php'; +require_once 'PHPUnit/TextUI/TestRunner.php'; + +class Horde_Xml_Element_AllTests { + + public static function main() + { + PHPUnit_TextUI_TestRunner::run(self::suite()); + } + + public static function suite() + { + $suite = new PHPUnit_Framework_TestSuite('Horde Framework - Horde_Xml_Element'); + + $basedir = dirname(__FILE__); + $baseregexp = preg_quote($basedir . DIRECTORY_SEPARATOR, '/'); + + foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($basedir)) as $file) { + if ($file->isFile() && preg_match('/Test.php$/', $file->getFilename())) { + $pathname = $file->getPathname(); + require $pathname; + + $class = str_replace(DIRECTORY_SEPARATOR, '_', + preg_replace("/^$baseregexp(.*)\.php/", '\\1', $pathname)); + $suite->addTestSuite('Horde_Xml_Element_' . $class); + } + } + + return $suite; + } + +} + +if (PHPUnit_MAIN_METHOD == 'Horde_Xml_Element_AllTests::main') { + Horde_Xml_Element_AllTests::main(); +} diff --git a/framework/Xml_Element/test/Horde/Xml/Element/CVS/Entries b/framework/Xml_Element/test/Horde/Xml/Element/CVS/Entries new file mode 100644 index 000000000..4cce6343f --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/Element/CVS/Entries @@ -0,0 +1,5 @@ +/AllTests.php/1.2/Tue Jul 29 15:52:48 2008// +/CountTest.php/1.2/Tue Jul 29 15:52:48 2008// +/IteratorTest.php/1.2/Tue Jul 29 15:52:48 2008// +D/fixtures//// +/ElementTest.php/1.5/Fri Sep 26 12:37:17 2008// diff --git a/framework/Xml_Element/test/Horde/Xml/Element/CVS/Repository b/framework/Xml_Element/test/Horde/Xml/Element/CVS/Repository new file mode 100644 index 000000000..53c55b27a --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/Element/CVS/Repository @@ -0,0 +1 @@ +framework/Xml_Element/test/Horde/Xml/Element diff --git a/framework/Xml_Element/test/Horde/Xml/Element/CVS/Root b/framework/Xml_Element/test/Horde/Xml/Element/CVS/Root new file mode 100644 index 000000000..5d636129a --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/Element/CVS/Root @@ -0,0 +1 @@ +chuck@cvs.horde.org:/repository diff --git a/framework/Xml_Element/test/Horde/Xml/Element/CVS/Template b/framework/Xml_Element/test/Horde/Xml/Element/CVS/Template new file mode 100644 index 000000000..3971591f9 --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/Element/CVS/Template @@ -0,0 +1,8 @@ + +Bug: +Submitted by: +Merge after: +CVS: ---------------------------------------------------------------------- +CVS: Bug: Fill this in if a listed bug is affected by the change. +CVS: Submitted by: Fill this in if someone else sent in the change. +CVS: Merge after: N [day[s]|week[s]|month[s]] (days assumed by default) diff --git a/framework/Xml_Element/test/Horde/Xml/Element/CountTest.php b/framework/Xml_Element/test/Horde/Xml/Element/CountTest.php new file mode 100644 index 000000000..c35c6c561 --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/Element/CountTest.php @@ -0,0 +1,40 @@ + + * @license http://opensource.org/licenses/bsd-license.php BSD + * @category Horde + * @package Horde_Xml_Element + * @subpackage UnitTests + */ + +require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/lib/Horde/Xml/Element.php'; +require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/lib/Horde/Xml/Element/Exception.php'; +require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/lib/Horde/Xml/Element/List.php'; + +class Horde_Xml_Element_CountTest extends PHPUnit_Framework_TestCase +{ + public function testCount() + { + $l = new Horde_Xml_Element_CountTest_List( + '12' + ); + $this->assertEquals(2, $l->count(), 'List count should be 2'); + } + +} + +class Horde_Xml_Element_CountTest_List extends Horde_Xml_Element_List +{ + protected function _buildListItemCache() + { + $results = array(); + foreach ($this->_element->childNodes as $child) { + if ($child->localName == 'item') { + $results[] = $child; + } + } + + return $results; + } + +} diff --git a/framework/Xml_Element/test/Horde/Xml/Element/ElementTest.php b/framework/Xml_Element/test/Horde/Xml/Element/ElementTest.php new file mode 100644 index 000000000..72928fc0f --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/Element/ElementTest.php @@ -0,0 +1,249 @@ + + * @license http://opensource.org/licenses/bsd-license.php BSD + * @category Horde + * @package Horde_Xml_Element + * @subpackage UnitTests + */ + +require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/lib/Horde/Xml/Element.php'; +require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/lib/Horde/Xml/Element/Exception.php'; + +/** + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php BSD + * @category Horde + * @package Horde_Xml_Element + * @subpackage UnitTests + */ +class Horde_Xml_Element_ElementTest extends PHPUnit_Framework_TestCase +{ + public function setUp() + { + $this->element = new Horde_Xml_Element(file_get_contents(dirname(__FILE__) . '/fixtures/Sample.xml')); + $this->namespacedElement = new Horde_Xml_Element(file_get_contents(dirname(__FILE__) . '/fixtures/NamespacedSample.xml')); + } + + public function testXml() + { + $el = new Horde_Xml_Element('Root'); + $this->assertEquals((string)$el, 'Root'); + $this->assertEquals($el['href'], '#'); + } + + public function testInvalidXml() + { + $failed = false; + try { + new Horde_Xml_Element('assertTrue($failed, 'Invalid XML should result in an exception'); + } + + public function testSerialization() + { + $elt = new Horde_Xml_Element('Test'); + $this->assertEquals($elt->title(), 'Test', 'Value before serialization/unserialization'); + $serialized = serialize($elt); + $unserialized = unserialize($serialized); + $this->assertEquals($unserialized->title(), 'Test', 'Value after serialization/unserialization'); + } + + public function testExists() + { + $this->assertFalse(isset($this->element[-1]), 'Negative array access should fail'); + $this->assertTrue(isset($this->element['version']), 'Version should be set'); + + $this->assertFalse(isset($this->namespacedElement[-1]), 'Negative array access should fail'); + $this->assertTrue(isset($this->namespacedElement['version']), 'Version should be set'); + } + + public function testGet() + { + $this->assertEquals($this->element['version'], '1.0', 'Version should be 1.0'); + $this->assertEquals($this->namespacedElement['version'], '1.0', 'Version should be 1.0'); + } + + public function testArrayGet() + { + $this->assertTrue(is_array($this->element->entry)); + $this->assertTrue(is_array($this->namespacedElement->entry)); + + foreach ($this->element->entry as $entry) { + $this->assertTrue($entry instanceof Horde_Xml_Element); + } + + foreach ($this->namespacedElement->entry as $entry) { + $this->assertTrue($entry instanceof Horde_Xml_Element); + } + } + + public function testSet() + { + $this->element['category'] = 'tests'; + $this->assertTrue(isset($this->element['category']), 'Category should be set'); + $this->assertEquals($this->element['category'], 'tests', 'Category should be tests'); + + $this->namespacedElement['atom:category'] = 'tests'; + $this->assertTrue(isset($this->namespacedElement['atom:category']), 'Category should be set'); + $this->assertEquals($this->namespacedElement['atom:category'], 'tests', 'Category should be tests'); + + // Changing an existing index. + $oldEntry = $this->element['version']; + $this->element['version'] = '1.1'; + $this->assertTrue($oldEntry != $this->element['version'], 'Version should have changed'); + } + + public function testOffsetUnset() + { + $element = new Horde_Xml_Element(file_get_contents(dirname(__FILE__) . '/fixtures/Sample.xml')); + $namespacedElement = new Horde_Xml_Element(file_get_contents(dirname(__FILE__) . '/fixtures/NamespacedSample.xml')); + + $this->assertTrue(isset($element['version'])); + unset($element['version']); + $this->assertFalse(isset($element['version']), 'Version should be unset'); + $this->assertEquals('', $element['version'], 'Version should be equal to the empty string'); + + $this->assertTrue(isset($namespacedElement['version'])); + unset($namespacedElement['version']); + $this->assertFalse(isset($namespacedElement['version']), 'Version should be unset'); + $this->assertEquals('', $namespacedElement['version'], 'Version should be equal to the empty string'); + } + + public function testUnset() + { + $element = new Horde_Xml_Element(file_get_contents(dirname(__FILE__) . '/fixtures/Sample.xml')); + $namespacedElement = new Horde_Xml_Element(file_get_contents(dirname(__FILE__) . '/fixtures/NamespacedSample.xml')); + + $this->assertTrue(isset($element->title)); + unset($element->title); + $this->assertFalse(isset($element->title)); + + $this->assertTrue(isset($namespacedElement->title)); + unset($namespacedElement->title); + $this->assertFalse(isset($namespacedElement->title)); + } + + public function testIsInitialized() + { + $e = new Horde_Xml_Element(''); + + $e->author->name['last'] = 'Lastname'; + $e->author->name['first'] = 'Firstname'; + $e->author->name->{'Firstname:url'} = 'www.example.com'; + + $e->author->title['foo'] = 'bar'; + if ($e->pants()) { + $this->fail(' does not exist, it should not have a true value'); + // This should not create an element in the actual tree. + } + if ($e->pants()) { + $this->fail(' should not have been created by testing for it'); + // This should not create an element in the actual tree. + } + + $xml = $e->saveXML(); + + $this->assertFalse(strpos($xml, 'pants'), ' should not be in the xml output'); + $this->assertTrue(strpos($xml, 'www.example.com') !== false, 'the url attribute should be set'); + } + + public function testStrings() + { + $xml = " + Using C++ Intrinsic Functions for Pipelined Text Processing + http://www.oreillynet.com/pub/wlg/8356 + + +
+ A good C++ programming technique that has almost no published material available on the WWW relates to using the special pipeline instructions in modern CPUs for faster text processing. Here's example code using C++ intrinsic functions to give a fourfold speed increase for a UTF-8 to UTF-16 converter compared to the original C/C++ code. +
+
+ Rick Jelliffe + 2005-11-07T08:15:57-08:00 +
"; + $element = new Horde_Xml_Element($xml); + + $this->assertTrue($element->summary instanceof Horde_Xml_Element, '__get access should return a Horde_Xml_Element instance'); + $this->assertFalse($element->summary() instanceof Horde_Xml_Element, 'method access should not return a Horde_Xml_Element instance'); + $this->assertTrue(is_string($element->summary()), 'method access should return a string'); + $this->assertFalse(is_string($element->summary), '__get access should not return a string'); + } + + public function testAppendChild() + { + $e = new Horde_Xml_Element(''); + $e2 = new Horde_Xml_Element(''); + + $e->appendChild($e2); + $this->assertEquals($e->saveXmlFragment(), + ''); + } + + public function testFromArray() + { + $e = new Horde_Xml_Element(''); + + $e->fromArray(array('user' => 'Joe Schmoe', + 'atom:title' => 'Test Title', + 'child#href' => 'http://www.example.com/', + '#title' => 'Test Element')); + + $this->assertEquals($e->saveXmlFragment(), + 'Joe SchmoeTest Title'); + + $e = new Horde_Xml_Element(''); + $e->fromArray(array('author' => array('name' => 'Joe', 'email' => 'joe@example.com'))); + + $this->assertEquals($e->saveXmlFragment(), + 'Joejoe@example.com'); + } + + public function testIllegalFromArray() + { + $failed = false; + $e = new Horde_Xml_Element(''); + try { + $e->fromArray(array('#name' => array('foo' => 'bar'))); + } catch (InvalidArgumentException $e) { + $failed = true; + } + $this->assertTrue($failed); + } + + public function testCustomGetterGet() + { + $xml = 'Joejoe@example.com'; + $e = new Horde_Xml_Element_CustomGetter($xml); + + $this->assertEquals($e->author, $e->writer); + $this->assertEquals($e->author->name, $e->psuedonym); + } + + public function testCustomGetterCall() + { + $xml = 'Joejoe@example.com'; + $e = new Horde_Xml_Element_CustomGetter($xml); + + $this->assertEquals($e->author(), $e->writer()); + $this->assertEquals($e->author->name(), $e->psuedonym()); + } + +} + +class Horde_Xml_Element_CustomGetter extends Horde_Xml_Element +{ + public function getWriter() + { + return $this->author; + } + + public function getPsuedonym() + { + return $this->author->name; + } + +} diff --git a/framework/Xml_Element/test/Horde/Xml/Element/IteratorTest.php b/framework/Xml_Element/test/Horde/Xml/Element/IteratorTest.php new file mode 100644 index 000000000..130903642 --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/Element/IteratorTest.php @@ -0,0 +1,80 @@ + + * @license http://opensource.org/licenses/bsd-license.php BSD + * @category Horde + * @package Horde_Xml_Element + * @subpackage UnitTests + */ + +require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/lib/Horde/Xml/Element.php'; +require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/lib/Horde/Xml/Element/Exception.php'; +require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/lib/Horde/Xml/Element/List.php'; + +class Horde_Xml_Element_IteratorTest extends PHPUnit_Framework_TestCase +{ + public function setUp() + { + $this->list = new Horde_Xml_Element_IteratorTest_List( + '12' + ); + } + + public function testRewind() + { + $times = 0; + foreach ($this->list as $i) { + ++$times; + } + + $times2 = 0; + foreach ($this->list as $i) { + ++$times2; + } + + $this->assertEquals($times, $times2, 'List should have the same number of iterations multiple times through'); + } + + public function testCurrent() + { + foreach ($this->list as $i) { + $this->assertType('Horde_Xml_Element', $i, 'Each list item should be an instance of Horde_Xml_Element'); + break; + } + } + + public function testKey() + { + $keys = array(); + foreach ($this->list as $k => $i) { + $keys[] = $k; + } + $this->assertEquals($keys, array(0, 1), 'List should have keys 0 and 1'); + } + + public function testNext() + { + $last = null; + foreach ($this->list as $current) { + $this->assertFalse($last === $current, 'Iteration should produce a new object each item'); + $last = $current; + } + } + +} + +class Horde_Xml_Element_IteratorTest_List extends Horde_Xml_Element_List +{ + protected function _buildListItemCache() + { + $results = array(); + foreach ($this->_element->childNodes as $child) { + if ($child->localName == 'item') { + $results[] = $child; + } + } + + return $results; + } + +} diff --git a/framework/Xml_Element/test/Horde/Xml/Element/fixtures/CVS/Entries b/framework/Xml_Element/test/Horde/Xml/Element/fixtures/CVS/Entries new file mode 100644 index 000000000..6f402d6bc --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/Element/fixtures/CVS/Entries @@ -0,0 +1,3 @@ +/NamespacedSample.xml/1.1/Wed Mar 5 20:37:56 2008// +/Sample.xml/1.1/Wed Mar 5 20:37:56 2008// +D diff --git a/framework/Xml_Element/test/Horde/Xml/Element/fixtures/CVS/Repository b/framework/Xml_Element/test/Horde/Xml/Element/fixtures/CVS/Repository new file mode 100644 index 000000000..4ac2119d1 --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/Element/fixtures/CVS/Repository @@ -0,0 +1 @@ +framework/Xml_Element/test/Horde/Xml/Element/fixtures diff --git a/framework/Xml_Element/test/Horde/Xml/Element/fixtures/CVS/Root b/framework/Xml_Element/test/Horde/Xml/Element/fixtures/CVS/Root new file mode 100644 index 000000000..5d636129a --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/Element/fixtures/CVS/Root @@ -0,0 +1 @@ +chuck@cvs.horde.org:/repository diff --git a/framework/Xml_Element/test/Horde/Xml/Element/fixtures/CVS/Template b/framework/Xml_Element/test/Horde/Xml/Element/fixtures/CVS/Template new file mode 100644 index 000000000..3971591f9 --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/Element/fixtures/CVS/Template @@ -0,0 +1,8 @@ + +Bug: +Submitted by: +Merge after: +CVS: ---------------------------------------------------------------------- +CVS: Bug: Fill this in if a listed bug is affected by the change. +CVS: Submitted by: Fill this in if someone else sent in the change. +CVS: Merge after: N [day[s]|week[s]|month[s]] (days assumed by default) diff --git a/framework/Xml_Element/test/Horde/Xml/Element/fixtures/NamespacedSample.xml b/framework/Xml_Element/test/Horde/Xml/Element/fixtures/NamespacedSample.xml new file mode 100644 index 000000000..02d0ee254 --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/Element/fixtures/NamespacedSample.xml @@ -0,0 +1,34 @@ + + + Atom Example + This is a simple Atom Feed made by XML_Feed_Writer. + + + + 4 + 3 + 2 + 2005-04-25T00:00:00+02:00 + + 1 + + The Item Title + 2004-09-25T16:03:00+02:00 + 2005-12-25T16:03:00+01:00 + + David Coallier + + Testing something before releasing + + + 2 + + Second item added to the builder/feeded.. + 2004-01-04T00:00:00+01:00 + 1970-01-01T01:00:00+01:00 + + David Coallier + + Jaws project, visit the website for infos... + + diff --git a/framework/Xml_Element/test/Horde/Xml/Element/fixtures/Sample.xml b/framework/Xml_Element/test/Horde/Xml/Element/fixtures/Sample.xml new file mode 100644 index 000000000..69afce7a6 --- /dev/null +++ b/framework/Xml_Element/test/Horde/Xml/Element/fixtures/Sample.xml @@ -0,0 +1,34 @@ + + + Atom Example + This is a simple Atom Feed made by XML_Feed_Writer. + + + + 4 + 3 + 2 + 2005-04-25T00:00:00+02:00 + + 1 + + The Item Title + 2004-09-25T16:03:00+02:00 + 2005-12-25T16:03:00+01:00 + + David Coallier + + Testing something before releasing + + + 2 + + Second item added to the builder/feeded.. + 2004-01-04T00:00:00+01:00 + 1970-01-01T01:00:00+01:00 + + David Coallier + + Jaws project, visit the website for infos... + + -- 2.11.0