diff --git a/cake/libs/controller/components/request_handler.php b/cake/libs/controller/components/request_handler.php index 2f31eb5df..d8a50c3e4 100644 --- a/cake/libs/controller/components/request_handler.php +++ b/cake/libs/controller/components/request_handler.php @@ -172,15 +172,15 @@ class RequestHandlerComponent extends Component { } if ($this->requestedWith('xml')) { - if (!class_exists('XmlNode')) { + if (!class_exists('Xml')) { App::import('Core', 'Xml'); } - $xml = new Xml(trim(file_get_contents('php://input'))); + $xml = Xml::build(trim(file_get_contents('php://input'))); - if (count($xml->children) == 1 && is_object($dataNode = $xml->child('data'))) { - $controller->data = $dataNode->toArray(); + if (isset($xml->data)) { + $controller->data = Xml::toArray($xml->data); } else { - $controller->data = $xml->toArray(); + $controller->data = Xml::toArray($xml); } } } diff --git a/cake/libs/set.php b/cake/libs/set.php index 05afbf06b..6fa769bfa 100644 --- a/cake/libs/set.php +++ b/cake/libs/set.php @@ -941,9 +941,8 @@ class Set { */ public static function reverse($object) { $out = array(); - if (is_a($object, 'XmlNode')) { - $out = $object->toArray(); - return $out; + if ($object instanceof SimpleXMLElement) { + return Xml::toArray($object); } else if (is_object($object)) { $keys = get_object_vars($object); if (isset($keys['_name_'])) { diff --git a/cake/libs/view/helpers/rss.php b/cake/libs/view/helpers/rss.php index 3009dbac1..b6c773d0f 100644 --- a/cake/libs/view/helpers/rss.php +++ b/cake/libs/view/helpers/rss.php @@ -17,18 +17,16 @@ * @since CakePHP(tm) v 1.2 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Helper', 'Xml'); +App::import('Core', 'Xml'); /** - * XML Helper class for easy output of XML structures. - * - * XmlHelper encloses all methods needed while working with XML documents. + * RSS Helper class for easy output RSS structures. * * @package cake * @subpackage cake.cake.libs.view.helpers * @link http://book.cakephp.org/view/1460/RSS */ -class RssHelper extends XmlHelper { +class RssHelper extends AppHelper { /** * Helpers used by RSS Helper @@ -270,7 +268,7 @@ class RssHelper extends XmlHelper { if (!empty($elements)) { $content = implode('', $elements); } - return $this->elem('item', $att, $content, !($content === null)); + return $this->elem('item', (array)$att, $content, !($content === null)); } /** @@ -283,4 +281,62 @@ class RssHelper extends XmlHelper { function time($time) { return $this->Time->toRSS($time); } + +/** + * Generates an XML element + * + * @param string $name The name of the XML element + * @param array $attrib The attributes of the XML element + * @param mixed $content XML element content + * @param boolean $endTag Whether the end tag of the element should be printed + * @return string XML + */ + function elem($name, $attrib = array(), $content = null, $endTag = true) { + $namespace = null; + if (isset($attrib['namespace'])) { + $namespace = $attrib['namespace']; + unset($attrib['namespace']); + } + $cdata = false; + if (is_array($content) && isset($content['cdata'])) { + $cdata = true; + unset($content['cdata']); + } + if (is_array($content) && array_key_exists('value', $content)) { + $content = $content['value']; + } + $children = array(); + if (is_array($content)) { + $children = $content; + $content = null; + } + + $xml = '<' . $name; + if (!empty($namespace)) { + $xml .= ' xmlns:"' . $namespace . '"'; + } + if (strpos($name, ':') !== false) { + list($prefix, ) = explode(':', $name, 2); + switch ($prefix) { + case 'atom': + $xml .= ' xmlns:atom="http://www.w3.org/2005/Atom"'; + break; + } + } + if ($cdata && !empty($content)) { + $content = ''; + } + $xml .= '>' . $content . ''; + $elem = Xml::build($xml); + foreach ($attrib as $key => $value) { + $elem->addAttribute($key, $value); + } + foreach ($children as $child) { + $elem->addChild($child); + } + + $xml = $elem->asXML(); + $xml = trim(substr($xml, strpos($xml, '?>') + 2)); + return $xml; + } } diff --git a/cake/libs/view/helpers/xml.php b/cake/libs/view/helpers/xml.php deleted file mode 100644 index 58e0aefa4..000000000 --- a/cake/libs/view/helpers/xml.php +++ /dev/null @@ -1,179 +0,0 @@ -Xml =& new Xml(); - $this->Xml->options(array('verifyNs' => false)); - } - -/** - * Returns an XML document header - * - * @param array $attrib Header tag attributes - * @return string XML header - * @access public - * @link http://book.cakephp.org/view/1476/header - */ - public function header($attrib = array()) { - if (Configure::read('App.encoding') !== null) { - $this->encoding = Configure::read('App.encoding'); - } - - if (is_array($attrib)) { - $attrib = array_merge(array('encoding' => $this->encoding), $attrib); - } - if (is_string($attrib) && strpos($attrib, 'xml') !== 0) { - $attrib = 'xml ' . $attrib; - } - - return $this->Xml->header($attrib); - } - -/** - * Adds a namespace to any documents generated - * - * @param string $name The namespace name - * @param string $url The namespace URI; can be empty if in the default namespace map - * @return boolean False if no URL is specified, and the namespace does not exist - * default namespace map, otherwise true - * @deprecated - * @see Xml::addNs() - */ - function addNs($name, $url = null) { - return $this->Xml->addNamespace($name, $url); - } - -/** - * Removes a namespace added in addNs() - * - * @param string $name The namespace name or URI - * @deprecated - * @see Xml::removeNs() - */ - public function removeNs($name) { - return $this->Xml->removeGlobalNamespace($name); - } - -/** - * Generates an XML element - * - * @param string $name The name of the XML element - * @param array $attrib The attributes of the XML element - * @param mixed $content XML element content - * @param boolean $endTag Whether the end tag of the element should be printed - * @return string XML - * @access public - * @link http://book.cakephp.org/view/1475/elem - */ - public function elem($name, $attrib = array(), $content = null, $endTag = true) { - $namespace = null; - if (isset($attrib['namespace'])) { - $namespace = $attrib['namespace']; - unset($attrib['namespace']); - } - $cdata = false; - if (is_array($content) && isset($content['cdata'])) { - $cdata = true; - unset($content['cdata']); - } - if (is_array($content) && array_key_exists('value', $content)) { - $content = $content['value']; - } - $children = array(); - if (is_array($content)) { - $children = $content; - $content = null; - } - - $elem =& $this->Xml->createElement($name, $content, $attrib, $namespace); - foreach ($children as $child) { - $elem->createElement($child); - } - $out = $elem->toString(array('cdata' => $cdata, 'leaveOpen' => !$endTag)); - - if (!$endTag) { - $this->Xml =& $elem; - } - return $out; - } - -/** - * Create closing tag for current element - * - * @return string - */ - public function closeElem() { - $name = $this->Xml->name(); - if ($parent =& $this->Xml->parent()) { - $this->Xml =& $parent; - } - return ''; - } - -/** - * Serializes a model resultset into XML - * - * @param mixed $data The content to be converted to XML - * @param array $options The data formatting options. For a list of valid options, see - * Xml::__construct(). - * @return string A copy of $data in XML format - * @see Xml::__construct() - * @access public - * @link http://book.cakephp.org/view/1474/serialize - */ - public function serialize($data, $options = array()) { - $options += array('attributes' => false, 'format' => 'attributes'); - $data =& new Xml($data, $options); - return $data->toString($options + array('header' => false)); - } -} diff --git a/cake/libs/xml.php b/cake/libs/xml.php index c7bc7754d..9b1905b82 100644 --- a/cake/libs/xml.php +++ b/cake/libs/xml.php @@ -19,1421 +19,315 @@ * @since CakePHP v .0.10.3.1400 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'Set'); + +class Xml { /** - * XML node. + * Initialize SimpleXMLElement or DOMDocument from a given XML string, file path, URL or array. * - * Single XML node in an XML tree. + * ### Usage: * - * @package cake - * @subpackage cake.cake.libs - * @since CakePHP v .0.10.3.1400 - */ -class XmlNode extends Object { - -/** - * Name of node + * Building XML from a string: * - * @var string - * @access public - */ - public $name = null; - -/** - * Node namespace + * `$xml = Xml::build('text');` * - * @var string - * @access public - */ - public $namespace = null; - -/** - * Namespaces defined for this node and all child nodes + * Building XML from string (output DOMDocument): * - * @var array - * @access public - */ - public $namespaces = array(); - -/** - * Value of node + * `$xml = Xml::build('text', array('return' => 'domdocument'));` * - * @var string - * @access public - */ - public $value; - -/** - * Attributes on this node + * Building XML from a file path: * - * @var array - * @access public - */ - public $attributes = array(); - -/** - * This node's children + * `$xml = Xml::build('/path/to/an/xml/file.xml');` * - * @var array - * @access public - */ - public $children = array(); - -/** - * Reference to parent node. + * Building from a remote URL: * - * @var XmlNode - * @access private - */ - private $__parent = null; - -/** - * Constructor. + * `$xml = Xml::build('http://example.com/example.xml');` * - * @param string $name Node name - * @param array $attributes Node attributes - * @param mixed $value Node contents (text) - * @param array $children Node children - */ - function __construct($name = null, $value = null, $namespace = null) { - if (strpos($name, ':') !== false) { - list($prefix, $name) = explode(':', $name); - if (!$namespace) { - $namespace = $prefix; - } - } - $this->name = $name; - if ($namespace) { - $this->namespace = $namespace; - } - - if (is_array($value) || is_object($value)) { - $this->normalize($value); - } elseif (!empty($value) || $value === 0 || $value === '0') { - $this->createTextNode($value); - } - } -/** - * Adds a namespace to the current node + * Building from an array: * - * @param string $prefix The namespace prefix - * @param string $url The namespace DTD URL - * @return void - */ - function addNamespace($prefix, $url) { - if ($ns = Xml::addGlobalNs($prefix, $url)) { - $this->namespaces = array_merge($this->namespaces, $ns); - return true; - } - return false; - } - -/** - * Adds a namespace to the current node - * - * @param string $prefix The namespace prefix - * @param string $url The namespace DTD URL - * @return void - */ - function removeNamespace($prefix) { - if (Xml::removeGlobalNs($prefix)) { - return true; - } - return false; - } - -/** - * Creates an XmlNode object that can be appended to this document or a node in it - * - * @param string $name Node name - * @param string $value Node value - * @param string $namespace Node namespace - * @return object XmlNode - */ - function &createNode($name = null, $value = null, $namespace = false) { - $node =& new XmlNode($name, $value, $namespace); - $node->setParent($this); - return $node; - } - -/** - * Creates an XmlElement object that can be appended to this document or a node in it - * - * @param string $name Element name - * @param string $value Element value - * @param array $attributes Element attributes - * @param string $namespace Node namespace - * @return object XmlElement - */ - function &createElement($name = null, $value = null, $attributes = array(), $namespace = false) { - $element =& new XmlElement($name, $value, $attributes, $namespace); - $element->setParent($this); - return $element; - } - -/** - * Creates an XmlTextNode object that can be appended to this document or a node in it - * - * @param string $value Node value - * @return object XmlTextNode - */ - function &createTextNode($value = null) { - $node = new XmlTextNode($value); - $node->setParent($this); - return $node; - } - -/** - * Gets the XML element properties from an object. - * - * @param object $object Object to get properties from - * @return array Properties from object - */ - public function normalize($object, $keyName = null, $options = array()) { - if (is_a($object, 'XmlNode')) { - return $object; - } - $name = null; - $options += array('format' => 'attributes'); - - if ($keyName !== null && !is_numeric($keyName)) { - $name = $keyName; - } elseif (!empty($object->_name_)) { - $name = $object->_name_; - } elseif (isset($object->name)) { - $name = $object->name; - } elseif ($options['format'] == 'attributes') { - $name = get_class($object); - } - - $tagOpts = $this->__tagOptions($name); - - if ($tagOpts === false) { - return; - } - - if (isset($tagOpts['name'])) { - $name = $tagOpts['name']; - } elseif ($name != strtolower($name)) { - $name = Inflector::slug(Inflector::underscore($name)); - } - - if (!empty($name)) { - $node =& $this->createElement($name); - } else { - $node =& $this; - } - - $namespace = array(); - $attributes = array(); - $children = array(); - $chldObjs = array(); - - if (is_object($object)) { - $chldObjs = get_object_vars($object); - } elseif (is_array($object)) { - $chldObjs = $object; - } elseif (!empty($object) || $object === 0 || $object === '0') { - $node->createTextNode($object); - } - $attr = array(); - - if (isset($tagOpts['attributes'])) { - $attr = $tagOpts['attributes']; - } - if (isset($tagOpts['value']) && isset($chldObjs[$tagOpts['value']])) { - $node->createTextNode($chldObjs[$tagOpts['value']]); - unset($chldObjs[$tagOpts['value']]); - } - - $n = $name; - if (isset($chldObjs['_name_'])) { - $n = null; - unset($chldObjs['_name_']); - } - $c = 0; - - foreach ($chldObjs as $key => $val) { - if (in_array($key, $attr) && !is_object($val) && !is_array($val)) { - $attributes[$key] = $val; - } else { - if (!isset($tagOpts['children']) || $tagOpts['children'] === array() || (is_array($tagOpts['children']) && in_array($key, $tagOpts['children']))) { - if (!is_numeric($key)) { - $n = $key; - } - if (is_array($val)) { - foreach ($val as $n2 => $obj2) { - if (is_numeric($n2)) { - $n2 = $n; - } - $node->normalize($obj2, $n2, $options); - } - } else { - if (is_object($val)) { - - $node->normalize($val, $n, $options); - } elseif ($options['format'] == 'tags' && $this->__tagOptions($key) !== false) { - $tmp =& $node->createElement($key); - if (!empty($val) || $val === 0 || $val === '0') { - $tmp->createTextNode($val); - } - } elseif ($options['format'] == 'attributes') { - $node->addAttribute($key, $val); - } - } - } - } - $c++; - } - if (!empty($name)) { - return $node; - } - return $children; - } - -/** - * Gets the tag-specific options for the given node name - * - * @param string $name XML tag name - * @param string $option The specific option to query. Omit for all options - * @return mixed A specific option value if $option is specified, otherwise an array of all options - * @access private - */ - function __tagOptions($name, $option = null) { - if (isset($this->_tags[$name])) { - $tagOpts = $this->_tags[$name]; - } elseif (isset($this->_tags[strtolower($name)])) { - $tagOpts = $this->_tags[strtolower($name)]; - } else { - return null; - } - if ($tagOpts === false) { - return false; - } - if (empty($option)) { - return $tagOpts; - } - if (isset($tagOpts[$option])) { - return $tagOpts[$option]; - } - return null; - } - -/** - * Returns the fully-qualified XML node name, with namespace - * - */ - public function name() { - if (!empty($this->namespace)) { - $_this =& XmlManager::getInstance(); - if (!isset($_this->options['verifyNs']) || !$_this->options['verifyNs'] || in_array($this->namespace, array_keys($_this->namespaces))) { - return $this->namespace . ':' . $this->name; - } - } - return $this->name; - } - -/** - * Sets the parent node of this XmlNode. - * - */ - public function setParent(&$parent) { - if (strtolower(get_class($this)) == 'xml') { - return; - } - if (isset($this->__parent) && is_object($this->__parent)) { - if ($this->__parent->compare($parent)) { - return; - } - foreach ($this->__parent->children as $i => $child) { - if ($this->compare($child)) { - array_splice($this->__parent->children, $i, 1); - break; - } - } - } - if ($parent == null) { - unset($this->__parent); - } else { - $parent->children[] =& $this; - $this->__parent =& $parent; - } - } - -/** - * Returns a copy of self. - * - * @return object Cloned instance - */ - public function cloneNode() { - return clone($this); - } - -/** - * Compares $node to this XmlNode object - * - * @param object An XmlNode or subclass instance - * @return boolean True if the nodes match, false otherwise - */ - public function compare($node) { - $keys = array(get_object_vars($this), get_object_vars($node)); - return ($keys[0] === $keys[1]); - } - -/** - * Append given node as a child. - * - * @param object $child XmlNode with appended child - * @param array $options XML generator options for objects and arrays - * @return object A reference to the appended child node - */ - public function &append(&$child, $options = array()) { - if (empty($child)) { - $return = false; - return $return; - } - - if (is_object($child)) { - if ($this->compare($child)) { - trigger_error(__('Cannot append a node to itself.')); - $return = false; - return $return; - } - } else if (is_array($child)) { - $child = Set::map($child); - if (is_array($child)) { - if (!is_a(current($child), 'XmlNode')) { - foreach ($child as $i => $childNode) { - $child[$i] = $this->normalize($childNode, null, $options); - } - } else { - foreach ($child as $childNode) { - $this->append($childNode, $options); - } - } - return $child; - } - } else { - $attributes = array(); - if (func_num_args() >= 2) { - $attributes = func_get_arg(1); - } - $child =& $this->createNode($child, null, $attributes); - } - - $child = $this->normalize($child, null, $options); - - if (empty($child->namespace) && !empty($this->namespace)) { - $child->namespace = $this->namespace; - } - - if (is_a($child, 'XmlNode')) { - $child->setParent($this); - } - - return $child; - } - -/** - * Returns first child node, or null if empty. - * - * @return object First XmlNode - */ - public function &first() { - if (isset($this->children[0])) { - return $this->children[0]; - } else { - $return = null; - return $return; - } - } - -/** - * Returns last child node, or null if empty. - * - * @return object Last XmlNode - */ - public function &last() { - if (count($this->children) > 0) { - return $this->children[count($this->children) - 1]; - } else { - $return = null; - return $return; - } - } - -/** - * Returns child node with given ID. - * - * @param string $id Name of child node - * @return object Child XmlNode - */ - public function &child($id) { - $null = null; - - if (is_int($id)) { - if (isset($this->children[$id])) { - return $this->children[$id]; - } else { - return null; - } - } elseif (is_string($id)) { - for ($i = 0; $i < count($this->children); $i++) { - if ($this->children[$i]->name == $id) { - return $this->children[$i]; - } - } - } - return $null; - } - -/** - * Gets a list of childnodes with the given tag name. - * - * @param string $name Tag name of child nodes - * @return array An array of XmlNodes with the given tag name - */ - public function children($name) { - $nodes = array(); - $count = count($this->children); - for ($i = 0; $i < $count; $i++) { - if ($this->children[$i]->name == $name) { - $nodes[] =& $this->children[$i]; - } - } - return $nodes; - } - -/** - * Gets a reference to the next child node in the list of this node's parent. - * - * @return object A reference to the XmlNode object - */ - public function &nextSibling() { - $null = null; - $count = count($this->__parent->children); - for ($i = 0; $i < $count; $i++) { - if ($this->__parent->children[$i] == $this) { - if ($i >= $count - 1 || !isset($this->__parent->children[$i + 1])) { - return $null; - } - return $this->__parent->children[$i + 1]; - } - } - return $null; - } - -/** - * Gets a reference to the previous child node in the list of this node's parent. - * - * @return object A reference to the XmlNode object - */ - public function &previousSibling() { - $null = null; - $count = count($this->__parent->children); - for ($i = 0; $i < $count; $i++) { - if ($this->__parent->children[$i] == $this) { - if ($i == 0 || !isset($this->__parent->children[$i - 1])) { - return $null; - } - return $this->__parent->children[$i - 1]; - } - } - return $null; - } - -/** - * Returns parent node. - * - * @return object Parent XmlNode - */ - public function &parent() { - return $this->__parent; - } - -/** - * Returns the XML document to which this node belongs - * - * @return object Parent XML object - */ - public function &document() { - $document =& $this; - while (true) { - if (get_class($document) == 'Xml' || $document == null) { - break; - } - $document =& $document->parent(); - } - return $document; - } - -/** - * Returns true if this structure has child nodes. - * - * @return bool - */ - public function hasChildren() { - if (is_array($this->children) && !empty($this->children)) { - return true; - } - return false; - } - -/** - * Returns this XML structure as a string. - * - * @return string String representation of the XML structure. - */ - public function toString($options = array(), $depth = 0) { - if (is_int($options)) { - $depth = $options; - $options = array(); - } - $defaults = array('cdata' => true, 'whitespace' => false, 'convertEntities' => false, 'showEmpty' => true, 'leaveOpen' => false); - $options = array_merge($defaults, Xml::options(), $options); - $tag = !(strpos($this->name, '#') === 0); - $d = ''; - - if ($tag) { - if ($options['whitespace']) { - $d .= str_repeat("\t", $depth); - } - - $d .= '<' . $this->name(); - if (!empty($this->namespaces) > 0) { - foreach ($this->namespaces as $key => $val) { - $val = str_replace('"', '\"', $val); - $d .= ' xmlns:' . $key . '="' . $val . '"'; - } - } - - $parent =& $this->parent(); - if ($parent->name === '#document' && !empty($parent->namespaces)) { - foreach ($parent->namespaces as $key => $val) { - $val = str_replace('"', '\"', $val); - $d .= ' xmlns:' . $key . '="' . $val . '"'; - } - } - - if (is_array($this->attributes) && !empty($this->attributes)) { - foreach ($this->attributes as $key => $val) { - if (is_bool($val) && $val === false) { - $val = 0; - } - $d .= ' ' . $key . '="' . htmlspecialchars($val, ENT_QUOTES, Configure::read('App.encoding')) . '"'; - } - } - } - - if (!$this->hasChildren() && empty($this->value) && $this->value !== 0 && $tag) { - if (!$options['leaveOpen']) { - $d .= ' />'; - } - if ($options['whitespace']) { - $d .= "\n"; - } - } elseif ($tag || $this->hasChildren()) { - if ($tag) { - $d .= '>'; - } - if ($this->hasChildren()) { - if ($options['whitespace']) { - $d .= "\n"; - } - $count = count($this->children); - $cDepth = $depth + 1; - for ($i = 0; $i < $count; $i++) { - $d .= $this->children[$i]->toString($options, $cDepth); - } - if ($tag) { - if ($options['whitespace'] && $tag) { - $d .= str_repeat("\t", $depth); - } - if (!$options['leaveOpen']) { - $d .= 'name() . '>'; - } - if ($options['whitespace']) { - $d .= "\n"; - } - } - } - } - return $d; - } - -/** - * Return array representation of current object. - * - * @param boolean $camelize true will camelize child nodes, false will not alter node names - * @return array Array representation - */ - public function toArray($camelize = true) { - $out = $this->attributes; - $multi = null; - - foreach ($this->children as $child) { - $key = $camelize ? Inflector::camelize($child->name) : $child->name; - - if (is_a($child, 'XmlTextNode')) { - $out['value'] = $child->value; - continue; - } elseif (isset($child->children[0]) && is_a($child->children[0], 'XmlTextNode')) { - $value = $child->children[0]->value; - if ($child->attributes) { - $value = array_merge(array('value' => $value), $child->attributes); - } - if (isset($out[$child->name]) || isset($multi[$key])) { - if (!isset($multi[$key])) { - $multi[$key] = array($out[$child->name]); - unset($out[$child->name]); - } - $multi[$key][] = $value; - } else { - $out[$child->name] = $value; - } - continue; - } elseif (count($child->children) === 0 && $child->value == '') { - $value = $child->attributes; - if (isset($out[$key]) || isset($multi[$key])) { - if (!isset($multi[$key])) { - $multi[$key] = array($out[$key]); - //unset($out[$key]); - } - $multi[$key][] = $value; - } elseif (!empty($value)) { - $out[$key] = $value; - } else { - $out[$child->name] = $value; - } - continue; - } else { - $value = $child->toArray($camelize); - } - - if (!isset($out[$key])) { - $out[$key] = $value; - } else { - if (!is_array($out[$key]) || !isset($out[$key][0])) { - $out[$key] = array($out[$key]); - } - $out[$key][] = $value; - } - } - - if (isset($multi)) { - $out = array_merge($out, $multi); - } - return $out; - } - -/** - * Returns data from toString when this object is converted to a string. - * - * @return string String representation of this structure. - * @access private - */ - function __toString() { - return $this->toString(); - } - -/** - * Debug method. Deletes the parent. Also deletes this node's children, - * if given the $recursive parameter. - * - * @param boolean $recursive Recursively delete elements. - */ - protected function _killParent($recursive = true) { - unset($this->__parent, $this->_log); - if ($recursive && $this->hasChildren()) { - for ($i = 0; $i < count($this->children); $i++) { - $this->children[$i]->_killParent(true); - } - } - } -} - -/** - * Main XML class. - * - * Parses and stores XML data, representing the root of an XML document - * - * @package cake - * @subpackage cake.cake.libs - * @since CakePHP v .0.10.3.1400 - */ -class Xml extends XmlNode { - -/** - * Resource handle to XML parser. - * - * @var resource - * @access private - */ - private $__parser; - -/** - * File handle to XML indata file. - * - * @var resource - * @access private - */ - private $__file; - -/** - * Raw XML string data (for loading purposes) - * - * @var string - * @access private - */ - private $__rawData = null; - -/** - * XML document header - * - * @var string - * @access protected - */ - protected $_header = null; - -/** - * Default array keys/object properties to use as tag names when converting objects or array - * structures to XML. Set by passing $options['tags'] to this object's constructor. - * - * @var array - * @access protected - */ - protected $_tags = array(); - -/** - * XML document version - * - * @var string - * @access private - */ - public $version = '1.0'; - -/** - * XML document encoding - * - * @var string - * @access private - */ - public $encoding = 'UTF-8'; - -/** - * Constructor. Sets up the XML parser with options, gives it this object as - * its XML object, and sets some variables. + * {{{ + * $value = array( + * 'tags' => array( + * 'tag' => array( + * array( + * 'id' => '1', + * 'name' => 'defect' + * ), + * array( + * 'id' => '2', + * 'name' => 'enhancement' + * ) + * ) + * ) + * ); + * $xml = Xml::build($value); + * }}} + * + * When building XML from an array ensure that there is only one top level element. * * ### Options - * - 'root': The name of the root element, defaults to '#document' - * - 'version': The XML version, defaults to '1.0' - * - 'encoding': Document encoding, defaults to 'UTF-8' - * - 'namespaces': An array of namespaces (as strings) used in this document - * - 'format': Specifies the format this document converts to when parsed or - * rendered out as text, either 'attributes' or 'tags', defaults to 'attributes' - * - 'tags': An array specifying any tag-specific formatting options, indexed - * by tag name. See XmlNode::normalize(). - * @param mixed $input The content with which this XML document should be initialized. Can be a - * string, array or object. If a string is specified, it may be a literal XML - * document, or a URL or file path to read from. - * @param array $options Options to set up with, for valid options see above: - * @see XmlNode::normalize() + * + * - `return` Can be 'simplexml' to return object of SimpleXMLElement or 'domdocument' to return DOMDocument. + * - If using array as input, you can pass `options` from Xml::fromArray. + * + * @param mixed $input XML string, a path to a file, an URL or an array + * @param array $options The options to use + * @return object SimpleXMLElement or DOMDocument + * @throws Exception */ - function __construct($input = null, $options = array()) { + public static function build($input, $options = array()) { + if (!is_array($options)) { + $options = array('return' => (string)$options); + } $defaults = array( - 'root' => '#document', 'tags' => array(), 'namespaces' => array(), - 'version' => '1.0', 'encoding' => 'UTF-8', 'format' => 'attributes' + 'return' => 'simplexml' ); - $options = array_merge($defaults, Xml::options(), $options); + $options = array_merge($defaults, $options); - foreach (array('version', 'encoding', 'namespaces') as $key) { - $this->{$key} = $options[$key]; - } - $this->_tags = $options['tags']; - parent::__construct('#document'); - - if ($options['root'] !== '#document') { - $Root =& $this->createNode($options['root']); - } else { - $Root =& $this; - } - - if (!empty($input)) { - if (is_string($input)) { - $Root->load($input); - } elseif (is_array($input) || is_object($input)) { - $Root->append($input, $options); + if (is_array($input) || is_object($input)) { + return self::fromArray((array)$input, $options); + } elseif (strpos($input, '<') !== false) { + if ($options['return'] === 'simplexml' || $options['return'] === 'simplexmlelement') { + return new SimpleXMLElement($input); } - } - } - -/** - * Initialize XML object from a given XML string. Returns false on error. - * - * @param string $input XML string, a path to a file, or an HTTP resource to load - * @return boolean Success - */ - public function load($input) { - if (!is_string($input)) { - return false; - } - $this->__rawData = null; - $this->_header = null; - - if (strstr($input, "<")) { - $this->__rawData = $input; - } elseif (strpos($input, 'http://') === 0 || strpos($input, 'https://') === 0) { - App::import('Core', 'HttpSocket'); - $socket = new HttpSocket(); - $this->__rawData = $socket->get($input); - } elseif (file_exists($input)) { - $this->__rawData = file_get_contents($input); - } else { - trigger_error(__('XML cannot be read')); - return false; - } - return $this->parse(); - } - -/** - * Parses and creates XML nodes from the __rawData property. - * - * @return boolean Success - * @access public - * @see Xml::load() - * @todo figure out how to link attributes and namespaces - */ - function parse() { - $this->__initParser(); - $this->__rawData = trim($this->__rawData); - $this->_header = trim(str_replace( - array('<' . '?', '?' . '>'), - array('', ''), - substr($this->__rawData, 0, strpos($this->__rawData, '?' . '>')) - )); - - xml_parse_into_struct($this->__parser, $this->__rawData, $vals); - $xml =& $this; - $count = count($vals); - - for ($i = 0; $i < $count; $i++) { - $data = $vals[$i]; - $data += array('tag' => null, 'value' => null, 'attributes' => array()); - switch ($data['type']) { - case "open" : - $xml =& $xml->createElement($data['tag'], $data['value'], $data['attributes']); - break; - case "close" : - $xml =& $xml->parent(); - break; - case "complete" : - $xml->createElement($data['tag'], $data['value'], $data['attributes']); - break; - case 'cdata': - $xml->createTextNode($data['value']); - break; + $dom = new DOMDocument(); + $dom->loadXML($input); + return $dom; + } elseif (file_exists($input) || strpos($input, 'http://') === 0 || strpos($input, 'https://') === 0) { + if ($options['return'] === 'simplexml' || $options['return'] === 'simplexmlelement') { + return new SimpleXMLElement($input, null, true); } + $dom = new DOMDocument(); + $dom->load($input); + return $dom; + } elseif (!is_string($input)) { + throw new Exception(__('Invalid input.')); } - xml_parser_free($this->__parser); - $this->__parser = null; - return true; + throw new Exception(__('XML cannot be read.')); } /** - * Initializes the XML parser resource + * Transform an array into a SimpleXMLElement * - * @return void - * @access private + * ### Options + * + * - `format` If create childs ('tags') or attributes ('attribute'). + * - `version` Version of XML document. Default is 1.0. + * - `encoding` Encoding of XML document. If null remove from XML header. Default is the some of application. + * - `return` If return object of SimpleXMLElement ('simplexml') or DOMDocument ('domdocument'). Default is SimpleXMLElement. + * + * Using the following data: + * + * {{{ + * $value = array( + * 'root' => array( + * 'tag' => array( + * 'id' => 1, + * 'value' => 'defect', + * '@' => 'description' + * ) + * ) + * ); + * }}} + * + * Calling `Xml::fromArray($value, 'tags');` Will generate: + * + * `1defectdescription` + * + * And calling `Xml::fromArray($value, 'attribute');` Will generate: + * + * `description` + * + * @param array $input Array with data + * @param array $options The options to use + * @return object SimpleXMLElement or DOMDocument */ - function __initParser() { - if (empty($this->__parser)) { - $this->__parser = xml_parser_create(); - xml_set_object($this->__parser, $this); - xml_parser_set_option($this->__parser, XML_OPTION_CASE_FOLDING, 0); - xml_parser_set_option($this->__parser, XML_OPTION_SKIP_WHITE, 1); + public static function fromArray($input, $options = array()) { + if (!is_array($input) || count($input) !== 1) { + throw new Exception(__('Invalid input.')); } - } - -/** - * Returns a string representation of the XML object - * - * @param mixed $options If boolean: whether to include the XML header with the document - * (defaults to true); if an array, overrides the default XML generation options - * @return string XML data - * @access public - * @deprecated - * @see Xml::toString() - */ - function compose($options = array()) { - return $this->toString($options); - } - -/** - * If debug mode is on, this method echoes an error message. - * - * @param string $msg Error message - * @param integer $code Error code - * @param integer $line Line in file - */ - public function error($msg, $code = 0, $line = 0) { - if (Configure::read('debug')) { - echo $msg . " " . $code . " " . $line; + $key = key($input); + if (is_integer($key)) { + throw new Exception(__('The key of input must be alphanumeric')); } + + if (!is_array($options)) { + $options = array('format' => (string)$options); + } + $defaults = array( + 'format' => 'tags', + 'version' => '1.0', + 'encoding' => Configure::read('App.encoding'), + 'return' => 'simplexml' + ); + $options = array_merge($defaults, $options); + + $dom = new DOMDocument($options['version'], $options['encoding']); + self::_fromArray($dom, $dom, $input, $options['format']); + + $options['return'] = strtolower($options['return']); + if ($options['return'] === 'simplexml' || $options['return'] === 'simplexmlelement') { + return new SimpleXMLElement($dom->saveXML()); + } + return $dom; } /** - * Returns a string with a textual description of the error code, or FALSE if no description was found. + * Recursive method to create childs from array * - * @param integer $code Error code - * @return string Error message - */ - public function getError($code) { - $r = @xml_error_string($code); - return $r; - } - -// Overridden functions from superclass - -/** - * Get next element. NOT implemented. - * - * @return object - */ - public function &next() { - $return = null; - return $return; - } - -/** - * Get previous element. NOT implemented. - * - * @return object - */ - public function &previous() { - $return = null; - return $return; - } - -/** - * Get parent element. NOT implemented. - * - * @return object - */ - public function &parent() { - $return = null; - return $return; - } - -/** - * Adds a namespace to the current document - * - * @param string $prefix The namespace prefix - * @param string $url The namespace DTD URL + * @param object $dom Handler to DOMDocument + * @param object $node Handler to DOMElement (child) + * @param array $data Array of data to append to the $node. + * @param string $format Either 'attribute' or 'tags'. This determines where nested keys go. * @return void */ - function addNamespace($prefix, $url) { - if ($count = count($this->children)) { - for ($i = 0; $i < $count; $i++) { - $this->children[$i]->addNamespace($prefix, $url); - } - return true; + protected function _fromArray(&$dom, &$node, &$data, $format) { + if (empty($data) || !is_array($data)) { + return; } - return parent::addNamespace($prefix, $url); - } - -/** - * Removes a namespace to the current document - * - * @param string $prefix The namespace prefix - * @return void - */ - function removeNamespace($prefix) { - if ($count = count($this->children)) { - for ($i = 0; $i < $count; $i++) { - $this->children[$i]->removeNamespace($prefix); - } - return true; - } - return parent::removeNamespace($prefix); - } - -/** - * Return string representation of current object. - * - * @return string String representation - */ - public function toString($options = array()) { - if (is_bool($options)) { - $options = array('header' => $options); - } - - $defaults = array('header' => false, 'encoding' => $this->encoding); - $options = array_merge($defaults, Xml::options(), $options); - $data = parent::toString($options, 0); - - if ($options['header']) { - if (!empty($this->_header)) { - return $this->header($this->_header) . "\n" . $data; - } - return $this->header() . "\n" . $data; - } - - return $data; - } - -/** - * Return a header used on the first line of the xml file - * - * @param mixed $attrib attributes of the header element - * @return string formated header - */ - function header($attrib = array()) { - $header = 'xml'; - if (is_string($attrib)) { - $header = $attrib; - } else { - - $attrib = array_merge(array('version' => $this->version, 'encoding' => $this->encoding), $attrib); - foreach ($attrib as $key=>$val) { - $header .= ' ' . $key . '="' . $val . '"'; - } - } - return '<' . '?' . $header . ' ?' . '>'; - } - -/** - * Destructor, used to free resources. - * - * @access private - */ - function __destruct() { - $this->_killParent(true); - } - -/** - * Adds a namespace to any XML documents generated or parsed - * - * @param string $name The namespace name - * @param string $url The namespace URI; can be empty if in the default namespace map - * @return boolean False if no URL is specified, and the namespace does not exist - * default namespace map, otherwise true - * @access public - * @static - */ - function addGlobalNs($name, $url = null) { - $_this =& XmlManager::getInstance(); - if ($ns = Xml::resolveNamespace($name, $url)) { - $_this->namespaces = array_merge($_this->namespaces, $ns); - return $ns; - } - return false; - } - -/** - * Resolves current namespace - * - * @param string $name - * @param string $url - * @return array - */ - function resolveNamespace($name, $url) { - $_this =& XmlManager::getInstance(); - if ($url == null && isset($_this->defaultNamespaceMap[$name])) { - $url = $_this->defaultNamespaceMap[$name]; - } elseif ($url == null) { - return false; - } - - if (!strpos($url, '://') && isset($_this->defaultNamespaceMap[$name])) { - $_url = $_this->defaultNamespaceMap[$name]; - $name = $url; - $url = $_url; - } - return array($name => $url); - } - -/** - * Alias to Xml::addNs - * - * @access public - * @static - */ - function addGlobalNamespace($name, $url = null) { - return Xml::addGlobalNs($name, $url); - } - -/** - * Removes a namespace added in addNs() - * - * @param string $name The namespace name or URI - * @access public - * @static - */ - function removeGlobalNs($name) { - $_this =& XmlManager::getInstance(); - if (isset($_this->namespaces[$name])) { - unset($_this->namespaces[$name]); - unset($this->namespaces[$name]); - return true; - } elseif (in_array($name, $_this->namespaces)) { - $keys = array_keys($_this->namespaces); - $count = count($keys); - for ($i = 0; $i < $count; $i++) { - if ($_this->namespaces[$keys[$i]] == $name) { - unset($_this->namespaces[$keys[$i]]); - unset($this->namespaces[$keys[$i]]); - return true; - } - } - } - return false; - } - -/** - * Alias to Xml::removeNs - * - * @access public - * @static - */ - function removeGlobalNamespace($name) { - return Xml::removeGlobalNs($name); - } - -/** - * Sets/gets global XML options - * - * @param array $options - * @return array - * @access public - * @static - */ - function options($options = array()) { - $_this =& XmlManager::getInstance(); - $_this->options = array_merge($_this->options, $options); - return $_this->options; - } -} - -/** - * The XML Element - * - */ -class XmlElement extends XmlNode { - -/** - * Construct an Xml element - * - * @param string $name name of the node - * @param string $value value of the node - * @param array $attributes - * @param string $namespace - * @return string A copy of $data in XML format - */ - function __construct($name = null, $value = null, $attributes = array(), $namespace = false) { - parent::__construct($name, $value, $namespace); - $this->addAttribute($attributes); - } - -/** - * Get all the attributes for this element - * - * @return array - */ - function attributes() { - return $this->attributes; - } - -/** - * Add attributes to this element - * - * @param string $name name of the node - * @param string $value value of the node - * @return boolean - */ - function addAttribute($name, $val = null) { - if (is_object($name)) { - $name = get_object_vars($name); - } - if (is_array($name)) { - foreach ($name as $key => $val) { - $this->addAttribute($key, $val); - } - return true; - } - if (is_numeric($name)) { - $name = $val; - $val = null; - } - if (!empty($name)) { - if (strpos($name, 'xmlns') === 0) { - if ($name == 'xmlns') { - $this->namespace = $val; + foreach ($data as $key => $value) { + if (is_string($key)) { + if (!is_array($value)) { + if (is_bool($value)) { + $value = (int)$value; + } elseif ($value === null) { + $value = ''; + } + $isNamespace = strpos($key, 'xmlns:'); + $nsUri = null; + if ($isNamespace !== false) { + $node->setAttributeNS('http://www.w3.org/2000/xmlns/', $key, $value); + continue; + } + if ($key[0] !== '@' && $format === 'tags') { + $child = $dom->createElement($key, $value); + $node->appendChild($child); + } else { + if ($key[0] === '@') { + $key = substr($key, 1); + } + $attribute = $dom->createAttribute($key); + $attribute->appendChild($dom->createTextNode($value)); + $node->appendChild($attribute); + } } else { - list($pre, $prefix) = explode(':', $name); - $this->addNamespace($prefix, $val); - return true; + if ($key[0] === '@') { + throw new Exception(__('Invalid array')); + } + if (array_keys($value) === range(0, count($value) - 1)) { // List + foreach ($value as $item) { + $data = compact('dom', 'node', 'key', 'format'); + $data['value'] = $item; + self::__createChild($data); + } + } else { // Struct + self::__createChild(compact('dom', 'node', 'key', 'value', 'format')); + } } + } else { + throw new Exception(__('Invalid array')); } - $this->attributes[$name] = $val; - return true; } - return false; } /** - * Remove attributes to this element + * Helper to _fromArray(). It will create childs of arrays * - * @param string $name name of the node - * @return boolean + * @param array $data Array with informations to create childs + * @return void */ - function removeAttribute($attr) { - if (array_key_exists($attr, $this->attributes)) { - unset($this->attributes[$attr]); - return true; + private function __createChild($data) { + extract($data); + $childNS = $childValue = null; + if (is_array($value)) { + if (isset($value['@'])) { + $childValue = (string)$value['@']; + unset($value['@']); + } + if (isset($value['xmlns:'])) { + $childNS = $value['xmlns:']; + unset($value['xmlns:']); + } + } elseif (!empty($value) || $value === 0) { + $childValue = (string)$value; } - return false; - } -} -/** - * XML text or CDATA node - * - * Stores XML text data according to the encoding of the parent document - * - * @package cake - * @subpackage cake.cake.libs - * @since CakePHP v .1.2.6000 - */ -class XmlTextNode extends XmlNode { + if ($childValue) { + $child = $dom->createElement($key, $childValue); + } else { + $child = $dom->createElement($key); + } + if ($childNS) { + $child->setAttribute('xmlns', $childNS); + } -/** - * Harcoded XML node name, represents this object as a text node - * - * @var string - */ - public $name = '#text'; - -/** - * The text/data value which this node contains - * - * @var string - */ - public $value = null; - -/** - * Construct text node with the given parent object and data - * - * @param object $parent Parent XmlNode/XmlElement object - * @param mixed $value Node value - */ - function __construct($value = null) { - $this->value = $value; + self::_fromArray($dom, $child, $value, $format); + $node->appendChild($child); } /** - * Looks for child nodes in this element + * Returns this XML structure as a array. * - * @return boolean False - not supported + * @param object $obj SimpleXMLElement, DOMDocument or DOMNode instance + * @return array Array representation of the XML structure. */ - function hasChildren() { - return false; + public static function toArray($obj) { + if ($obj instanceof DOMNode) { + $obj = simplexml_import_dom($obj); + } + if (!($obj instanceof SimpleXMLElement)) { + throw new Exception(__('The input is not instance of SimpleXMLElement, DOMDocument or DOMNode.')); + } + $result = array(); + $namespaces = array_merge(array('' => ''), $obj->getNamespaces(true)); + self::_toArray($obj, $result, '', array_keys($namespaces)); + return $result; } /** - * Append an XML node: XmlTextNode does not support this operation + * Recursive method to toArray * - * @return boolean False - not supported - * @todo make convertEntities work without mb support, convert entities to number entities + * @param object $xml SimpleXMLElement object + * @param array $parentData Parent array with data + * @param string $ns Namespace of current child + * @param array $namespaces List of namespaces in XML + * @return void */ - function append() { - return false; + protected static function _toArray($xml, &$parentData, $ns, $namespaces) { + $data = array(); + + foreach ($namespaces as $namespace) { + foreach ($xml->attributes($namespace, true) as $key => $value) { + if (!empty($namespace)) { + $key = $namespace . ':' . $key; + } + $data['@' . $key] = (string)$value; + } + + foreach ($xml->children($namespace, true) as $child) { + self::_toArray($child, $data, $namespace, $namespaces); + } + } + + $asString = trim((string)$xml); + if (empty($data)) { + $data = $asString; + } elseif (!empty($asString)) { + $data['@'] = $asString; + } + + if (!empty($ns)) { + $ns .= ':'; + } + $name = $ns . $xml->getName(); + if (isset($parentData[$name])) { + if (!is_array($parentData[$name]) || !isset($parentData[$name][0])) { + $parentData[$name] = array($parentData[$name]); + } + $parentData[$name][] = $data; + } else { + $parentData[$name] = $data; + } } -/** - * Return string representation of current text node object. - * - * @return string String representation - */ - public function toString($options = array(), $depth = 0) { - if (is_int($options)) { - $depth = $options; - $options = array(); - } - - $defaults = array('cdata' => true, 'whitespace' => false, 'convertEntities' => false); - $options = array_merge($defaults, Xml::options(), $options); - $val = $this->value; - - if ($options['convertEntities'] && function_exists('mb_convert_encoding')) { - $val = mb_convert_encoding($val,'UTF-8', 'HTML-ENTITIES'); - } - - if ($options['cdata'] === true && !is_numeric($val)) { - $val = ''; - } - - if ($options['whitespace']) { - return str_repeat("\t", $depth) . $val . "\n"; - } - return $val; - } -} - -/** - * Manages application-wide namespaces and XML parsing/generation settings. - * Private class, used exclusively within scope of XML class. - * - * @access private - */ -class XmlManager { - -/** - * Global XML namespaces. Used in all XML documents processed by this application - * - * @var array - * @access public - */ - public $namespaces = array(); - -/** - * Global XML document parsing/generation settings. - * - * @var array - * @access public - */ - public $options = array(); - -/** - * Map of common namespace URIs - * - * @access private - * @var array - */ - public $defaultNamespaceMap = array( - 'dc' => 'http://purl.org/dc/elements/1.1/', // Dublin Core - 'dct' => 'http://purl.org/dc/terms/', // Dublin Core Terms - 'g' => 'http://base.google.com/ns/1.0', // Google Base - 'rc' => 'http://purl.org/rss/1.0/modules/content/', // RSS 1.0 Content Module - 'wf' => 'http://wellformedweb.org/CommentAPI/', // Well-Formed Web Comment API - 'fb' => 'http://rssnamespace.org/feedburner/ext/1.0', // FeedBurner extensions - 'lj' => 'http://www.livejournal.org/rss/lj/1.0/', // Live Journal - 'itunes' => 'http://www.itunes.com/dtds/podcast-1.0.dtd', // iTunes - 'xhtml' => 'http://www.w3.org/1999/xhtml', // XHTML, - 'atom' => 'http://www.w3.org/2005/Atom' // Atom - ); - -/** - * Returns a reference to the global XML object that manages app-wide XML settings - * - * @return object - */ - public function &getInstance() { - static $instance = array(); - - if (!$instance) { - $instance[0] =& new XmlManager(); - } - return $instance[0]; - } -} +} \ No newline at end of file diff --git a/cake/tests/cases/libs/all_xml.test.php b/cake/tests/cases/libs/all_xml.test.php index 70625ae31..aed5b21d1 100644 --- a/cake/tests/cases/libs/all_xml.test.php +++ b/cake/tests/cases/libs/all_xml.test.php @@ -38,7 +38,6 @@ class AllXmlTest extends PHPUnit_Framework_TestSuite { $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'xml.test.php'); $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'view' . DS . 'helpers' . DS . 'rss.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'view' . DS . 'helpers' . DS . 'xml.test.php'); return $suite; } } \ No newline at end of file diff --git a/cake/tests/cases/libs/set.test.php b/cake/tests/cases/libs/set.test.php index 9e3b536f1..e2f92a4fd 100644 --- a/cake/tests/cases/libs/set.test.php +++ b/cake/tests/cases/libs/set.test.php @@ -2674,20 +2674,20 @@ class SetTest extends CakeTestCase { '; - $xml = new Xml($string); + $xml = Xml::build($string); $result = Set::reverse($xml); - $expected = array('Rss' => array( + $expected = array('rss' => array( 'version' => '2.0', - 'Channel' => array( + 'channel' => array( 'title' => 'Cake PHP Google Group', 'link' => 'http://groups.google.com/group/cake-php', 'description' => 'Search this group before posting anything. There are over 20,000 posts and it's very likely your question was answered before. Visit the IRC channel #cakephp at irc.freenode.net for live chat with users and developers of Cake. If you post, tell us the version of Cake, PHP, and database.', 'language' => 'en', - 'Item' => array( + 'item' => array( array( 'title' => 'constructng result array when using findall', 'link' => 'http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f', - 'description' => "i'm using cakephp to construct a logical data model array that will be
passed to a flex app. I have the following model association:
ServiceDay->(hasMany)ServiceTi me->(hasMany)ServiceTimePrice. So what
the current output from my findall is something like this example:

Array(
[0] => Array(", + 'description' => "i'm using cakephp to construct a logical data model array that will be
passed to a flex app. I have the following model association:
ServiceDay->(hasMany)ServiceTi me->(hasMany)ServiceTimePrice. So what
the current output from my findall is something like this example:

Array(
[0] => Array(", 'guid' => array('isPermaLink' => 'true', 'value' => 'http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f'), 'author' => 'bmil...@gmail.com(bpscrugs)', 'pubDate' => 'Fri, 28 Dec 2007 00:44:14 UT', @@ -2706,43 +2706,43 @@ class SetTest extends CakeTestCase { $this->assertEqual($result, $expected); $string =''; - $xml = new Xml($string); + $xml = Xml::build($string); $result = Set::reverse($xml); - $expected = array('Data' => array('Post' => array('title' => 'Title of this post', 'description' => 'cool'))); + $expected = array('data' => array('post' => array('title' => 'Title of this post', 'description' => 'cool'))); $this->assertEqual($result, $expected); - $xml = new Xml('An example of a correctly reversed XMLNode'); + $xml = Xml::build('An example of a correctly reversed SimpleXMLElement'); $result = Set::reverse($xml); - $expected = array('Example' => + $expected = array('example' => array( - 'Item' => array( - 'title' => 'An example of a correctly reversed XMLNode', - 'desc' => array(), + 'item' => array( + 'title' => 'An example of a correctly reversed SimpleXMLElement', + 'desc' => '', ) ) ); $this->assertEquals($result, $expected); - $xml = new Xml('title1title2'); + $xml = Xml::build('title1title2'); $result = Set::reverse($xml); $expected = - array('Example' => array( - 'Item' => array( + array('example' => array( + 'item' => array( 'attr' => '123', - 'Titles' => array( - 'Title' => array('title1', 'title2') + 'titles' => array( + 'title' => array('title1', 'title2') ) ) ) ); $this->assertEquals($result, $expected); - $xml = new Xml('listtextforitems'); + $xml = Xml::build('listtextforitems'); $result = Set::reverse($xml); $expected = - array('Example' => array( + array('example' => array( 'attr' => 'ex_attr', - 'Item' => array( + 'item' => array( 'attr' => '123', 'titles' => 'list', 'value' => 'textforitems' @@ -2752,7 +2752,7 @@ class SetTest extends CakeTestCase { $this->assertEquals($result, $expected); $string = ' - + Cake PHP Google Group http://groups.google.com/group/cake-php @@ -2783,23 +2783,23 @@ class SetTest extends CakeTestCase { '; - $xml = new Xml($string); + $xml = Xml::build($string); $result = Set::reverse($xml); - $expected = array('Rss' => array( + $expected = array('rss' => array( 'version' => '2.0', - 'Channel' => array( + 'channel' => array( 'title' => 'Cake PHP Google Group', 'link' => 'http://groups.google.com/group/cake-php', 'description' => 'Search this group before posting anything. There are over 20,000 posts and it's very likely your question was answered before. Visit the IRC channel #cakephp at irc.freenode.net for live chat with users and developers of Cake. If you post, tell us the version of Cake, PHP, and database.', 'language' => 'en', - 'Item' => array( + 'item' => array( array( 'title' => 'constructng result array when using findall', 'link' => 'http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f', - 'description' => "i'm using cakephp to construct a logical data model array that will be
passed to a flex app. I have the following model association:
ServiceDay->(hasMany)ServiceTi me->(hasMany)ServiceTimePrice. So what
the current output from my findall is something like this example:

Array(
[0] => Array(", + 'description' => "i'm using cakephp to construct a logical data model array that will be
passed to a flex app. I have the following model association:
ServiceDay->(hasMany)ServiceTi me->(hasMany)ServiceTimePrice. So what
the current output from my findall is something like this example:

Array(
[0] => Array(", 'creator' => 'cakephp', - 'Category' => array('cakephp', 'model'), + 'category' => array('cakephp', 'model'), 'guid' => array('isPermaLink' => 'true', 'value' => 'http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f'), 'author' => 'bmil...@gmail.com(bpscrugs)', 'pubDate' => 'Fri, 28 Dec 2007 00:44:14 UT', @@ -2809,7 +2809,7 @@ class SetTest extends CakeTestCase { 'link' => 'http://groups.google.com/group/cake-php/msg/8b350d898707dad8', 'description' => 'Then perhaps you might do us all a favour and refrain from replying to
things you do not understand. That goes especially for asinine comments.
Indeed.
To sum up:
No comment.
In my day, a simple "RTFM" would suffice. I\'ll keep in mind to ignore any
further responses from you.
You (and I) were referring to the *online documentation*, not other', 'creator' => 'cakephp', - 'Category' => array('cakephp', 'model'), + 'category' => array('cakephp', 'model'), 'guid' => array('isPermaLink' => 'true', 'value' => 'http://groups.google.com/group/cake-php/msg/8b350d898707dad8'), 'author' => 'subtropolis.z...@gmail.com(subtropolis zijn)', 'pubDate' => 'Fri, 28 Dec 2007 00:45:01 UT' @@ -2841,15 +2841,13 @@ class SetTest extends CakeTestCase { '; - $xml = new Xml($text); + $xml = Xml::build($text); $result = Set::reverse($xml); $expected = array('XRDS' => array( - 'xmlns' => 'xri://$xrds', 'XRD' => array( array( - 'xml:id' => 'oauth', - 'xmlns' => 'xri://$XRD*($v*2.0)', + 'id' => 'oauth', 'version' => '2.0', 'Type' => 'xri://$xrds*simple', 'Expires' => '2008-04-13T07:34:58Z', @@ -2872,7 +2870,6 @@ class SetTest extends CakeTestCase { ) ), array( - 'xmlns' => 'xri://$XRD*($v*2.0)', 'version' => '2.0', 'Type' => 'xri://$xrds*simple', 'Service' => array( diff --git a/cake/tests/cases/libs/view/helpers/rss.test.php b/cake/tests/cases/libs/view/helpers/rss.test.php index f99e6343d..b61d6dd32 100644 --- a/cake/tests/cases/libs/view/helpers/rss.test.php +++ b/cake/tests/cases/libs/view/helpers/rss.test.php @@ -38,9 +38,6 @@ class RssHelperTest extends CakeTestCase { $controller = null; $this->View = new View($controller); $this->Rss = new RssHelper($this->View); - - $manager =& XmlManager::getInstance(); - $manager->namespaces = array(); } /** @@ -54,52 +51,6 @@ class RssHelperTest extends CakeTestCase { } /** - * testAddNamespace method - * - * @access public - * @return void - */ - function testAddNamespace() { - $this->Rss->addNs('custom', 'http://example.com/dtd.xml'); - $manager =& XmlManager::getInstance(); - - $expected = array('custom' => 'http://example.com/dtd.xml'); - $this->assertEqual($manager->namespaces, $expected); - - $this->Rss->removeNs('custom'); - - $this->Rss->addNs('dummy', 'http://dummy.com/1.0/'); - $result = $this->Rss->document(); - $expected = array( - 'rss' => array( - 'xmlns:dummy' => 'http://dummy.com/1.0/', - 'version' => '2.0' - ) - ); - $this->assertTags($result, $expected); - - $this->Rss->removeNs('dummy'); - } - -/** - * testRemoveNamespace method - * - * @access public - * @return void - */ - function testRemoveNamespace() { - $this->Rss->addNs('custom', 'http://example.com/dtd.xml'); - $this->Rss->addNs('custom2', 'http://example.com/dtd2.xml'); - $manager =& XmlManager::getInstance(); - - $expected = array('custom' => 'http://example.com/dtd.xml', 'custom2' => 'http://example.com/dtd2.xml'); - $this->assertEqual($manager->namespaces, $expected); - - $this->Rss->removeNs('custom'); - $expected = array('custom2' => 'http://example.com/dtd2.xml'); - $this->assertEqual($manager->namespaces, $expected); - } - /** * testDocument method * * @access public @@ -253,6 +204,7 @@ class RssHelperTest extends CakeTestCase { ' array( + 'xmlns:atom' => 'http://www.w3.org/2005/Atom', 'href' => "http://www.example.com/rss.xml", 'rel' => "self", 'type' =>"application/rss+xml" @@ -387,22 +339,6 @@ class RssHelperTest extends CakeTestCase { ); $this->assertTags($result, $expected); - $item = array( - 'title' => array( - 'value' => 'My Title & more', - 'convertEntities' => false - ) - ); - $result = $this->Rss->item(null, $item); - $expected = array( - 'assertTags($result, $expected); - $item = array( 'title' => array( 'value' => 'My Title & more', diff --git a/cake/tests/cases/libs/view/helpers/xml.test.php b/cake/tests/cases/libs/view/helpers/xml.test.php deleted file mode 100644 index 52706aea6..000000000 --- a/cake/tests/cases/libs/view/helpers/xml.test.php +++ /dev/null @@ -1,289 +0,0 @@ - - * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) - * - * Licensed under The MIT License - * Redistributions of files must retain the above copyright notice - * - * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests - * @package cake - * @subpackage cake.tests.cases.libs.view.helpers - * @since CakePHP(tm) v 1.2.0.4206 - * @license MIT License (http://www.opensource.org/licenses/mit-license.php) - */ -if (!defined('CAKEPHP_UNIT_TEST_EXECUTION')) { - define('CAKEPHP_UNIT_TEST_EXECUTION', 1); -} -App::import('Helper', 'Xml'); -App::import('Core', 'View'); - -/** - * TestXml class - * - * @package cake - * @subpackage cake.tests.cases.libs.view.helpers - */ -class TestXmlHelper extends Object { - -/** - * content property - * - * @var string '' - * @access public - */ - public $content = ''; - -/** - * construct method - * - * @param mixed $content - * @access private - * @return void - */ - function __construct($content) { - $this->content = $content; - } - -/** - * toString method - * - * @access public - * @return void - */ - function toString() { - return $this->content; - } -} - -/** - * XmlHelperTest class - * - * @package cake - * @subpackage cake.tests.cases.libs.view.helpers - */ -class XmlHelperTest extends CakeTestCase { - -/** - * setUp method - * - * @access public - * @return void - */ - function setUp() { - $controller = null; - $View = new View($controller); - $this->Xml = new XmlHelper($View); - $manager =& XmlManager::getInstance(); - $manager->namespaces = array(); - } - -/** - * tearDown method - * - * @access public - * @return void - */ - function tearDown() { - unset($this->Xml); - } - -/** - * testAddNamespace method - * - * @access public - * @return void - */ - function testAddNamespace() { - $this->Xml->addNs('custom', 'http://example.com/dtd.xml'); - $manager =& XmlManager::getInstance(); - - $expected = array('custom' => 'http://example.com/dtd.xml'); - $this->assertEqual($manager->namespaces, $expected); - } - -/** - * testRemoveNamespace method - * - * @access public - * @return void - */ - function testRemoveNamespace() { - $this->Xml->addNs('custom', 'http://example.com/dtd.xml'); - $this->Xml->addNs('custom2', 'http://example.com/dtd2.xml'); - $manager =& XmlManager::getInstance(); - - $expected = array('custom' => 'http://example.com/dtd.xml', 'custom2' => 'http://example.com/dtd2.xml'); - $this->assertEqual($manager->namespaces, $expected); - - $this->Xml->removeNs('custom'); - $expected = array('custom2' => 'http://example.com/dtd2.xml'); - $this->assertEqual($manager->namespaces, $expected); - } - -/** - * testRenderZeroElement method - * - * @access public - * @return void - */ - function testRenderZeroElement() { - $result = $this->Xml->elem('count', null, 0); - $expected = '0'; - $this->assertEqual($result, $expected); - - $result = $this->Xml->elem('count', null, array('cdata' => true, 'value' => null)); - $expected = ''; - $this->assertEqual($result, $expected); - } - -/** - * testRenderElementWithNamespace method - * - * @access public - * @return void - */ - function testRenderElementWithNamespace() { - $result = $this->Xml->elem('count', array('namespace' => 'myNameSpace'), 'content'); - $expected = 'content'; - $this->assertEqual($result, $expected); - - $result = $this->Xml->elem('count', array('namespace' => 'myNameSpace'), 'content', false); - $expected = 'content'; - $this->assertEqual($result, $expected); - - $expected .= ''; - $result .= $this->Xml->closeElem(); - $this->assertEqual($result, $expected); - } - /** - * testRenderElementWithComplexContent method - * - * @access public - * @return void - */ - function testRenderElementWithComplexContent() { - $result = $this->Xml->elem('count', array('namespace' => 'myNameSpace'), array('contrived' => 'content')); - $expected = ''; - $this->assertEqual($result, $expected); - - $result = $this->Xml->elem('count', array('namespace' => 'myNameSpace'), array('cdata' => true, 'value' => 'content')); - $expected = ''; - $this->assertEqual($result, $expected); - } - -/** - * testSerialize method - * - * @access public - * @return void - */ - function testSerialize() { - $data = array( - 'test1' => 'test with no quotes', - 'test2' => 'test with "double quotes"' - ); - $result = $this->Xml->serialize($data); - $expected = ''; - $this->assertIdentical($result, $expected); - - $data = array( - 'test1' => 'test with no quotes', - 'test2' => 'test without double quotes' - ); - $result = $this->Xml->serialize($data); - $expected = ''; - $this->assertIdentical($result, $expected); - - $data = array( - 'ServiceDay' => array('ServiceTime' => array('ServiceTimePrice' => array('dollar' => 1, 'cents' => '2'))) - ); - $result = $this->Xml->serialize($data); - $expected = ''; - $this->assertIdentical($result, $expected); - - $data = array( - 'ServiceDay' => array('ServiceTime' => array('ServiceTimePrice' => array('dollar' => 1, 'cents' => '2'))) - ); - $result = $this->Xml->serialize($data, array('format' => 'tags')); - $expected = '12'; - $this->assertIdentical($result, $expected); - - $data = array( - 'Pages' => array('id' => 2, 'url' => 'http://www.url.com/rb/153/?id=bbbb&t=access') - ); - $result = $this->Xml->serialize($data); - $expected = ''; - $this->assertIdentical($result, $expected); - - $test = array( - 'Test' => array('test' => true) - ); - $expected = ''; - $result = $this->Xml->serialize($test); - $this->assertidentical($expected, $result); - } - -/** - * testSerializeOnMultiDimensionalArray method - * - * @access public - * @return void - */ - function testSerializeOnMultiDimensionalArray() { - $data = array( - 'Statuses' => array( - array('Status' => array('id' => 1)), - array('Status' => array('id' => 2)) - ) - ); - $result = $this->Xml->serialize($data, array('format' => 'tags')); - $expected = '12'; - $this->assertIdentical($result, $expected); - - } - -/** - * testHeader method - * - * @access public - * @return void - */ - function testHeader() { - $expectedDefaultEncoding = Configure::read('App.encoding'); - if (empty($expectedDefaultEncoding)) { - $expectedDefaultEncoding = 'UTF-8'; - } - $attrib = array(); - $result = $this->Xml->header($attrib); - $expected = ''; - $this->assertIdentical($result, $expected); - - $attrib = array( - 'encoding' => 'UTF-8', - 'version' => '1.1' - ); - $result = $this->Xml->header($attrib); - $expected = ''; - $this->assertIdentical($result, $expected); - - $attrib = array( - 'encoding' => 'UTF-8', - 'version' => '1.2', - 'additional' => 'attribute' - ); - $result = $this->Xml->header($attrib); - $expected = ''; - $this->assertIdentical($result, $expected); - - $attrib = 'encoding="UTF-8" someOther="value"'; - $result = $this->Xml->header($attrib); - $expected = ''; - $this->assertIdentical($result, $expected); - } -} diff --git a/cake/tests/cases/libs/xml.test.php b/cake/tests/cases/libs/xml.test.php index fef0bafcd..cc2d5d22e 100644 --- a/cake/tests/cases/libs/xml.test.php +++ b/cake/tests/cases/libs/xml.test.php @@ -20,21 +20,49 @@ App::import('Core', 'Xml'); /** - * Test XML Class + * Article class * - * @package cake - * @subpackage cake.tests.cases.libs + * @package cake + * @subpackage cake.tests.cases.libs */ -class TestXml extends Xml { +class Article extends CakeTestModel { /** - * Return the protected _header instance variable + * name property * - * @return string Header + * @var string 'Article' */ - public function getHeader() { - return $this->_header; - } + public $name = 'Article'; + +/** + * belongsTo property + * + * @var array + */ + public $belongsTo = array('User'); +} + +/** + * User class + * + * @package cake + * @subpackage cake.tests.cases.libs + */ +class User extends CakeTestModel { + +/** + * name property + * + * @var string 'User' + */ + public $name = 'User'; + +/** + * hasMany property + * + * @var array + */ + public $hasMany = array('Article'); } /** @@ -46,1392 +74,767 @@ class TestXml extends Xml { class XmlTest extends CakeTestCase { /** - * setUp method + * autoFixtures property + * + * @var bool false + */ + public $autoFixtures = false; + +/** + * fixtures property + * @var array + */ + public $fixtures = array( + 'core.article', 'core.user' + ); + +/** + * setup method * * @access public * @return void */ function setUp() { - parent::setUp(); - $manager = new XmlManager(); - $manager->namespaces = array(); + parent::setup(); + $this->_appEncoding = Configure::read('App.encoding'); + Configure::write('App.encoding', 'UTF-8'); } /** - * testRootTagParsing method + * tearDown method * * @access public * @return void */ - function testRootTagParsing() { - $input = '<' . '?xml version="1.0" encoding="UTF-8" ?' . '>' . "\n" . - '' - .'' - .'' - .''; - $xml = new Xml($input); - $this->assertEqual($xml->children[0]->name, 'plugin'); - $this->assertEqual($xml->children[0]->children[0]->name, 'current'); - $this->assertEqual($xml->toString(true), $input); + function tearDown() { + parent::tearDown(); + Configure::write('App.encoding', $this->_appEncoding); } /** - * testSerialization method + * testBuild method * - * @access public * @return void */ - function testSerialization() { - $input = array( - array( - 'Project' => array('id' => 1, 'title' => null, 'client_id' => 1, 'show' => 1, 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => 1, 'industry_id' => 1, 'modified' => null, 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 1, 'name' => 'Touch Screen Kiosk'), - 'Industry' => array('id' => 1, 'name' => 'Financial') - ), - array( - 'Project' => array('id' => 2, 'title' => null, 'client_id' => 2, 'show' => 1, 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => 2, 'industry_id' => 2, 'modified' => '2007-11-26 14:48:36', 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 2, 'name' => 'Awareness Campaign'), - 'Industry' => array('id' => 2, 'name' => 'Education') - ) + public function testBuild() { + $xml = 'value'; + $obj = Xml::build($xml); + $this->assertTrue($obj instanceof SimpleXMLElement); + $this->assertEqual((string)$obj->getName(), 'tag'); + $this->assertEqual((string)$obj, 'value'); + + $xml = 'value'; + $this->assertEqual($obj, Xml::build($xml)); + + $obj = Xml::build($xml, array('return' => 'domdocument')); + $this->assertTrue($obj instanceof DOMDocument); + $this->assertEqual($obj->firstChild->nodeName, 'tag'); + $this->assertEqual($obj->firstChild->nodeValue, 'value'); + + $xml = TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'fixtures' . DS . 'sample.xml'; + $obj = Xml::build($xml); + $this->assertEqual($obj->getName(), 'tags'); + $this->assertEqual(count($obj), 2); + + $this->assertEqual(Xml::build($xml), Xml::build(file_get_contents($xml))); + + $obj = Xml::build($xml, array('return' => 'domdocument')); + $this->assertEqual($obj->firstChild->nodeName, 'tags'); + + $this->assertEqual(Xml::build($xml, array('return' => 'domdocument')), Xml::build(file_get_contents($xml), array('return' => 'domdocument'))); + $this->assertEqual(Xml::build($xml, array('return' => 'simplexml')), Xml::build($xml, 'simplexml')); + + $xml = array('tag' => 'value'); + $obj = Xml::build($xml); + $this->assertEqual($obj->getName(), 'tag'); + $this->assertEqual((string)$obj, 'value'); + + $obj = Xml::build($xml, array('return' => 'domdocument')); + $this->assertEqual($obj->firstChild->nodeName, 'tag'); + $this->assertEqual($obj->firstChild->nodeValue, 'value'); + + $obj = Xml::build($xml, array('return' => 'domdocument', 'encoding' => null)); + $this->assertNoPattern('/encoding/', $obj->saveXML()); + } + +/** + * data provider function for testBuildInvalidData + * + * @return array + */ + public static function invalidDataProvider() { + return array( + array(null), + array(false), + array(''), + array('') ); - - $xml = new Xml($input); - $result = preg_replace("/\n/",'', $xml->toString(false)); - $expected = '1Touch Screen Kiosk1Financial2<client_id>2</client_id><show>1</show><is_spotlight /><style_id>0</style_id><job_type_id>2</job_type_id><industry_id>2</industry_id><modified>2007-11-26 14:48:36</modified><created /><style><id /><name /></style><job_type><id>2</id><name>Awareness Campaign</name></job_type><industry><id>2</id><name>Education</name></industry></project>'; - - $xml = new Xml($input, array('format' => 'tags')); - $result = $xml->toString(array('header' => false, 'cdata' => false)); - $this->assertEqual($expected, $result); - } - -/** - * testNestedArraySerialization method - * - * @access public - * @return void - */ - function testSerializationNestedArray() { - $input = array( - array( - 'Project' => array('id' => 1, 'title' => null, 'client_id' => 1, 'show' => 1, 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => 1, 'industry_id' => 1, 'modified' => null, 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 1, 'name' => 'Touch Screen Kiosk'), - 'Industry' => array('id' => 1, 'name' => 'Financial'), - 'BusinessSolution' => array(array('id' => 6, 'name' => 'Convert Sales')), - 'MediaType' => array( - array('id' => 15, 'name' => 'Print'), - array('id' => 7, 'name' => 'Web Demo'), - array('id' => 6, 'name' => 'CD-ROM') + $xml = array( + 'tags' => array( + 'tag' => array( + array( + 'id' => '1', + 'name' => 'defect' + ), + array( + 'id' => '2', + 'name' => 'enhancement' + ) ) - ), - array( - 'Project' => array('id' => 2, 'title' => null, 'client_id' => 2, 'show' => 1, 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => 2, 'industry_id' => 2, 'modified' => '2007-11-26 14:48:36', 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 2, 'name' => 'Awareness Campaign'), - 'Industry' => array('id' => 2, 'name' => 'Education'), - 'BusinessSolution' => array( - array('id' => 4, 'name' => 'Build Relationship'), - array('id' => 6, 'name' => 'Convert Sales') + ) + ); + $obj = Xml::fromArray($xml, 'attributes'); + $this->assertTrue($obj instanceof SimpleXMLElement); + $this->assertEqual($obj->getName(), 'tags'); + $this->assertEqual(count($obj), 2); + $xmlText = '<' . '?xml version="1.0" encoding="UTF-8"?><tags><tag id="1" name="defect"/><tag id="2" name="enhancement"/></tags>'; + $this->assertEqual(str_replace(array("\r", "\n"), '', $obj->asXML()), $xmlText); + + $obj = Xml::fromArray($xml); + $this->assertTrue($obj instanceof SimpleXMLElement); + $this->assertEqual($obj->getName(), 'tags'); + $this->assertEqual(count($obj), 2); + $xmlText = '<' . '?xml version="1.0" encoding="UTF-8"?><tags><tag><id>1</id><name>defect</name></tag><tag><id>2</id><name>enhancement</name></tag></tags>'; + $this->assertEqual(str_replace(array("\r", "\n"), '', $obj->asXML()), $xmlText); + + $xml = array( + 'tags' => array( + ) + ); + $obj = Xml::fromArray($xml); + $this->assertEqual($obj->getName(), 'tags'); + $this->assertEqual((string)$obj, ''); + + $xml = array( + 'tags' => array( + 'bool' => true, + 'int' => 1, + 'float' => 10.2, + 'string' => 'ok', + 'null' => null, + 'array' => array() + ) + ); + $obj = Xml::fromArray($xml, 'tags'); + $this->assertEqual(count($obj), 6); + $this->assertIdentical((string)$obj->bool, '1'); + $this->assertIdentical((string)$obj->int, '1'); + $this->assertIdentical((string)$obj->float, '10.2'); + $this->assertIdentical((string)$obj->string, 'ok'); + $this->assertIdentical((string)$obj->null, ''); + $this->assertIdentical((string)$obj->array, ''); + + $xml = array( + 'tags' => array( + 'tag' => array( + array( + '@id' => '1', + 'name' => 'defect' + ), + array( + '@id' => '2', + 'name' => 'enhancement' + ) + ) + ) + ); + $obj = Xml::fromArray($xml, 'tags'); + $xmlText = '<' . '?xml version="1.0" encoding="UTF-8"?><tags><tag id="1"><name>defect</name></tag><tag id="2"><name>enhancement</name></tag></tags>'; + $this->assertEqual(str_replace(array("\r", "\n"), '', $obj->asXML()), $xmlText); + + $xml = array( + 'tags' => array( + 'tag' => array( + array( + '@id' => '1', + 'name' => 'defect', + '@' => 'Tag 1' + ), + array( + '@id' => '2', + 'name' => 'enhancement' + ), ), - 'MediaType' => array( - array('id' => 17, 'name' => 'Web'), - array('id' => 6, 'name' => 'CD-ROM') - ) + '@' => 'All tags' ) ); - $expected = '<project><id>1</id><title /><client_id>1</client_id><show>1</show><is_spotlight /><style_id>0</style_id><job_type_id>1</job_type_id><industry_id>1</industry_id><modified /><created /><style><id /><name /></style><job_type><id>1</id><name>Touch Screen Kiosk</name></job_type><industry><id>1</id><name>Financial</name></industry><business_solution><id>6</id><name>Convert Sales</name></business_solution><media_type><id>15</id><name>Print</name></media_type><media_type><id>7</id><name>Web Demo</name></media_type><media_type><id>6</id><name>CD-ROM</name></media_type></project><project><id>2</id><title /><client_id>2</client_id><show>1</show><is_spotlight /><style_id>0</style_id><job_type_id>2</job_type_id><industry_id>2</industry_id><modified>2007-11-26 14:48:36</modified><created /><style><id /><name /></style><job_type><id>2</id><name>Awareness Campaign</name></job_type><industry><id>2</id><name>Education</name></industry><business_solution><id>4</id><name>Build Relationship</name></business_solution><business_solution><id>6</id><name>Convert Sales</name></business_solution><media_type><id>17</id><name>Web</name></media_type><media_type><id>6</id><name>CD-ROM</name></media_type></project>'; + $obj = Xml::fromArray($xml, 'tags'); + $xmlText = '<' . '?xml version="1.0" encoding="UTF-8"?><tags>All tags<tag id="1">Tag 1<name>defect</name></tag><tag id="2"><name>enhancement</name></tag></tags>'; + $this->assertEqual(str_replace(array("\r", "\n"), '', $obj->asXML()), $xmlText); - $xml = new Xml($input, array('format' => 'tags')); - $result = $xml->toString(array('header' => false, 'cdata' => false)); - $this->assertEqual($expected, $result); - } - -/** - * Prove that serialization with a given root node works - * as expected. - * - * @access public - * @return void - * @link https://trac.cakephp.org/ticket/6294 - */ - function testArraySerializationWithRoot() { - $input = array( - array('Shirt' => array('id' => 1, 'color' => 'green')), - array('Shirt' => array('id' => 2, 'color' => 'blue')), - ); - $expected = '<collection><shirt id="1" color="green" />'; - $expected .= '<shirt id="2" color="blue" /></collection>'; - - $Xml = new Xml($input, array('root' => 'collection')); - $result = $Xml->toString(array('header' => false)); - $this->assertEqual($expected, $result); - } - -/** - * testCloneNode - * - * @access public - * @return void - */ - function testCloneNode() { - $node =& new XmlNode('element', 'myValue'); - $twin =& $node->cloneNode(); - $this->assertEqual($node, $twin); - } - -/** - * testNextSibling - * - * @access public - * @return void - */ - function testNextSibling() { - $input = array( - array( - 'Project' => array('id' => 1, 'title' => null, 'client_id' => 1, 'show' => '1', 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => '1.89', 'industry_id' => '1.56', 'modified' => null, 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 1, 'name' => 'Touch Screen Kiosk'), - 'Industry' => array('id' => 1, 'name' => 'Financial') - ), - array( - 'Project' => array('id' => 2, 'title' => null, 'client_id' => 2, 'show' => '1', 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => '2.2', 'industry_id' => 2.2, 'modified' => '2007-11-26 14:48:36', 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 2, 'name' => 'Awareness Campaign'), - 'Industry' => array('id' => 2, 'name' => 'Education'), - ) - ); - $xml =& new Xml($input, array('format' => 'tags')); - $node =& $xml->children[0]->children[0]; - - $nextSibling =& $node->nextSibling(); - $this->assertEqual($nextSibling, $xml->children[0]->children[1]); - - $nextSibling2 =& $nextSibling->nextSibling(); - $this->assertEqual($nextSibling2, $xml->children[0]->children[2]); - - $noFriends =& $xml->children[0]->children[12]; - $this->assertNull($noFriends->nextSibling()); - } - -/** - * testPreviousSibling - * - * @access public - * @return void - */ - function testPreviousSibling() { - $input = array( - array( - 'Project' => array('id' => 1, 'title' => null, 'client_id' => 1, 'show' => '1', 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => '1.89', 'industry_id' => '1.56', 'modified' => null, 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 1, 'name' => 'Touch Screen Kiosk'), - 'Industry' => array('id' => 1, 'name' => 'Financial') - ), - array( - 'Project' => array('id' => 2, 'title' => null, 'client_id' => 2, 'show' => '1', 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => '2.2', 'industry_id' => 2.2, 'modified' => '2007-11-26 14:48:36', 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 2, 'name' => 'Awareness Campaign'), - 'Industry' => array('id' => 2, 'name' => 'Education'), - ) - ); - $xml =& new Xml($input, array('format' => 'tags')); - $node =& $xml->children[0]->children[1]; - - $prevSibling =& $node->previousSibling(); - $this->assertEqual($prevSibling, $xml->children[0]->children[0]); - - $this->assertNull($prevSibling->previousSibling()); - } - -/** - * testAddAndRemoveAttributes - * - * @access public - * @return void - */ - function testAddAndRemoveAttributes() { - $node =& new XmlElement('myElement', 'superValue'); - $this->assertTrue(empty($node->attributes)); - - $attrs = array( - 'id' => 'test', - 'show' => 1, - 'is_spotlight' => 1, - ); - $node->addAttribute($attrs); - $this->assertEqual($node->attributes, $attrs); - - $node =& new XmlElement('myElement', 'superValue'); - $node->addAttribute('test', 'value'); - $this->assertTrue(isset($node->attributes['test'])); - - $node =& new XmlElement('myElement', 'superValue'); - $obj =& new StdClass(); - $obj->class = 'info'; - $obj->id = 'primaryInfoBox'; - $node->addAttribute($obj); - $expected = array( - 'class' => 'info', - 'id' => 'primaryInfoBox', - ); - $this->assertEqual($node->attributes, $expected); - - $result = $node->removeAttribute('class'); - $this->assertTrue($result); - $this->assertFalse(isset($node->attributes['class'])); - - $result = $node->removeAttribute('missing'); - $this->assertFalse($result); - } - - /** - * Tests that XML documents with non-standard spacing (i.e. leading whitespace, whole document - * on one line) still parse properly. - * - * @return void - */ - function testParsingWithNonStandardWhitespace() { - $raw = '<?xml version="1.0" encoding="ISO-8859-1" ?><prices><price>1.0</price></prices>'; - $array = array('Prices' => array('price' => 1.0)); - - $xml = new TestXml($raw); - $this->assertEqual($xml->toArray(), $array); - $this->assertEqual($xml->getHeader(), 'xml version="1.0" encoding="ISO-8859-1"'); - - $xml = new TestXml(' ' . $raw); - $this->assertEqual($xml->toArray(), $array); - $this->assertEqual($xml->getHeader(), 'xml version="1.0" encoding="ISO-8859-1"'); - - $xml = new TestXml("\n" . $raw); - $this->assertEqual($xml->toArray(), $array); - $this->assertEqual($xml->getHeader(), 'xml version="1.0" encoding="ISO-8859-1"'); - } - - /* Not implemented yet */ - /* function testChildFilter() { - $input = array( - array( - 'Project' => array('id' => 1, 'title' => null, 'client_id' => 1, 'show' => 1, 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => 1, 'industry_id' => 1, 'modified' => null, 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 1, 'name' => 'Touch Screen Kiosk'), - 'Industry' => array('id' => 1, 'name' => 'Financial'), - 'BusinessSolution' => array(array('id' => 6, 'name' => 'Convert Sales')), - 'MediaType' => array( - array('id' => 15, 'name' => 'Print'), - array('id' => 7, 'name' => 'Web Demo'), - array('id' => 6, 'name' => 'CD-ROM') - ) - ), - array( - 'Project' => array('id' => 2, 'title' => null, 'client_id' => 2, 'show' => 1, 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => 2, 'industry_id' => 2, 'modified' => '2007-11-26 14:48:36', 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 2, 'name' => 'Awareness Campaign'), - 'Industry' => array('id' => 2, 'name' => 'Education'), - 'BusinessSolution' => array( - array('id' => 4, 'name' => 'Build Relationship'), - array('id' => 6, 'name' => 'Convert Sales') - ), - 'MediaType' => array( - array('id' => 17, 'name' => 'Web'), - array('id' => 6, 'name' => 'CD-ROM') - ) - ) - ); - - $xml = new Xml($input, array('format' => 'tags', 'tags' => array( - 'MediaType' => array('value' => 'id', 'children' => false), - 'JobType' => array('children' => array()), - 'Industry' => array('children' => array('name')), - 'show' => false - ))); - - $result = $xml->toString(array('header' => false, 'cdata' => false)); - $expected = '<project><id>1</id><title /><client_id>1</client_id><is_spotlight /><style_id>0</style_id><job_type_id>1</job_type_id><industry_id>1</industry_id><modified /><created /><style><id /><name /></style><job_type><id>1</id><name>Touch Screen Kiosk</name></job_type><industry><name>Financial</name></industry><business_solution><id>6</id><name>Convert Sales</name></business_solution><media_type>15</media_type><media_type>7</media_type><media_type>6</media_type></project><project><id>2</id><title /><client_id>2</client_id><is_spotlight /><style_id>0</style_id><job_type_id>2</job_type_id><industry_id>2</industry_id><modified>2007-11-26 14:48:36</modified><created /><style><id /><name /></style><job_type><id>2</id><name>Awareness Campaign</name></job_type><industry><name>Education</name></industry><business_solution><id>4</id><name>Build Relationship</name></business_solution><business_solution><id>6</id><name>Convert Sales</name></business_solution><media_type>17</media_type><media_type>6</media_type></project>'; - $this->assertEqual($expected, $result); - } */ - - /* Broken due to a Set class issue */ - /* function testMixedArray() { - $input = array('OptionGroup' => array( - array('name' => 'OptA', 'id' => 12, 'OptA 1', 'OptA 2', 'OptA 3', 'OptA 4', 'OptA 5', 'OptA 6'), - array('name' => 'OptB', 'id' => 12, 'OptB 1', 'OptB 2', 'OptB 3', 'OptB 4', 'OptB 5', 'OptB 6') - )); - $expected = '<option_group><name>OptA</name><id>12</id><option_group>OptA 1</option_group><option_group>OptA 2</option_group><option_group>OptA 3</option_group><option_group>OptA 4</option_group><option_group>OptA 5</option_group><option_group>OptA 6</option_group></option_group><option_group><name>OptB</name><id>12</id><option_group>OptB 1</option_group><option_group>OptB 2</option_group><option_group>OptB 3</option_group><option_group>OptB 4</option_group><option_group>OptB 5</option_group><option_group>OptB 6</option_group></option_group>'; - $xml = new Xml($input, array('format' => 'tags')); - $result = $xml->toString(array('header' => false, 'cdata' => false)); - $this->assertEqual($expected, $result); - } */ - - /* function testMixedNestedArray() { - $input = array( - 'OptionA' => array( - 'name' => 'OptA', - 'id' => 12, - 'opt' => array('OptA 1', 'OptA 2', 'OptA 3', 'OptA 4', 'OptA 5', 'OptA 6') - ), - 'OptionB' => array( - 'name' => 'OptB', - 'id' => 12, - 'opt' => array('OptB 1', 'OptB 2', 'OptB 3', 'OptB 4', 'OptB 5', 'OptB 6') - ) - ); - $expected = '<option_a><name>OptA</name><id>12</id><opt>OptA 1</opt><opt>OptA 2</opt><opt>OptA 3</opt><opt>OptA 4</opt><opt>OptA 5</opt><opt>OptA 6</opt></option_a><option_b><name>OptB</name><id>12</id><opt>OptB 1</opt><opt>OptB 2</opt><opt>OptB 3</opt><opt>OptB 4</opt><opt>OptB 5</opt><opt>OptB 6</opt></option_b>'; - $xml = new Xml($input, array('format' => 'tags')); - $result = $xml->toString(array('header' => false, 'cdata' => false)); - $this->assertEqual($expected, $result); - } */ - - /* function testMixedArrayAttributes() { - $input = array('OptionGroup' => array( - array( - 'name' => 'OptA', - 'id' => 12, - array('opt' => 'OptA 1'), - array('opt' => 'OptA 2'), - array('opt' => 'OptA 3'), - array('opt' => 'OptA 4'), - array('opt' => 'OptA 5'), - array('opt' => 'OptA 6') - ), - array( - 'name' => 'OptB', - 'id' => 12, - array('opt' => 'OptB 1'), - array('opt' => 'OptB 2'), - array('opt' => 'OptB 3'), - array('opt' => 'OptB 4'), - array('opt' => 'OptB 5'), - array('opt' => 'OptB 6') - ) - )); - $expected = '<option_group name="OptA" id="12"><opt>OptA 1</opt><opt>OptA 2</opt><opt>OptA 3</opt><opt>OptA 4</opt><opt>OptA 5</opt><opt>OptA 6</opt></option_group><option_group name="OptB" id="12"><opt>OptB 1</opt><opt>OptB 2</opt><opt>OptB 3</opt><opt>OptB 4</opt><opt>OptB 5</opt><opt>OptB 6</opt></option_group>'; - - $options = array('tags' => array('option_group' => array('attributes' => array('id', 'name')))); - $xml = new Xml($input, $options); - $result = $xml->toString(false); - - $this->assertEqual($expected, $result); - } */ - - /* Not implemented yet */ - /* function testTagMap() { - $input = array( - array( - 'Project' => array('id' => 1, 'title' => null, 'show' => 1, 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => 1, 'industry_id' => 1, 'modified' => null, 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 1, 'name' => 'Touch Screen Kiosk'), - 'Industry' => array('id' => 1, 'name' => 'Financial') - ), - array( - 'Project' => array('id' => 2, 'title' => null, 'show' => 1, 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => 2, 'industry_id' => 2, 'modified' => '2007-11-26 14:48:36', 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 2, 'name' => 'Awareness Campaign'), - 'Industry' => array('id' => 2, 'name' => 'Education'), - ) - ); - $expected = '<project id="1"><title /><show>1</show><is_spotlight /><style_id>0</style_id><job_type_id>1</job_type_id><industry_id>1</industry_id><modified /><created /><style id=""><name /></style><jobtype id="1">Touch Screen Kiosk</jobtype><industry id="1"><name>Financial</name></industry></project><project id="2"><title /><show>1</show><is_spotlight /><style_id>0</style_id><job_type_id>2</job_type_id><industry_id>2</industry_id><modified>2007-11-26 14:48:36</modified><created /><style id=""><name /></style><jobtype id="2">Awareness Campaign</jobtype><industry id="2"><name>Education</name></industry></project>'; - - $xml = new Xml($input, array('tags' => array( - 'Project' => array('attributes' => array('id')), - 'style' => array('attributes' => array('id')), - 'JobType' => array('name' => 'jobtype', 'attributes' => array('id'), 'value' => 'name'), - 'Industry' => array('attributes' => array('id')) - ))); - $result = $xml->toString(array('header' => false, 'cdata' => false)); - $this->assertEqual($expected, $result); - } */ - -/** - * testAllCData method - * - * @access public - * @return void - */ - function testAllCData() { - $input = array( - array( - 'Project' => array('id' => 1, 'title' => null, 'client_id' => 1, 'show' => '1', 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => '1.89', 'industry_id' => '1.56', 'modified' => null, 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 1, 'name' => 'Touch Screen Kiosk'), - 'Industry' => array('id' => 1, 'name' => 'Financial') - ), - array( - 'Project' => array('id' => 2, 'title' => null, 'client_id' => 2, 'show' => '1', 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => '2.2', 'industry_id' => 2.2, 'modified' => '2007-11-26 14:48:36', 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 2, 'name' => 'Awareness Campaign'), - 'Industry' => array('id' => 2, 'name' => 'Education'), - ) - ); - $expected = '<project><id>1</id><title /><client_id>1</client_id><show>1</show><is_spotlight /><style_id>0</style_id><job_type_id>1.89</job_type_id><industry_id>1.56</industry_id><modified /><created /><style><id /><name /></style><job_type><id>1</id><name><![CDATA[Touch Screen Kiosk]]></name></job_type><industry><id>1</id><name><![CDATA[Financial]]></name></industry></project><project><id>2</id><title /><client_id>2</client_id><show>1</show><is_spotlight /><style_id>0</style_id><job_type_id>2.2</job_type_id><industry_id>2.2</industry_id><modified><![CDATA[2007-11-26 14:48:36]]></modified><created /><style><id /><name /></style><job_type><id>2</id><name><![CDATA[Awareness Campaign]]></name></job_type><industry><id>2</id><name><![CDATA[Education]]></name></industry></project>'; - $xml = new Xml($input, array('format' => 'tags')); - $result = $xml->toString(array('header' => false, 'cdata' => true)); - $this->assertEqual($expected, $result); - } - /* PHP-native Unicode support pending */ - /* function testConvertEntities() { - $input = array('project' => 'écît'); - $xml = new Xml($input); - - $result = $xml->toString(array('header' => false, 'cdata' => false, 'convertEntities' => true)); - $expected = '<project>écît</project>'; - $this->assertEqual($result, $expected); - } */ - -/** - * testWhitespace method - * - * @access public - * @return void - */ - function testWhitespace() { - $input = array( - array( - 'Project' => array('id' => 1, 'title' => null, 'client_id' => 1, 'show' => 1, 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => 1, 'industry_id' => 1, 'modified' => null, 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 1, 'name' => 'Touch Screen Kiosk'), - 'Industry' => array('id' => 1, 'name' => 'Financial') - ), - array( - 'Project' => array('id' => 2, 'title' => null, 'client_id' => 2, 'show' => 1, 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => 2, 'industry_id' => 2, 'modified' => '2007-11-26 14:48:36', 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 2, 'name' => 'Awareness Campaign'), - 'Industry' => array('id' => 2, 'name' => 'Education'), - ) - ); - $expected = "\n\t<project>\n\t\t<id>\n\t\t\t1\n\t\t</id>\n\t\t<title />\n\t\t<client_id>\n\t\t\t1\n\t\t</client_id>\n\t\t<show>\n\t\t\t1\n\t\t</show>\n\t\t<is_spotlight />\n\t\t<style_id>\n\t\t\t0\n\t\t</style_id>\n\t\t<job_type_id>\n\t\t\t1\n\t\t</job_type_id>\n\t\t<industry_id>\n\t\t\t1\n\t\t</industry_id>\n\t\t<modified />\n\t\t<created />\n\t\t<style>\n\t\t\t<id />\n\t\t\t<name />\n\t\t</style>\n\t\t<job_type>\n\t\t\t<id>\n\t\t\t\t1\n\t\t\t</id>\n\t\t\t<name>\n\t\t\t\tTouch Screen Kiosk\n\t\t\t</name>\n\t\t</job_type>\n\t\t<industry>\n\t\t\t<id>\n\t\t\t\t1\n\t\t\t</id>\n\t\t\t<name>\n\t\t\t\tFinancial\n\t\t\t</name>\n\t\t</industry>\n\t</project>\n\t<project>\n\t\t<id>\n\t\t\t2\n\t\t</id>\n\t\t<title />\n\t\t<client_id>\n\t\t\t2\n\t\t</client_id>\n\t\t<show>\n\t\t\t1\n\t\t</show>\n\t\t<is_spotlight />\n\t\t<style_id>\n\t\t\t0\n\t\t</style_id>\n\t\t<job_type_id>\n\t\t\t2\n\t\t</job_type_id>\n\t\t<industry_id>\n\t\t\t2\n\t\t</industry_id>\n\t\t<modified>\n\t\t\t2007-11-26 14:48:36\n\t\t</modified>\n\t\t<created />\n\t\t<style>\n\t\t\t<id />\n\t\t\t<name />\n\t\t</style>\n\t\t<job_type>\n\t\t\t<id>\n\t\t\t\t2\n\t\t\t</id>\n\t\t\t<name>\n\t\t\t\tAwareness Campaign\n\t\t\t</name>\n\t\t</job_type>\n\t\t<industry>\n\t\t\t<id>\n\t\t\t\t2\n\t\t\t</id>\n\t\t\t<name>\n\t\t\t\tEducation\n\t\t\t</name>\n\t\t</industry>\n\t</project>\n"; - - $xml = new Xml($input, array('format' => 'tags')); - $result = $xml->toString(array('header' => false, 'cdata' => false, 'whitespace' => true)); - $this->assertEqual($expected, $result); - } - -/** - * testSetSerialization method - * - * @access public - * @return void - */ - function testSetSerialization() { - $input = array( - array( - 'Project' => array('id' => 1, 'title' => null, 'client_id' => 1, 'show' => 1, 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => 1, 'industry_id' => 1, 'modified' => null, 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 1, 'name' => 'Touch Screen Kiosk'), - 'Industry' => array('id' => 1, 'name' => 'Financial') - ), - array( - 'Project' => array('id' => 2, 'title' => null, 'client_id' => 2, 'show' => 1, 'is_spotlight' => null, 'style_id' => 0, 'job_type_id' => 2, 'industry_id' => 2, 'modified' => '2007-11-26 14:48:36', 'created' => null), - 'Style' => array('id' => null, 'name' => null), - 'JobType' => array('id' => 2, 'name' => 'Awareness Campaign'), - 'Industry' => array('id' => 2, 'name' => 'Education'), - ) - ); - $expected = '<project><id>1</id><title /><client_id>1</client_id><show>1</show><is_spotlight /><style_id>0</style_id><job_type_id>1</job_type_id><industry_id>1</industry_id><modified /><created /><style><id /><name /></style><job_type><id>1</id><name>Touch Screen Kiosk</name></job_type><industry><id>1</id><name>Financial</name></industry></project><project><id>2</id><title /><client_id>2</client_id><show>1</show><is_spotlight /><style_id>0</style_id><job_type_id>2</job_type_id><industry_id>2</industry_id><modified>2007-11-26 14:48:36</modified><created /><style><id /><name /></style><job_type><id>2</id><name>Awareness Campaign</name></job_type><industry><id>2</id><name>Education</name></industry></project>'; - - $xml = new Xml(Set::map($input), array('format' => 'tags')); - $result = $xml->toString(array('header' => false, 'cdata' => false)); - $this->assertEqual($expected, $result); - } - -/** - * ensure that normalize does not add _name_ elements that come from Set::map sometimes. - * - * @return void - */ - function testNormalizeNotAdding_name_Element() { - $input = array( - 'output' => array( - 'Vouchers' => array( - array('Voucher' => array('id' => 1)), - array('Voucher' => array('id' => 2)), - ), - ) - ); - $xml = new Xml($input, array('attributes' => false, 'format' => 'tags')); - $this->assertFalse(isset($xml->children[0]->children[0]->children[1]), 'Too many children %s'); - $this->assertEqual($xml->children[0]->children[0]->children[0]->name, 'voucher'); - } -/** - * testSimpleParsing method - * - * @access public - * @return void - */ - function testSimpleParsing() { - $source = '<response><hello><![CDATA[happy world]]></hello><goodbye><![CDATA[cruel world]]></goodbye></response>'; - $xml = new Xml($source); - $result = $xml->toString(); - $this->assertEqual($source, $result); - } - -/** - * test that elements with empty tag values do not collapse and corrupt data structures - * - * @access public - * @return void - */ - function testElementCollapsing() { - $xmlDataThatFails = '<resultpackage> - <result qid="46b1c46ed6208"><![CDATA[46b1c46ed3af9]]></result> - <result qid="46b1c46ed332a"><![CDATA[]]></result> - <result qid="46b1c46ed90e6"><![CDATA[46b1c46ed69d8]]></result> - <result qid="46b1c46ed71a7"><![CDATA[46b1c46ed5a38]]></result> - <result qid="46b1c46ed8146"><![CDATA[46b1c46ed98b6]]></result> - <result qid="46b1c46ed7978"><![CDATA[]]></result> - <result qid="46b1c46ed4a98"><![CDATA[]]></result> - <result qid="46b1c46ed42c8"><![CDATA[]]></result> - <result qid="46b1c46ed5268"><![CDATA[46b1c46ed8917]]></result> - </resultpackage>'; - - $Xml = new Xml(); - $Xml->load('<?xml version="1.0" encoding="UTF-8" ?>' . $xmlDataThatFails); - $result = $Xml->toArray(false); - - $this->assertTrue(is_array($result)); - $expected = array( - 'resultpackage' => array( - 'result' => array( - 0 => array( - 'value' => '46b1c46ed3af9', - 'qid' => '46b1c46ed6208'), - 1 => array( - 'qid' => '46b1c46ed332a'), - 2 => array( - 'value' => '46b1c46ed69d8', - 'qid' => '46b1c46ed90e6'), - 3 => array( - 'value' => '46b1c46ed5a38', - 'qid' => '46b1c46ed71a7'), - 4 => array( - 'value' => '46b1c46ed98b6', - 'qid' => '46b1c46ed8146'), - 5 => array( - 'qid' => '46b1c46ed7978'), - 6 => array( - 'qid' => '46b1c46ed4a98'), - 7 => array( - 'qid' => '46b1c46ed42c8'), - 8 => array( - 'value' => '46b1c46ed8917', - 'qid' => '46b1c46ed5268'), - ) - )); - $this->assertEqual( - count($result['resultpackage']['result']), count($expected['resultpackage']['result']), - 'Incorrect array length %s'); - - $this->assertFalse( - isset($result['resultpackage']['result'][0][0]['qid']), 'Nested array exists, data is corrupt. %s'); - - $this->assertEqual($result, $expected); - } - -/** - * test that empty values do not casefold collapse - * - * @see http://code.cakephp.org/tickets/view/8 - * @return void - */ - function testCaseFoldingWithEmptyValues() { - $filledValue = '<method name="set_user_settings"> - <title>update user information - 1 - - 1 - varchar(45) - - '; - $xml =& new XML($filledValue); - $expected = array( - 'Method' => array( - 'name' => 'set_user_settings', - 'title' => 'update user information', - 'user' => '1', - 'User' => array( + $xml = array( + 'tags' => array( + 'tag' => array( 'id' => 1, - 'name' => 'varchar(45)', - ), + '@' => 'defect' + ) ) ); - $result = $xml->toArray(); - $this->assertEqual($result, $expected); + $obj = Xml::fromArray($xml, 'attributes'); + $xmlText = '<' . '?xml version="1.0" encoding="UTF-8"?>defect'; + $this->assertEqual(str_replace(array("\r", "\n"), '', $obj->asXML()), $xmlText); + } - $emptyValue =' - update user information - - - 1 - varchar(45) - - '; - - $xml =& new XML($emptyValue); - $expected = array( - 'Method' => array( - 'name' => 'set_user_settings', - 'title' => 'update user information', - 'user' => array(), - 'User' => array( - 'id' => 1, - 'name' => 'varchar(45)', - ), - ) +/** + * data provider for fromArray() failures + * + * @return array + */ + public static function invalidArrayDataProvider() { + return array( + array(''), + array(null), + array(false), + array(array()), + array(array('numeric key as root')), + array(array('item1' => '', 'item2' => '')), + array(array('items' => array('item1', 'item2'))), + array(array( + 'tags' => array( + 'tag' => array( + array( + array( + 'string' + ) + ) + ) + ) + )), + array(array( + 'tags' => array( + '@tag' => array( + array( + '@id' => '1', + 'name' => 'defect' + ), + array( + '@id' => '2', + 'name' => 'enhancement' + ) + ) + ) + )), + array(new DateTime()) ); - $result = $xml->toArray(); - $this->assertEqual($result, $expected); - } -/** - * testMixedParsing method - * - * @access public - * @return void - */ - function testMixedParsing() { - $source = ''; - $xml = new Xml($source); - $result = $xml->toString(); - $this->assertEqual($source, $result); } /** - * testComplexParsing method + * testFromArrayFail method * - * @access public - * @return void + * @dataProvider invalidArrayDataProvider + * @expectedException Exception */ - function testComplexParsing() { - $source = '1<client_id>1</client_id><show>1</show><is_spotlight /><style_id>0</style_id><job_type_id>1</job_type_id><industry_id>1</industry_id><modified /><created /><style><id /><name /></style><job_type><id>1</id><name>Touch Screen Kiosk</name></job_type><industry><id>1</id><name>Financial</name></industry></project><project><id>2</id><title /><client_id>2</client_id><show>1</show><is_spotlight /><style_id>0</style_id><job_type_id>2</job_type_id><industry_id>2</industry_id><modified>2007-11-26 14:48:36</modified><created /><style><id /><name /></style><job_type><id>2</id><name>Awareness Campaign</name></job_type><industry><id>2</id><name>Education</name></industry></project></projects>'; - $xml = new Xml($source); - $result = $xml->toString(array('cdata' => false)); - $this->assertEqual($source, $result); - } - -/** - * testNamespaceParsing method - * - * @access public - * @return void - */ - function testNamespaceParsing() { - $source = '<a:container xmlns:a="http://example.com/a" xmlns:b="http://example.com/b" xmlns:c="http://example.com/c" xmlns:d="http://example.com/d" xmlns:e="http://example.com/e"><b:rule test=""><c:result>value</c:result></b:rule><d:rule test=""><e:result>value</e:result></d:rule></a:container>'; - $xml = new Xml($source); - - $result = $xml->toString(array('cdata' => false)); - $this->assertEqual($source, $result); - - $children = $xml->children('container'); - $this->assertEqual($children[0]->namespace, 'a'); - - $children = $children[0]->children('rule'); - $this->assertEqual($children[0]->namespace, 'b'); - } - -/** - * testNamespaces method - * - * @access public - * @return void - */ - function testNamespaces() { - $source = '<a:container xmlns:a="http://example.com/a" xmlns:b="http://example.com/b" xmlns:c="http://example.com/c" xmlns:d="http://example.com/d" xmlns:e="http://example.com/e"><b:rule test=""><c:result>value</c:result></b:rule><d:rule test=""><e:result>value</e:result></d:rule></a:container>'; - $xml = new Xml($source); - - $expects = '<a:container xmlns:a="http://example.com/a" xmlns:b="http://example.com/b" xmlns:c="http://example.com/c" xmlns:d="http://example.com/d" xmlns:e="http://example.com/e" xmlns:f="http://example.com/f"><b:rule test=""><c:result>value</c:result></b:rule><d:rule test=""><e:result>value</e:result></d:rule></a:container>'; - - $_xml =& XmlManager::getInstance(); - $xml->addNamespace('f', 'http://example.com/f'); - $result = $xml->toString(array('cdata' => false)); - $this->assertEqual($expects, $result); - } - -/** - * testEscapeCharSerialization method - * - * @access public - * @return void - */ - function testEscapeCharSerialization() { - $xml = new Xml(array('text' => 'JavaScript & DHTML'), array('attributes' => false, 'format' => 'attributes')); - - $result = $xml->toString(false); - $expected = '<std_class text="JavaScript & DHTML" />'; - $this->assertEqual($expected, $result); - } - -/** - * testCompleteEscapeCharSerialization method - * - * @access public - * @return void - */ - function testCompleteEscapeCharSerialization() { - $xml = new Xml(array('text' => '<>&"\''), array('attributes' => false, 'format' => 'attributes')); - - $result = $xml->toString(false); - $expected = '<std_class text="<>&"'" />'; - $this->assertEqual($expected, $result); + public function testFromArrayFail($value) { + Xml::fromArray($value); } /** * testToArray method * - * @access public * @return void */ - function testToArray() { - App::import('Set'); - $string = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?> - <rss version="2.0"> - <channel> - <title>Cake PHP Google Group - http://groups.google.com/group/cake-php - Search this group before posting anything. There are over 20,000 posts and it&#39;s very likely your question was answered before. Visit the IRC channel #cakephp at irc.freenode.net for live chat with users and developers of Cake. If you post, tell us the version of Cake, PHP, and database. - en - - constructng result array when using findall - http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f - i'm using cakephp to construct a logical data model array that will be <br> passed to a flex app. I have the following model association: <br> ServiceDay-&gt;(hasMany)ServiceTi me-&gt;(hasMany)ServiceTimePrice. So what <br> the current output from my findall is something like this example: <br> <p>Array( <br> [0] =&gt; Array( - http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f - bmil...@gmail.com(bpscrugs) - Fri, 28 Dec 2007 00:44:14 UT - - - Re: share views between actions? - http://groups.google.com/group/cake-php/msg/8b350d898707dad8 - Then perhaps you might do us all a favour and refrain from replying to <br> things you do not understand. That goes especially for asinine comments. <br> Indeed. <br> To sum up: <br> No comment. <br> In my day, a simple &quot;RTFM&quot; would suffice. I'll keep in mind to ignore any <br> further responses from you. <br> You (and I) were referring to the *online documentation*, not other - http://groups.google.com/group/cake-php/msg/8b350d898707dad8 - subtropolis.z...@gmail.com(subtropolis zijn) - Fri, 28 Dec 2007 00:45:01 UT - - - '; - $xml = new Xml($string); - $result = $xml->toArray(); - $expected = array('Rss' => array( - 'version' => '2.0', - 'Channel' => array( - 'title' => 'Cake PHP Google Group', - 'link' => 'http://groups.google.com/group/cake-php', - 'description' => 'Search this group before posting anything. There are over 20,000 posts and it's very likely your question was answered before. Visit the IRC channel #cakephp at irc.freenode.net for live chat with users and developers of Cake. If you post, tell us the version of Cake, PHP, and database.', - 'language' => 'en', - 'Item' => array( + public function testToArray() { + $xml = 'name'; + $obj = Xml::build($xml); + $this->assertEqual(Xml::toArray($obj), array('tag' => 'name')); + + $xml = TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'fixtures' . DS . 'sample.xml'; + $obj = Xml::build($xml); + $expected = array( + 'tags' => array( + 'tag' => array( array( - 'title' => 'constructng result array when using findall', - 'link' => 'http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f', - 'description' => "i'm using cakephp to construct a logical data model array that will be
passed to a flex app. I have the following model association:
ServiceDay->(hasMany)ServiceTi me->(hasMany)ServiceTimePrice. So what
the current output from my findall is something like this example:

Array(
[0] => Array(", - 'guid' => array('isPermaLink' => 'true', 'value' => 'http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f'), - 'author' => 'bmil...@gmail.com(bpscrugs)', - 'pubDate' => 'Fri, 28 Dec 2007 00:44:14 UT', + '@id' => '1', + 'name' => 'defect' ), array( - 'title' => 'Re: share views between actions?', - 'link' => 'http://groups.google.com/group/cake-php/msg/8b350d898707dad8', - 'description' => 'Then perhaps you might do us all a favour and refrain from replying to
things you do not understand. That goes especially for asinine comments.
Indeed.
To sum up:
No comment.
In my day, a simple "RTFM" would suffice. I\'ll keep in mind to ignore any
further responses from you.
You (and I) were referring to the *online documentation*, not other', - 'guid' => array('isPermaLink' => 'true', 'value' => 'http://groups.google.com/group/cake-php/msg/8b350d898707dad8'), - 'author' => 'subtropolis.z...@gmail.com(subtropolis zijn)', - 'pubDate' => 'Fri, 28 Dec 2007 00:45:01 UT' - ) - ) - ) - )); - $this->assertEqual($result, $expected); - - $string =''; - $xml = new Xml($string); - $result = $xml->toArray(); - $expected = array('Data' => array('Post' => array('title' => 'Title of this post', 'description' => 'cool'))); - $this->assertEqual($result, $expected); - - $xml = new Xml('An example of a correctly reversed XMLNode'); - $result = Set::reverse($xml); - $expected = array( - 'Example' => array( - 'Item' => array( - 'title' => 'An example of a correctly reversed XMLNode', - 'desc' => array(), - ) - ) - ); - $this->assertIdentical($result, $expected); - - $xml = new Xml('title1title2'); - $result = $xml->toArray(); - $expected = array( - 'Example' => array( - 'Item' => array( - 'attr' => '123', - 'Titles' => array( - 'Title' => array('title1', 'title2') + '@id' => '2', + 'name' => 'enhancement' ) ) ) ); - $this->assertIdentical($result, $expected); + $this->assertEqual(Xml::toArray($obj), $expected); - $xml = new Xml('listtextforitems'); - $result = $xml->toArray(); - $expected = array( - 'Example' => array( - 'attr' => 'ex_attr', - 'Item' => array( - 'attr' => '123', - 'titles' => 'list', - 'value' => 'textforitems' - ) - ) - ); - $this->assertIdentical($result, $expected); - - $xml = new Xml('listtextforitems'); - $example = $xml->child('example'); - $item = $example->child('item'); - $result = $item->toArray(); - - $expected = array( - 'attr' => '123', - 'titles' => 'list', - 'value' => 'textforitems' - ); - $this->assertIdentical($result, $expected); - - $string = ' - - - Cake PHP Google Group - http://groups.google.com/group/cake-php - Search this group before posting anything. There are over 20,000 posts and it&#39;s very likely your question was answered before. Visit the IRC channel #cakephp at irc.freenode.net for live chat with users and developers of Cake. If you post, tell us the version of Cake, PHP, and database. - en - - constructng result array when using findall - http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f - i'm using cakephp to construct a logical data model array that will be <br> passed to a flex app. I have the following model association: <br> ServiceDay-&gt;(hasMany)ServiceTi me-&gt;(hasMany)ServiceTimePrice. So what <br> the current output from my findall is something like this example: <br> <p>Array( <br> [0] =&gt; Array( - cakephp - - - http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f - bmil...@gmail.com(bpscrugs) - Fri, 28 Dec 2007 00:44:14 UT - - - Re: share views between actions? - http://groups.google.com/group/cake-php/msg/8b350d898707dad8 - Then perhaps you might do us all a favour and refrain from replying to <br> things you do not understand. That goes especially for asinine comments. <br> Indeed. <br> To sum up: <br> No comment. <br> In my day, a simple &quot;RTFM&quot; would suffice. I'll keep in mind to ignore any <br> further responses from you. <br> You (and I) were referring to the *online documentation*, not other - cakephp - - - http://groups.google.com/group/cake-php/msg/8b350d898707dad8 - subtropolis.z...@gmail.com(subtropolis zijn) - Fri, 28 Dec 2007 00:45:01 UT - - - '; - - $xml = new Xml($string); - $result = $xml->toArray(); - - $expected = array('Rss' => array( - 'version' => '2.0', - 'Channel' => array( - 'title' => 'Cake PHP Google Group', - 'link' => 'http://groups.google.com/group/cake-php', - 'description' => 'Search this group before posting anything. There are over 20,000 posts and it's very likely your question was answered before. Visit the IRC channel #cakephp at irc.freenode.net for live chat with users and developers of Cake. If you post, tell us the version of Cake, PHP, and database.', - 'language' => 'en', - 'Item' => array( + $array = array( + 'tags' => array( + 'tag' => array( array( - 'title' => 'constructng result array when using findall', - 'link' => 'http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f', - 'description' => "i'm using cakephp to construct a logical data model array that will be
passed to a flex app. I have the following model association:
ServiceDay->(hasMany)ServiceTi me->(hasMany)ServiceTimePrice. So what
the current output from my findall is something like this example:

Array(
[0] => Array(", - 'creator' => 'cakephp', - 'Category' => array('cakephp', 'model'), - 'guid' => array('isPermaLink' => 'true', 'value' => 'http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f'), - 'author' => 'bmil...@gmail.com(bpscrugs)', - 'pubDate' => 'Fri, 28 Dec 2007 00:44:14 UT', + 'id' => '1', + 'name' => 'defect' ), array( - 'title' => 'Re: share views between actions?', - 'link' => 'http://groups.google.com/group/cake-php/msg/8b350d898707dad8', - 'description' => 'Then perhaps you might do us all a favour and refrain from replying to
things you do not understand. That goes especially for asinine comments.
Indeed.
To sum up:
No comment.
In my day, a simple "RTFM" would suffice. I\'ll keep in mind to ignore any
further responses from you.
You (and I) were referring to the *online documentation*, not other', - 'creator' => 'cakephp', - 'Category' => array('cakephp', 'model'), - 'guid' => array('isPermaLink' => 'true', 'value' => 'http://groups.google.com/group/cake-php/msg/8b350d898707dad8'), - 'author' => 'subtropolis.z...@gmail.com(subtropolis zijn)', - 'pubDate' => 'Fri, 28 Dec 2007 00:45:01 UT' + 'id' => '2', + 'name' => 'enhancement' ) ) ) - )); - $this->assertEqual($result, $expected); + ); + $this->assertEqual(Xml::toArray(Xml::fromArray($array, 'tags')), $array); - $text = " - - - 1 - 2 - 3 - 4 - - "; - $xml = new Xml($text); - $result = $xml->toArray(); - - $expected = array('Course' => array( - 'Comps' => array( - 'Comp' => array( - 1, 2, 3, 4 + $expected = array( + 'tags' => array( + 'tag' => array( + array( + '@id' => '1', + '@name' => 'defect' + ), + array( + '@id' => '2', + '@name' => 'enhancement' + ) ) ) - )); + ); + $this->assertEqual(Xml::toArray(Xml::fromArray($array, 'attributes')), $expected); + $this->assertEqual(Xml::toArray(Xml::fromArray($array, array('return' => 'domdocument', 'format' => 'attributes'))), $expected); + $this->assertEqual(Xml::toArray(Xml::fromArray($array)), $array); + $this->assertEqual(Xml::toArray(Xml::fromArray($array, array('return' => 'domdocument'))), $array); - $this->assertEqual($result, $expected); + $array = array( + 'tags' => array( + 'tag' => array( + 'id' => '1', + 'posts' => array( + array('id' => '1'), + array('id' => '2') + ) + ), + 'tagOther' => array( + 'subtag' => array( + 'id' => '1' + ) + ) + ) + ); + $expected = array( + 'tags' => array( + 'tag' => array( + '@id' => '1', + 'posts' => array( + array('@id' => '1'), + array('@id' => '2') + ) + ), + 'tagOther' => array( + 'subtag' => array( + '@id' => '1' + ) + ) + ) + ); + $this->assertEqual(Xml::toArray(Xml::fromArray($array, 'attributes')), $expected); + $this->assertEqual(Xml::toArray(Xml::fromArray($array, array('format' => 'attributes', 'return' => 'domdocument'))), $expected); - $text = ' - - - xri://$xrds*simple - 2008-04-13T07:34:58Z - - http://oauth.net/core/1.0/endpoint/authorize - http://oauth.net/core/1.0/parameters/auth-header - http://oauth.net/core/1.0/parameters/uri-query - https://ma.gnolia.com/oauth/authorize - http://ma.gnolia.com/oauth/authorize - - - - xri://$xrds*simple - - http://oauth.net/discovery/1.0 - #oauth - - - '; + $xml = ''; + $xml .= 'defect'; + $xml .= ''; + $obj = Xml::build($xml); - $xml = new Xml($text); - $result = $xml->toArray(); + $expected = array( + 'root' => array( + 'tag' => array( + '@id' => 1, + '@' => 'defect' + ) + ) + ); + $this->assertEqual(Xml::toArray($obj), $expected); - $expected = array('XRDS' => array( - 'xmlns' => 'xri://$xrds', - 'XRD' => array( - array( - 'xml:id' => 'oauth', - 'xmlns' => 'xri://$XRD*($v*2.0)', - 'version' => '2.0', - 'Type' => 'xri://$xrds*simple', - 'Expires' => '2008-04-13T07:34:58Z', - 'Service' => array( - 'Type' => array( - 'http://oauth.net/core/1.0/endpoint/authorize', - 'http://oauth.net/core/1.0/parameters/auth-header', - 'http://oauth.net/core/1.0/parameters/uri-query' + $xml = ''; + $xml .= '
ApplesBananas
'; + $xml .= 'CakePHPMIT
'; + $xml .= 'The book is on the table.
'; + $xml .= '
'; + $obj = Xml::build($xml); + + $expected = array( + 'root' => array( + 'table' => array( + array('tr' => array('td' => array('Apples', 'Bananas'))), + array('name' => 'CakePHP', 'license' => 'MIT'), + 'The book is on the table.' + ) + ) + ); + $this->assertEqual(Xml::toArray($obj), $expected); + + $xml = ''; + $xml .= 'defect'; + $xml .= '1'; + $xml .= ''; + $obj = Xml::build($xml); + + $expected = array( + 'root' => array( + 'tag' => 'defect', + 'cake:bug' => 1 + ) + ); + $this->assertEqual(Xml::toArray($obj), $expected); + } + +/** + * testRss + * + * @return void + */ + public function testRss() { + $rss = file_get_contents(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'fixtures' . DS . 'rss.xml'); + $rssAsArray = Xml::toArray(Xml::build($rss)); + $this->assertEqual($rssAsArray['rss']['@version'], '2.0'); + $this->assertEqual(count($rssAsArray['rss']['channel']['item']), 2); + + $atomLink = array('@href' => 'http://bakery.cakephp.org/articles/rss', '@rel' => 'self', '@type' => 'application/rss+xml'); + $this->assertEqual($rssAsArray['rss']['channel']['atom:link'], $atomLink); + $this->assertEqual($rssAsArray['rss']['channel']['link'], 'http://bakery.cakephp.org/'); + + $expected = array( + 'title' => 'Alertpay automated sales via IPN', + 'link' => 'http://bakery.cakephp.org/articles/view/alertpay-automated-sales-via-ipn', + 'description' => 'I\'m going to show you how I implemented a payment module via the Alertpay payment processor.', + 'pubDate' => 'Tue, 31 Aug 2010 01:42:00 -0500', + 'guid' => 'http://bakery.cakephp.org/articles/view/alertpay-automated-sales-via-ipn' + ); + $this->assertIdentical($rssAsArray['rss']['channel']['item'][1], $expected); + + $rss = array( + 'rss' => array( + 'xmlns:atom' => 'http://www.w3.org/2005/Atom', + '@version' => '2.0', + 'channel' => array( + 'atom:link' => array( + '@href' => 'http://bakery.cakephp.org/articles/rss', + '@rel' => 'self', + '@type' => 'application/rss+xml' + ), + 'title' => 'The Bakery: ', + 'link' => 'http://bakery.cakephp.org/', + 'description' => 'Recent Articles at The Bakery.', + 'pubDate' => 'Sun, 12 Sep 2010 04:18:26 -0500', + 'item' => array( + array( + 'title' => 'CakePHP 1.3.4 released', + 'link' => 'http://bakery.cakephp.org/articles/view/cakephp-1-3-4-released' ), - 'URI' => array( - array( - 'value' => 'https://ma.gnolia.com/oauth/authorize', - 'priority' => '10', - ), - array( - 'value' => 'http://ma.gnolia.com/oauth/authorize', - 'priority' => '20' + array( + 'title' => 'Wizard Component 1.2 Tutorial', + 'link' => 'http://bakery.cakephp.org/articles/view/wizard-component-1-2-tutorial' + ) + ) + ) + ) + ); + $rssAsSimpleXML = Xml::fromArray($rss); + $xmlText = '<' . '?xml version="1.0" encoding="UTF-8"?>'; + $xmlText .= ''; + $xmlText .= ''; + $xmlText .= ''; + $xmlText .= 'The Bakery: '; + $xmlText .= 'http://bakery.cakephp.org/'; + $xmlText .= 'Recent Articles at The Bakery.'; + $xmlText .= 'Sun, 12 Sep 2010 04:18:26 -0500'; + $xmlText .= 'CakePHP 1.3.4 releasedhttp://bakery.cakephp.org/articles/view/cakephp-1-3-4-released'; + $xmlText .= 'Wizard Component 1.2 Tutorialhttp://bakery.cakephp.org/articles/view/wizard-component-1-2-tutorial'; + $xmlText .= ''; + $this->assertEqual(str_replace(array("\r", "\n"), '', $rssAsSimpleXML->asXML()), $xmlText); + } + +/** + * testXmlRpc + * + * @return void + */ + public function testXmlRpc() { + $xml = Xml::build('test'); + $expected = array( + 'methodCall' => array( + 'methodName' => 'test', + 'params' => '' + ) + ); + $this->assertIdentical(Xml::toArray($xml), $expected); + + $xml = Xml::build('test12Egypt0-31'); + $expected = array( + 'methodCall' => array( + 'methodName' => 'test', + 'params' => array( + 'param' => array( + 'value' => array( + 'array' => array( + 'data' => array( + 'value' => array( + array('int' => '12'), + array('string' => 'Egypt'), + array('boolean' => '0'), + array('int' => '-31') + ) + ) ) ) ) - ), - array( - 'xmlns' => 'xri://$XRD*($v*2.0)', - 'version' => '2.0', - 'Type' => 'xri://$xrds*simple', - 'Service' => array( - 'priority' => '10', - 'Type' => 'http://oauth.net/discovery/1.0', - 'URI' => '#oauth' + ) + ) + ); + $this->assertIdentical(Xml::toArray($xml), $expected); + + $xmlText = '1testing'; + $xml = Xml::build($xmlText); + $expected = array( + 'methodResponse' => array( + 'params' => array( + 'param' => array( + 'value' => array( + 'array' => array( + 'data' => array( + 'value' => array( + array('int' => '1'), + array('string' => 'testing') + ) + ) + ) + ) ) ) ) - )); - $this->assertEqual($result, $expected); + ); + $this->assertIdentical(Xml::toArray($xml), $expected); - $text = ' - - - - - - - '; - $xml = new Xml($text); - $result = $xml->toArray(); + $xml = Xml::fromArray($expected, 'tags'); + $this->assertEqual(str_replace(array("\r", "\n"), '', $xml->asXML()), $xmlText); + } + +/** + * testSoap + * + * @return void + */ + public function testSoap() { + $xmlRequest = Xml::build(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'fixtures' . DS . 'soap_request.xml'); $expected = array( - 'Root' => array( - 'Child' => array( - array('id' => 1, 'other' => 1), - array('id' => 2, 'other' => 1), - array('id' => 3, 'other' => 1), - array('id' => 4, 'other' => 1), - array('id' => 5, 'other' => 1) + 'Envelope' => array( + '@soap:encodingStyle' => 'http://www.w3.org/2001/12/soap-encoding', + 'soap:Body' => array( + 'm:GetStockPrice' => array( + 'm:StockName' => 'IBM' + ) ) ) ); - $this->assertEqual($result, $expected); + $this->assertEqual(Xml::toArray($xmlRequest), $expected); - $text = '

'; - $xml = new Xml($text); - $result = $xml->toArray(); + $xmlResponse = Xml::build(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'fixtures' . DS . 'soap_response.xml'); $expected = array( - 'Main' => array( - 'First' => array( - array('label' => 'first type node 1'), - array('label' => 'first type node 2') - ), - 'Second' => array('label'=>'second type node') - ) - ); - $this->assertIdentical($result,$expected); - - $text = '
'; - $xml = new Xml($text); - $result = $xml->toArray(); - $expected = array( - 'Main' => array( - 'First' => array( - array('label' => 'first type node 1'), - array('label' => 'first type node 2') - ), - 'Second' => array('label'=>'second type node'), - 'Collection' => array( - 'Fifth' => array('label' => 'fifth type node'), - 'Third' => array( - array('label' => 'third type node 1'), - array('label' => 'third type node 2'), - array('label' => 'third type node 3'), - ), - 'Fourth' => array('label' => 'fourth type node'), + 'Envelope' => array( + '@soap:encodingStyle' => 'http://www.w3.org/2001/12/soap-encoding', + 'soap:Body' => array( + 'm:GetStockPriceResponse' => array( + 'm:Price' => '34.5' + ) ) - ) + ) ); - $this->assertIdentical($result,$expected); + $this->assertEqual(Xml::toArray($xmlResponse), $expected); + + $xml = array( + 'soap:Envelope' => array( + 'xmlns:soap' => 'http://www.w3.org/2001/12/soap-envelope', + '@soap:encodingStyle' => 'http://www.w3.org/2001/12/soap-encoding', + 'soap:Body' => array( + 'xmlns:m' => 'http://www.example.org/stock', + 'm:GetStockPrice' => array( + 'm:StockName' => 'IBM' + ) + ) + ) + ); + $xmlRequest = Xml::fromArray($xml, array('encoding' => null)); + $xmlText = '<' . '?xml version="1.0"?>'; + $xmlText .= ''; + $xmlText .= ''; + $xmlText .= 'IBM'; + $xmlText .= ''; + $this->assertEqual(str_replace(array("\r", "\n"), '', $xmlRequest->asXML()), $xmlText); } /** - * testAppend method + * testNamespace * - * @access public - * @return void + * @retun void */ - function testAppend() { - $parentNode = new XmlNode('ourParentNode'); - $parentNode->append( new XmlNode('ourChildNode')); - $first =& $parentNode->first(); - $this->assertEqual($first->name, 'ourChildNode'); - - $string = 'ourChildNode'; - $parentNode = new XmlNode('ourParentNode'); - $parentNode->append($string); - $last =& $parentNode->last(); - $this->assertEqual($last->name, 'ourChildNode'); - $this->expectError(); - $parentNode->append($parentNode); - } - -/** - * testNamespacing method - * - * @access public - * @return void - */ - function testNamespacing() { - $node = new Xml(''); - $node->addNamespace('cake', 'http://cakephp.org'); - $this->assertEqual($node->toString(), ''); - - $this->assertTrue($node->removeNamespace('cake')); - $this->assertEqual($node->toString(), ''); - - - $node = new Xml(''); - $this->assertTrue($node->removeNamespace('cake')); - $this->assertEqual($node->toString(), ''); - - $node->addNamespace('cake', 'http://cakephp.org'); - $this->assertEqual($node->toString(), ''); - } - -/** - * testCamelize method - * - * @access public - * @return void - */ - function testCamelize() { - $xmlString = 'examples.getStateName' . - '41'; - - $Xml = new Xml($xmlString); + public function testNamespace() { + $xmlResponse = Xml::build('goodbadTag without ns'); $expected = array( - 'methodCall' => array( - 'methodName' => 'examples.getStateName', - 'params' => array( - 'param' => array('value' => array('i4' => 41))))); - $this->assertEqual($expected, $Xml->toArray(false)); + 'root' => array( + 'ns:tag' => array( + '@id' => '1', + 'child' => 'good', + 'otherchild' => 'bad' + ), + 'tag' => 'Tag without ns' + ) + ); + $this->assertEqual(Xml::toArray($xmlResponse), $expected); - $Xml = new Xml($xmlString); + $xmlResponse = Xml::build('1'); $expected = array( - 'MethodCall' => array( - 'methodName' => 'examples.getStateName', - 'Params' => array( - 'Param' => array('Value' => array('i4' => 41))))); - $this->assertEqual($expected, $Xml->toArray()); + 'root' => array( + 'ns:tag' => array( + '@id' => '1' + ), + 'tag' => array( + 'id' => '1' + ) + ) + ); + $this->assertEqual(Xml::toArray($xmlResponse), $expected); + + $xmlResponse = Xml::build('1'); + $expected = array( + 'root' => array( + 'ns:attr' => '1' + ) + ); + $this->assertEqual(Xml::toArray($xmlResponse), $expected); + + $xmlResponse = Xml::build('1'); + $this->assertEqual(Xml::toArray($xmlResponse), $expected); + + $xml = array( + 'root' => array( + 'ns:attr' => array( + 'xmlns:ns' => 'http://cakephp.org', + '@' => 1 + ) + ) + ); + $expected = '<' . '?xml version="1.0" encoding="UTF-8"?>1'; + $xmlResponse = Xml::fromArray($xml); + $this->assertEqual(str_replace(array("\r", "\n"), '', $xmlResponse->asXML()), $expected); + + $xml = array( + 'root' => array( + 'tag' => array( + 'xmlns:pref' => 'http://cakephp.org', + 'pref:item' => array( + 'item 1', + 'item 2' + ) + ) + ) + ); + $expected = '<' . '?xml version="1.0" encoding="UTF-8"?>item 1item 2'; + $xmlResponse = Xml::fromArray($xml); + $this->assertEqual(str_replace(array("\r", "\n"), '', $xmlResponse->asXML()), $expected); + + $xml = array( + 'root' => array( + 'tag' => array( + 'xmlns:' => 'http://cakephp.org' + ) + ) + ); + $expected = '<' . '?xml version="1.0" encoding="UTF-8"?>'; + $xmlResponse = Xml::fromArray($xml); + $this->assertEqual(str_replace(array("\r", "\n"), '', $xmlResponse->asXML()), $expected); + + $xml = array( + 'root' => array( + 'xmlns:' => 'http://cakephp.org' + ) + ); + $expected = '<' . '?xml version="1.0" encoding="UTF-8"?>'; + $xmlResponse = Xml::fromArray($xml); + $this->assertEqual(str_replace(array("\r", "\n"), '', $xmlResponse->asXML()), $expected); + + $xml = array( + 'root' => array( + 'xmlns:ns' => 'http://cakephp.org' + ) + ); + $expected = '<' . '?xml version="1.0" encoding="UTF-8"?>'; + $xmlResponse = Xml::fromArray($xml); + $this->assertEqual(str_replace(array("\r", "\n"), '', $xmlResponse->asXML()), $expected); } /** - * testNumericDataHandling method + * data provider for toArray() failures * - * @access public - * @return void + * @return array */ - function testNumericDataHandling() { - $data = '012345'; - - $node = new Xml(); - $node->load($data); - $node->parse(); - - $result = $node->first(); - $result = $result->children("data"); - - $result = $result[0]->first(); - $this->assertEqual($result->value, '012345'); + public static function invalidToArrayDataProvider() { + return array( + array(new DateTime()), + array(array()) + ); } /** - * test that creating an xml object does not leak memory + * testToArrayFail method + * + * @dataProvider invalidToArrayDataProvider + * @expectedException Exception + */ + public function testToArrayFail($value) { + Xml::toArray($value); + } + +/** + * testWithModel method * * @return void */ - function testMemoryLeakInConstructor() { - if ($this->skipIf(!function_exists('memory_get_usage'), 'Cannot test memory leaks without memory_get_usage')) { - return; - } - $data = 'TEST'; - $start = memory_get_usage(); - for ($i = 0; $i <= 300; $i++) { - $test =& new XML($data); - $test->__destruct(); - unset($test); - } - $end = memory_get_usage(); - $this->assertWithinMargin($start, $end, 3600, 'Memory leaked %s'); + public function testWithModel() { + $this->loadFixtures('User', 'Article'); + + $user = new User(); + $data = $user->read(null, 1); + + $obj = Xml::build(compact('data')); + $expected = '<' . '?xml version="1.0" encoding="UTF-8"?>'; + $expected .= '1mariano5f4dcc3b5aa765d61d8327deb882cf99'; + $expected .= '2007-03-17 01:16:232007-03-17 01:18:31'; + $expected .= '
11First ArticleFirst Article Body'; + $expected .= 'Y2007-03-18 10:39:232007-03-18 10:41:31
'; + $expected .= '
31Third ArticleThird Article Body'; + $expected .= 'Y2007-03-18 10:43:232007-03-18 10:45:31
'; + $expected .= '
'; + $this->assertEqual(str_replace(array("\r", "\n"), '', $obj->asXML()), $expected); } + } diff --git a/cake/tests/fixtures/rss.xml b/cake/tests/fixtures/rss.xml new file mode 100644 index 000000000..172649d40 --- /dev/null +++ b/cake/tests/fixtures/rss.xml @@ -0,0 +1,33 @@ + + + + + The Bakery: + http://bakery.cakephp.org/ + Recent Articles at The Bakery. + en-us + Wed, 01 Sep 2010 12:09:25 -0500 + http://validator.w3.org/feed/docs/rss2.html + CakePHP Bakery + mariano@cricava.com (Mariano Iglesias) + gwoo@cakephp.org (Garrett Woodworth) + + EpisodeCMS + http://bakery.cakephp.org/articles/view/episodecms + EpisodeCMS is CakePHP based content management system. +Features: control panel, events API, module management, multilanguage and translations, themes +http://episodecms.com/ + +Please help me to improve it. Thanks. + Tue, 31 Aug 2010 02:07:02 -0500 + http://bakery.cakephp.org/articles/view/episodecms + + + Alertpay automated sales via IPN + http://bakery.cakephp.org/articles/view/alertpay-automated-sales-via-ipn + I'm going to show you how I implemented a payment module via the Alertpay payment processor. + Tue, 31 Aug 2010 01:42:00 -0500 + http://bakery.cakephp.org/articles/view/alertpay-automated-sales-via-ipn + + + \ No newline at end of file diff --git a/cake/tests/fixtures/sample.xml b/cake/tests/fixtures/sample.xml new file mode 100644 index 000000000..0ab267da0 --- /dev/null +++ b/cake/tests/fixtures/sample.xml @@ -0,0 +1,9 @@ + + + + defect + + + enhancement + + \ No newline at end of file diff --git a/cake/tests/fixtures/soap_request.xml b/cake/tests/fixtures/soap_request.xml new file mode 100644 index 000000000..cd3a238c4 --- /dev/null +++ b/cake/tests/fixtures/soap_request.xml @@ -0,0 +1,12 @@ + + + + + + IBM + + + + \ No newline at end of file diff --git a/cake/tests/fixtures/soap_response.xml b/cake/tests/fixtures/soap_response.xml new file mode 100644 index 000000000..c9e9de538 --- /dev/null +++ b/cake/tests/fixtures/soap_response.xml @@ -0,0 +1,12 @@ + + + + + + 34.5 + + + + \ No newline at end of file