--- /dev/null
+D/lib////
+D/test////
+/package.xml/1.15/Fri Sep 26 12:37:16 2008//
--- /dev/null
+framework/Xml_Element
--- /dev/null
+chuck@cvs.horde.org:/repository
--- /dev/null
+
+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)
--- /dev/null
+D/Horde////
--- /dev/null
+framework/Xml_Element/lib
--- /dev/null
+chuck@cvs.horde.org:/repository
--- /dev/null
+
+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)
--- /dev/null
+framework/Xml_Element/lib/Horde
--- /dev/null
+chuck@cvs.horde.org:/repository
--- /dev/null
+
+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)
--- /dev/null
+D/Element////
+/Element.php/1.14/Sat Sep 27 14:56:17 2008//
--- /dev/null
+framework/Xml_Element/lib/Horde/Xml
--- /dev/null
+chuck@cvs.horde.org:/repository
--- /dev/null
+
+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)
--- /dev/null
+<?php
+/**
+ * $Horde: framework/Xml_Element/lib/Horde/Xml/Element.php,v 1.14 2008/09/27 02:57:42 chuck Exp $
+ *
+ * Portions Copyright 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
+ * Copyright 2007-2008 The Horde Project (http://www.horde.org/)
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @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 <chuck@horde.org>
+ * @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;
+ }
+ }
+
+}
--- /dev/null
+/Exception.php/1.3/Tue Jul 29 15:52:47 2008//
+/List.php/1.3/Tue Jul 29 15:52:47 2008//
+D
--- /dev/null
+framework/Xml_Element/lib/Horde/Xml/Element
--- /dev/null
+chuck@cvs.horde.org:/repository
--- /dev/null
+
+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)
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Xml_Element
+ */
+
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @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);
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Xml_Element
+ */
+
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @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));
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.4.9" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+http://pear.php.net/dtd/tasks-1.0.xsd
+http://pear.php.net/dtd/package-2.0
+http://pear.php.net/dtd/package-2.0.xsd">
+ <name>Xml_Element</name>
+ <channel>pear.horde.org</channel>
+ <summary>Horde Xml Element object</summary>
+ <description>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.
+ </description>
+ <lead>
+ <name>Chuck Hagenbuch</name>
+ <user>chuck</user>
+ <email>chuck@horde.org</email>
+ <active>yes</active>
+ </lead>
+ <lead>
+ <name>Jan Schneider</name>
+ <user>jan</user>
+ <email>jan@horde.org</email>
+ <active>yes</active>
+ </lead>
+ <date>2008-09-25</date>
+ <version>
+ <release>0.4.2</release>
+ <api>0.4.0</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://opensource.org/licenses/bsd-license.php">BSD</license>
+ <notes>
+* Avoid errors when a child node doesn't exist.
+</notes>
+ <contents>
+ <dir name="/">
+ <dir name="lib">
+ <dir name="Horde">
+ <dir name="Xml">
+ <dir name="Element">
+ <file name="Exception.php" role="php" />
+ <file name="List.php" role="php" />
+ </dir> <!-- /lib/Horde/Xml/Element -->
+ <file name="Element.php" role="php" />
+ </dir> <!-- /lib/Horde/Xml -->
+ </dir> <!-- /lib/Horde -->
+ </dir> <!-- /lib -->
+ </dir> <!-- / -->
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>5.2.0</min>
+ </php>
+ <pearinstaller>
+ <min>1.5.0</min>
+ </pearinstaller>
+ </required>
+ </dependencies>
+ <phprelease>
+ <filelist>
+ <install name="lib/Horde/Xml/Element/Exception.php" as="Horde/Xml/Element/Exception.php" />
+ <install name="lib/Horde/Xml/Element/List.php" as="Horde/Xml/Element/List.php" />
+ <install name="lib/Horde/Xml/Element.php" as="Horde/Xml/Element.php" />
+ </filelist>
+ </phprelease>
+</package>
--- /dev/null
+D/Horde////
--- /dev/null
+framework/Xml_Element/test
--- /dev/null
+chuck@cvs.horde.org:/repository
--- /dev/null
+
+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)
--- /dev/null
+framework/Xml_Element/test/Horde
--- /dev/null
+chuck@cvs.horde.org:/repository
--- /dev/null
+
+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)
--- /dev/null
+D/Element////
--- /dev/null
+framework/Xml_Element/test/Horde/Xml
--- /dev/null
+chuck@cvs.horde.org:/repository
--- /dev/null
+
+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)
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @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();
+}
--- /dev/null
+/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//
--- /dev/null
+framework/Xml_Element/test/Horde/Xml/Element
--- /dev/null
+chuck@cvs.horde.org:/repository
--- /dev/null
+
+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)
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @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(
+ '<?xml version="1.0" encoding="utf-8"?><list><item>1</item><item>2</item></list>'
+ );
+ $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;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @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 <chuck@horde.org>
+ * @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 href="#">Root</root>');
+ $this->assertEquals((string)$el, 'Root');
+ $this->assertEquals($el['href'], '#');
+ }
+
+ public function testInvalidXml()
+ {
+ $failed = false;
+ try {
+ new Horde_Xml_Element('<root');
+ } catch (Horde_Xml_Element_Exception $e) {
+ $failed = true;
+ }
+ $this->assertTrue($failed, 'Invalid XML should result in an exception');
+ }
+
+ public function testSerialization()
+ {
+ $elt = new Horde_Xml_Element('<entry><title>Test</title></entry>');
+ $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('<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('<pants> 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('<pants> 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'), '<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 = "<entry>
+ <title> Using C++ Intrinsic Functions for Pipelined Text Processing</title>
+ <id>http://www.oreillynet.com/pub/wlg/8356</id>
+ <link rel='alternate' href='http://www.oreillynet.com/pub/wlg/8356'/>
+ <summary type='xhtml'>
+ <div xmlns='http://www.w3.org/1999/xhtml'>
+ 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.
+ </div>
+ </summary>
+ <author><name>Rick Jelliffe</name></author>
+ <updated>2005-11-07T08:15:57-08:00</updated>
+</entry>";
+ $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('<element />');
+ $e2 = new Horde_Xml_Element('<child />');
+
+ $e->appendChild($e2);
+ $this->assertEquals($e->saveXmlFragment(),
+ '<element><child/></element>');
+ }
+
+ public function testFromArray()
+ {
+ $e = new Horde_Xml_Element('<element />');
+
+ $e->fromArray(array('user' => 'Joe Schmoe',
+ 'atom:title' => 'Test Title',
+ 'child#href' => 'http://www.example.com/',
+ '#title' => 'Test Element'));
+
+ $this->assertEquals($e->saveXmlFragment(),
+ '<element title="Test Element"><user>Joe Schmoe</user><atom:title xmlns:atom="http://www.w3.org/2005/Atom">Test Title</atom:title><child href="http://www.example.com/"/></element>');
+
+ $e = new Horde_Xml_Element('<element />');
+ $e->fromArray(array('author' => array('name' => 'Joe', 'email' => 'joe@example.com')));
+
+ $this->assertEquals($e->saveXmlFragment(),
+ '<element><author><name>Joe</name><email>joe@example.com</email></author></element>');
+ }
+
+ public function testIllegalFromArray()
+ {
+ $failed = false;
+ $e = new Horde_Xml_Element('<element />');
+ try {
+ $e->fromArray(array('#name' => array('foo' => 'bar')));
+ } catch (InvalidArgumentException $e) {
+ $failed = true;
+ }
+ $this->assertTrue($failed);
+ }
+
+ public function testCustomGetterGet()
+ {
+ $xml = '<element><author><name>Joe</name><email>joe@example.com</email></author></element>';
+ $e = new Horde_Xml_Element_CustomGetter($xml);
+
+ $this->assertEquals($e->author, $e->writer);
+ $this->assertEquals($e->author->name, $e->psuedonym);
+ }
+
+ public function testCustomGetterCall()
+ {
+ $xml = '<element><author><name>Joe</name><email>joe@example.com</email></author></element>';
+ $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;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @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(
+ '<?xml version="1.0" encoding="utf-8"?><list><item>1</item><item>2</item></list>'
+ );
+ }
+
+ 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;
+ }
+
+}
--- /dev/null
+/NamespacedSample.xml/1.1/Wed Mar 5 20:37:56 2008//
+/Sample.xml/1.1/Wed Mar 5 20:37:56 2008//
+D
--- /dev/null
+framework/Xml_Element/test/Horde/Xml/Element/fixtures
--- /dev/null
+chuck@cvs.horde.org:/repository
--- /dev/null
+
+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)
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<atom:feed xmlns:atom="http://www.w3.org/2005/Atom" xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/" version="1.0">
+ <title>Atom Example</title>
+ <tagline>This is a simple Atom Feed made by XML_Feed_Writer.</tagline>
+ <atom:link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="./TestAtomFeedNamespaced.xml" />
+ <atom:link rel="http://schemas.google.com/g/2005#post" type="application/atom+xml" href="./TestAtomFeedNamespaced.xml" />
+ <atom:link rel="self" type="application/atom+xml" href="./TestAtomFeedNamespaced.xml" />
+ <opensearch:totalResults>4</opensearch:totalResults>
+ <opensearch:startIndex>3</opensearch:startIndex>
+ <opensearch:itemsPerPage>2</opensearch:itemsPerPage>
+ <modified>2005-04-25T00:00:00+02:00</modified>
+ <atom:entry>
+ <atom:id>1</atom:id>
+ <atom:link rel="edit" href="./TestAtomFeedNamespaced.xml/1/1" />
+ <title>The Item Title</title>
+ <issued>2004-09-25T16:03:00+02:00</issued>
+ <modified>2005-12-25T16:03:00+01:00</modified>
+ <author>
+ <name>David Coallier</name>
+ </author>
+ <summary>Testing something before releasing</summary>
+ </atom:entry>
+ <atom:entry>
+ <atom:id>2</atom:id>
+ <atom:link rel="edit" href="./TestAtomFeedNamespaced.xml/2/1" />
+ <title>Second item added to the builder/feeded..</title>
+ <issued>2004-01-04T00:00:00+01:00</issued>
+ <modified>1970-01-01T01:00:00+01:00</modified>
+ <author>
+ <name>David Coallier</name>
+ </author>
+ <summary>Jaws project, visit the website for infos...</summary>
+ </atom:entry>
+</atom:feed>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom" xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/" version="1.0">
+ <title>Atom Example</title>
+ <tagline>This is a simple Atom Feed made by XML_Feed_Writer.</tagline>
+ <link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="./TestAtomFeed.xml" />
+ <link rel="http://schemas.google.com/g/2005#post" type="application/atom+xml" href="./TestAtomFeed.xml" />
+ <link rel="self" type="application/atom+xml" href="./TestAtomFeed.xml" />
+ <opensearch:totalResults>4</opensearch:totalResults>
+ <opensearch:startIndex>3</opensearch:startIndex>
+ <opensearch:itemsPerPage>2</opensearch:itemsPerPage>
+ <modified>2005-04-25T00:00:00+02:00</modified>
+ <entry>
+ <id>1</id>
+ <link rel="edit" href="./TestAtomFeed.xml/1/1" />
+ <title>The Item Title</title>
+ <issued>2004-09-25T16:03:00+02:00</issued>
+ <modified>2005-12-25T16:03:00+01:00</modified>
+ <author>
+ <name>David Coallier</name>
+ </author>
+ <summary>Testing something before releasing</summary>
+ </entry>
+ <entry>
+ <id>2</id>
+ <link rel="edit" href="./TestAtomFeed.xml/2/1" />
+ <title>Second item added to the builder/feeded..</title>
+ <issued>2004-01-04T00:00:00+01:00</issued>
+ <modified>1970-01-01T01:00:00+01:00</modified>
+ <author>
+ <name>David Coallier</name>
+ </author>
+ <summary>Jaws project, visit the website for infos...</summary>
+ </entry>
+</feed>