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 . '' . $name. '>';
+ $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 '' . $name . '>';
- }
-
-/**
- * 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 .= '' . $this->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(",
- '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'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->(hasMany)ServiceTi me->(hasMany)ServiceTimePrice. So what <br> the current output from my findall is something like this example: <br> <p>Array( <br> [0] => 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 "RTFM" 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: