Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authormatthieu_ <matthieu_@59fd770c-687e-43c8-a1e3-f5a4ff64c105>2007-08-25 00:27:48 +0400
committermatthieu_ <matthieu_@59fd770c-687e-43c8-a1e3-f5a4ff64c105>2007-08-25 00:27:48 +0400
commitc12bdaa5e95b2f6dba577b3b2c614279f68dc24a (patch)
treebc955fc3dbc61d4cf2bf0612c770d31c3e6a8666 /libs
parent8f7f5857cbe329e88b8104c98be3035f79f7fde4 (diff)
- Translation
- filter to name the columns - API for the modules actions, provider, UserCountry, Visitfrquency, visitinterest, time, - HALF of the api for referers - improved XML export nwo using PEAR xml serializer
Diffstat (limited to 'libs')
-rwxr-xr-xlibs/PEAR.php10
-rw-r--r--libs/XML/Serializer.php1025
-rw-r--r--libs/XML/Unserializer.php856
-rw-r--r--libs/XML/Util.php752
4 files changed, 2638 insertions, 5 deletions
diff --git a/libs/PEAR.php b/libs/PEAR.php
index fc879a0a78..f14d8a06f1 100755
--- a/libs/PEAR.php
+++ b/libs/PEAR.php
@@ -227,7 +227,7 @@ class PEAR
* @return mixed A reference to the variable. If not set it will be
* auto initialised to NULL.
*/
- function &getStaticProperty($class, $var)
+ static function &getStaticProperty($class, $var)
{
static $properties;
if (!isset($properties[$class])) {
@@ -278,7 +278,7 @@ class PEAR
*/
function isError($data, $code = null)
{
- if (is_a($data, 'PEAR_Error')) {
+ if ($data instanceof PEAR_Error) {
if (is_null($code)) {
return true;
} elseif (is_string($code)) {
@@ -521,7 +521,7 @@ class PEAR
* @see PEAR::setErrorHandling
* @since PHP 4.0.5
*/
- function &raiseError($message = null,
+ static function &raiseError($message = null,
$code = null,
$mode = null,
$options = null,
@@ -566,10 +566,10 @@ class PEAR
$ec = 'PEAR_Error';
}
if ($skipmsg) {
- $a = &new $ec($code, $mode, $options, $userinfo);
+ $a = new $ec($code, $mode, $options, $userinfo);
return $a;
} else {
- $a = &new $ec($message, $code, $mode, $options, $userinfo);
+ $a = new $ec($message, $code, $mode, $options, $userinfo);
return $a;
}
}
diff --git a/libs/XML/Serializer.php b/libs/XML/Serializer.php
new file mode 100644
index 0000000000..9b2e9f6cfb
--- /dev/null
+++ b/libs/XML/Serializer.php
@@ -0,0 +1,1025 @@
+<?PHP
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * XML_Serializer
+ *
+ * Creates XML documents from PHP data structures like arrays, objects or scalars.
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * http://www.php.net/license/3_0.txt. If you did not receive a copy of
+ * the PHP License and are unable to obtain it through the web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category XML
+ * @package XML_Serializer
+ * @author Stephan Schmidt <schst@php.net>
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Serializer.php,v 1.47 2005/09/30 13:40:30 schst Exp $
+ * @link http://pear.php.net/package/XML_Serializer
+ * @see XML_Unserializer
+ */
+
+/**
+ * uses PEAR error management
+ */
+require_once 'PEAR.php';
+
+/**
+ * uses XML_Util to create XML tags
+ */
+require_once 'XML/Util.php';
+
+/**
+ * option: string used for indentation
+ *
+ * Possible values:
+ * - any string (default is any string)
+ */
+define('XML_SERIALIZER_OPTION_INDENT', 'indent');
+
+/**
+ * option: string used for linebreaks
+ *
+ * Possible values:
+ * - any string (default is \n)
+ */
+define('XML_SERIALIZER_OPTION_LINEBREAKS', 'linebreak');
+
+/**
+ * option: enable type hints
+ *
+ * Possible values:
+ * - true
+ * - false
+ */
+define('XML_SERIALIZER_OPTION_TYPEHINTS', 'typeHints');
+
+/**
+ * option: add an XML declaration
+ *
+ * Possible values:
+ * - true
+ * - false
+ */
+define('XML_SERIALIZER_OPTION_XML_DECL_ENABLED', 'addDecl');
+
+/**
+ * option: encoding of the document
+ *
+ * Possible values:
+ * - any valid encoding
+ * - null (default)
+ */
+define('XML_SERIALIZER_OPTION_XML_ENCODING', 'encoding');
+
+/**
+ * option: default name for tags
+ *
+ * Possible values:
+ * - any string (XML_Serializer_Tag is default)
+ */
+define('XML_SERIALIZER_OPTION_DEFAULT_TAG', 'defaultTagName');
+
+/**
+ * option: use classname for objects in indexed arrays
+ *
+ * Possible values:
+ * - true (default)
+ * - false
+ */
+define('XML_SERIALIZER_OPTION_CLASSNAME_AS_TAGNAME', 'classAsTagName');
+
+/**
+ * option: attribute where original key is stored
+ *
+ * Possible values:
+ * - any string (default is _originalKey)
+ */
+define('XML_SERIALIZER_OPTION_ATTRIBUTE_KEY', 'keyAttribute');
+
+/**
+ * option: attribute for type (only if typeHints => true)
+ *
+ * Possible values:
+ * - any string (default is _type)
+ */
+define('XML_SERIALIZER_OPTION_ATTRIBUTE_TYPE', 'typeAttribute');
+
+/**
+ * option: attribute for class (only if typeHints => true)
+ *
+ * Possible values:
+ * - any string (default is _class)
+ */
+define('XML_SERIALIZER_OPTION_ATTRIBUTE_CLASS', 'classAttribute');
+
+/**
+ * option: scalar values (strings, ints,..) will be serialized as attribute
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ * - array which sets this option on a per-tag basis
+ */
+define('XML_SERIALIZER_OPTION_SCALAR_AS_ATTRIBUTES', 'scalarAsAttributes');
+
+/**
+ * option: prepend string for attributes
+ *
+ * Possible values:
+ * - any string (default is any string)
+ */
+define('XML_SERIALIZER_OPTION_PREPEND_ATTRIBUTES', 'prependAttributes');
+
+/**
+ * option: indent the attributes, if set to '_auto', it will indent attributes so they all start at the same column
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ */
+define('XML_SERIALIZER_OPTION_INDENT_ATTRIBUTES', 'indentAttributes');
+
+/**
+ * option: use 'simplexml' to use parent name as tagname if transforming an indexed array
+ *
+ * Possible values:
+ * - XML_SERIALIZER_MODE_DEFAULT (default)
+ * - XML_SERIALIZER_MODE_SIMPLEXML
+ */
+define('XML_SERIALIZER_OPTION_MODE', 'mode');
+
+/**
+ * option: add a doctype declaration
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ */
+define('XML_SERIALIZER_OPTION_DOCTYPE_ENABLED', 'addDoctype');
+
+/**
+ * option: supply a string or an array with id and uri ({@see XML_Util::getDoctypeDeclaration()}
+ *
+ * Possible values:
+ * - string
+ * - array
+ */
+define('XML_SERIALIZER_OPTION_DOCTYPE', 'doctype');
+
+/**
+ * option: name of the root tag
+ *
+ * Possible values:
+ * - string
+ * - null (default)
+ */
+define('XML_SERIALIZER_OPTION_ROOT_NAME', 'rootName');
+
+/**
+ * option: attributes of the root tag
+ *
+ * Possible values:
+ * - array
+ */
+define('XML_SERIALIZER_OPTION_ROOT_ATTRIBS', 'rootAttributes');
+
+/**
+ * option: all values in this key will be treated as attributes
+ *
+ * Possible values:
+ * - array
+ */
+define('XML_SERIALIZER_OPTION_ATTRIBUTES_KEY', 'attributesArray');
+
+/**
+ * option: this value will be used directly as content, instead of creating a new tag, may only be used in conjuction with attributesArray
+ *
+ * Possible values:
+ * - string
+ * - null (default)
+ */
+define('XML_SERIALIZER_OPTION_CONTENT_KEY', 'contentName');
+
+/**
+ * option: this value will be used in a comment, instead of creating a new tag
+ *
+ * Possible values:
+ * - string
+ * - null (default)
+ */
+define('XML_SERIALIZER_OPTION_COMMENT_KEY', 'commentName');
+
+/**
+ * option: tag names that will be changed
+ *
+ * Possible values:
+ * - array
+ */
+define('XML_SERIALIZER_OPTION_TAGMAP', 'tagMap');
+
+/**
+ * option: function that will be applied before serializing
+ *
+ * Possible values:
+ * - any valid PHP callback
+ */
+define('XML_SERIALIZER_OPTION_ENCODE_FUNC', 'encodeFunction');
+
+/**
+ * option: function that will be applied before serializing
+ *
+ * Possible values:
+ * - string
+ * - null (default)
+ */
+define('XML_SERIALIZER_OPTION_NAMESPACE', 'namespace');
+
+/**
+ * option: type of entities to replace
+ *
+ * Possible values:
+ * - XML_SERIALIZER_ENTITIES_NONE
+ * - XML_SERIALIZER_ENTITIES_XML (default)
+ * - XML_SERIALIZER_ENTITIES_XML_REQUIRED
+ * - XML_SERIALIZER_ENTITIES_HTML
+ */
+define('XML_SERIALIZER_OPTION_ENTITIES', 'replaceEntities');
+
+/**
+ * option: whether to return the result of the serialization from serialize()
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ */
+define('XML_SERIALIZER_OPTION_RETURN_RESULT', 'returnResult');
+
+/**
+ * option: whether to ignore properties that are set to null
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ */
+define('XML_SERIALIZER_OPTION_IGNORE_NULL', 'ignoreNull');
+
+/**
+ * option: whether to use cdata sections for character data
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ */
+define('XML_SERIALIZER_OPTION_CDATA_SECTIONS', 'cdata');
+
+
+/**
+ * default mode
+ */
+define('XML_SERIALIZER_MODE_DEFAULT', 'default');
+
+/**
+ * SimpleXML mode
+ *
+ * When serializing indexed arrays, the key of the parent value is used as a tagname.
+ */
+define('XML_SERIALIZER_MODE_SIMPLEXML', 'simplexml');
+
+/**
+ * error code for no serialization done
+ */
+define('XML_SERIALIZER_ERROR_NO_SERIALIZATION', 51);
+
+/**
+ * do not replace entitites
+ */
+define('XML_SERIALIZER_ENTITIES_NONE', XML_UTIL_ENTITIES_NONE);
+
+/**
+ * replace all XML entitites
+ * This setting will replace <, >, ", ' and &
+ */
+define('XML_SERIALIZER_ENTITIES_XML', XML_UTIL_ENTITIES_XML);
+
+/**
+ * replace only required XML entitites
+ * This setting will replace <, " and &
+ */
+define('XML_SERIALIZER_ENTITIES_XML_REQUIRED', XML_UTIL_ENTITIES_XML_REQUIRED);
+
+/**
+ * replace HTML entitites
+ * @link http://www.php.net/htmlentities
+ */
+define('XML_SERIALIZER_ENTITIES_HTML', XML_UTIL_ENTITIES_HTML);
+
+/**
+ * Creates XML documents from PHP data structures like arrays, objects or scalars.
+ *
+ * this class can be used in two modes:
+ *
+ * 1. create an XML document from an array or object that is processed by other
+ * applications. That means, you can create a RDF document from an array in the
+ * following format:
+ *
+ * $data = array(
+ * 'channel' => array(
+ * 'title' => 'Example RDF channel',
+ * 'link' => 'http://www.php-tools.de',
+ * 'image' => array(
+ * 'title' => 'Example image',
+ * 'url' => 'http://www.php-tools.de/image.gif',
+ * 'link' => 'http://www.php-tools.de'
+ * ),
+ * array(
+ * 'title' => 'Example item',
+ * 'link' => 'http://example.com'
+ * ),
+ * array(
+ * 'title' => 'Another Example item',
+ * 'link' => 'http://example.org'
+ * )
+ * )
+ * );
+ *
+ * to create a RDF document from this array do the following:
+ *
+ * require_once 'XML/Serializer.php';
+ *
+ * $options = array(
+ * XML_SERIALIZER_OPTION_INDENT => "\t", // indent with tabs
+ * XML_SERIALIZER_OPTION_LINEBREAKS => "\n", // use UNIX line breaks
+ * XML_SERIALIZER_OPTION_ROOT_NAME => 'rdf:RDF', // root tag
+ * XML_SERIALIZER_OPTION_DEFAULT_TAG => 'item' // tag for values with numeric keys
+ * );
+ *
+ * $serializer = new XML_Serializer($options);
+ * $rdf = $serializer->serialize($data);
+ *
+ * You will get a complete XML document that can be processed like any RDF document.
+ *
+ * 2. this classes can be used to serialize any data structure in a way that it can
+ * later be unserialized again.
+ * XML_Serializer will store the type of the value and additional meta information
+ * in attributes of the surrounding tag. This meat information can later be used
+ * to restore the original data structure in PHP. If you want XML_Serializer
+ * to add meta information to the tags, add
+ *
+ * XML_SERIALIZER_OPTION_TYPEHINTS => true
+ *
+ * to the options array in the constructor.
+ *
+ * @category XML
+ * @package XML_Serializer
+ * @author Stephan Schmidt <schst@php.net>
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: @package_version@
+ * @link http://pear.php.net/package/XML_Serializer
+ * @see XML_Unserializer
+ */
+class XML_Serializer extends PEAR
+{
+ /**
+ * list of all available options
+ *
+ * @access private
+ * @var array
+ */
+ var $_knownOptions = array(
+ XML_SERIALIZER_OPTION_INDENT,
+ XML_SERIALIZER_OPTION_LINEBREAKS,
+ XML_SERIALIZER_OPTION_TYPEHINTS,
+ XML_SERIALIZER_OPTION_XML_DECL_ENABLED,
+ XML_SERIALIZER_OPTION_XML_ENCODING,
+ XML_SERIALIZER_OPTION_DEFAULT_TAG,
+ XML_SERIALIZER_OPTION_CLASSNAME_AS_TAGNAME,
+ XML_SERIALIZER_OPTION_ATTRIBUTE_KEY,
+ XML_SERIALIZER_OPTION_ATTRIBUTE_TYPE,
+ XML_SERIALIZER_OPTION_ATTRIBUTE_CLASS,
+ XML_SERIALIZER_OPTION_SCALAR_AS_ATTRIBUTES,
+ XML_SERIALIZER_OPTION_PREPEND_ATTRIBUTES,
+ XML_SERIALIZER_OPTION_INDENT_ATTRIBUTES,
+ XML_SERIALIZER_OPTION_MODE,
+ XML_SERIALIZER_OPTION_DOCTYPE_ENABLED,
+ XML_SERIALIZER_OPTION_DOCTYPE,
+ XML_SERIALIZER_OPTION_ROOT_NAME,
+ XML_SERIALIZER_OPTION_ROOT_ATTRIBS,
+ XML_SERIALIZER_OPTION_ATTRIBUTES_KEY,
+ XML_SERIALIZER_OPTION_CONTENT_KEY,
+ XML_SERIALIZER_OPTION_COMMENT_KEY,
+ XML_SERIALIZER_OPTION_TAGMAP,
+ XML_SERIALIZER_OPTION_ENCODE_FUNC,
+ XML_SERIALIZER_OPTION_NAMESPACE,
+ XML_SERIALIZER_OPTION_ENTITIES,
+ XML_SERIALIZER_OPTION_RETURN_RESULT,
+ XML_SERIALIZER_OPTION_IGNORE_NULL,
+ XML_SERIALIZER_OPTION_CDATA_SECTIONS
+ );
+
+ /**
+ * default options for the serialization
+ *
+ * @access private
+ * @var array
+ */
+ var $_defaultOptions = array(
+ XML_SERIALIZER_OPTION_INDENT => '', // string used for indentation
+ XML_SERIALIZER_OPTION_LINEBREAKS => "\n", // string used for newlines
+ XML_SERIALIZER_OPTION_TYPEHINTS => false, // automatically add type hin attributes
+ XML_SERIALIZER_OPTION_XML_DECL_ENABLED => false, // add an XML declaration
+ XML_SERIALIZER_OPTION_XML_ENCODING => null, // encoding specified in the XML declaration
+ XML_SERIALIZER_OPTION_DEFAULT_TAG => 'XML_Serializer_Tag', // tag used for indexed arrays or invalid names
+ XML_SERIALIZER_OPTION_CLASSNAME_AS_TAGNAME => false, // use classname for objects in indexed arrays
+ XML_SERIALIZER_OPTION_ATTRIBUTE_KEY => '_originalKey', // attribute where original key is stored
+ XML_SERIALIZER_OPTION_ATTRIBUTE_TYPE => '_type', // attribute for type (only if typeHints => true)
+ XML_SERIALIZER_OPTION_ATTRIBUTE_CLASS => '_class', // attribute for class of objects (only if typeHints => true)
+ XML_SERIALIZER_OPTION_SCALAR_AS_ATTRIBUTES => false, // scalar values (strings, ints,..) will be serialized as attribute
+ XML_SERIALIZER_OPTION_PREPEND_ATTRIBUTES => '', // prepend string for attributes
+ XML_SERIALIZER_OPTION_INDENT_ATTRIBUTES => false, // indent the attributes, if set to '_auto', it will indent attributes so they all start at the same column
+ XML_SERIALIZER_OPTION_MODE => XML_SERIALIZER_MODE_DEFAULT, // use XML_SERIALIZER_MODE_SIMPLEXML to use parent name as tagname if transforming an indexed array
+ XML_SERIALIZER_OPTION_DOCTYPE_ENABLED => false, // add a doctype declaration
+ XML_SERIALIZER_OPTION_DOCTYPE => null, // supply a string or an array with id and uri ({@see XML_Util::getDoctypeDeclaration()}
+ XML_SERIALIZER_OPTION_ROOT_NAME => null, // name of the root tag
+ XML_SERIALIZER_OPTION_ROOT_ATTRIBS => array(), // attributes of the root tag
+ XML_SERIALIZER_OPTION_ATTRIBUTES_KEY => null, // all values in this key will be treated as attributes
+ XML_SERIALIZER_OPTION_CONTENT_KEY => null, // this value will be used directly as content, instead of creating a new tag, may only be used in conjuction with attributesArray
+ XML_SERIALIZER_OPTION_COMMENT_KEY => null, // this value will be used directly as comment, instead of creating a new tag, may only be used in conjuction with attributesArray
+ XML_SERIALIZER_OPTION_TAGMAP => array(), // tag names that will be changed
+ XML_SERIALIZER_OPTION_ENCODE_FUNC => null, // function that will be applied before serializing
+ XML_SERIALIZER_OPTION_NAMESPACE => null, // namespace to use
+ XML_SERIALIZER_OPTION_ENTITIES => XML_SERIALIZER_ENTITIES_XML, // type of entities to replace,
+ XML_SERIALIZER_OPTION_RETURN_RESULT => false, // serialize() returns the result of the serialization instead of true
+ XML_SERIALIZER_OPTION_IGNORE_NULL => false, // ignore properties that are set to null
+ XML_SERIALIZER_OPTION_CDATA_SECTIONS => false // Whether to use cdata sections for plain character data
+ );
+
+ /**
+ * options for the serialization
+ *
+ * @access public
+ * @var array
+ */
+ var $options = array();
+
+ /**
+ * current tag depth
+ *
+ * @access private
+ * @var integer
+ */
+ var $_tagDepth = 0;
+
+ /**
+ * serilialized representation of the data
+ *
+ * @access private
+ * @var string
+ */
+ var $_serializedData = null;
+
+ /**
+ * constructor
+ *
+ * @access public
+ * @param mixed $options array containing options for the serialization
+ */
+ function XML_Serializer( $options = null )
+ {
+ $this->PEAR();
+ if (is_array($options)) {
+ $this->options = array_merge($this->_defaultOptions, $options);
+ } else {
+ $this->options = $this->_defaultOptions;
+ }
+ }
+
+ /**
+ * return API version
+ *
+ * @access public
+ * @static
+ * @return string $version API version
+ */
+ function apiVersion()
+ {
+ return '@package_version@';
+ }
+
+ /**
+ * reset all options to default options
+ *
+ * @access public
+ * @see setOption(), XML_Serializer()
+ */
+ function resetOptions()
+ {
+ $this->options = $this->_defaultOptions;
+ }
+
+ /**
+ * set an option
+ *
+ * You can use this method if you do not want to set all options in the constructor
+ *
+ * @access public
+ * @see resetOption(), XML_Serializer()
+ */
+ function setOption($name, $value)
+ {
+ $this->options[$name] = $value;
+ }
+
+ /**
+ * sets several options at once
+ *
+ * You can use this method if you do not want to set all options in the constructor
+ *
+ * @access public
+ * @see resetOption(), XML_Unserializer(), setOption()
+ */
+ function setOptions($options)
+ {
+ $this->options = array_merge($this->options, $options);
+ }
+
+ /**
+ * serialize data
+ *
+ * @access public
+ * @param mixed $data data to serialize
+ * @return boolean true on success, pear error on failure
+ */
+ function serialize($data, $options = null)
+ {
+ // if options have been specified, use them instead
+ // of the previously defined ones
+ if (is_array($options)) {
+ $optionsBak = $this->options;
+ if (isset($options['overrideOptions']) && $options['overrideOptions'] == true) {
+ $this->options = array_merge($this->_defaultOptions, $options);
+ } else {
+ $this->options = array_merge($this->options, $options);
+ }
+ } else {
+ $optionsBak = null;
+ }
+
+ // start depth is zero
+ $this->_tagDepth = 0;
+
+ $rootAttributes = $this->options[XML_SERIALIZER_OPTION_ROOT_ATTRIBS];
+ if (isset($this->options[XML_SERIALIZER_OPTION_NAMESPACE]) && is_array($this->options[XML_SERIALIZER_OPTION_NAMESPACE])) {
+ $rootAttributes['xmlns:'.$this->options[XML_SERIALIZER_OPTION_NAMESPACE][0]] = $this->options[XML_SERIALIZER_OPTION_NAMESPACE][1];
+ }
+
+ $this->_serializedData = '';
+ // serialize an array
+ if (is_array($data)) {
+ if (isset($this->options[XML_SERIALIZER_OPTION_ROOT_NAME])) {
+ $tagName = $this->options[XML_SERIALIZER_OPTION_ROOT_NAME];
+ } else {
+ $tagName = 'array';
+ }
+
+ $this->_serializedData .= $this->_serializeArray($data, $tagName, $rootAttributes);
+ } elseif (is_object($data)) {
+ // serialize an object
+ if (isset($this->options[XML_SERIALIZER_OPTION_ROOT_NAME])) {
+ $tagName = $this->options[XML_SERIALIZER_OPTION_ROOT_NAME];
+ } else {
+ $tagName = get_class($data);
+ }
+ $this->_serializedData .= $this->_serializeObject($data, $tagName, $rootAttributes);
+ } else {
+ $tag = array();
+ if (isset($this->options[XML_SERIALIZER_OPTION_ROOT_NAME])) {
+ $tag['qname'] = $this->options[XML_SERIALIZER_OPTION_ROOT_NAME];
+ } else {
+ $tag['qname'] = gettype($data);
+ }
+ if ($this->options[XML_SERIALIZER_OPTION_TYPEHINTS] === true) {
+ $rootAttributes[$this->options[XML_SERIALIZER_OPTION_ATTRIBUTE_TYPE]] = gettype($data);
+ }
+ @settype($data, 'string');
+ $tag['content'] = $data;
+ $tag['attributes'] = $rootAttributes;
+ $this->_serializedData = $this->_createXMLTag($tag);
+ }
+
+ // add doctype declaration
+ if ($this->options[XML_SERIALIZER_OPTION_DOCTYPE_ENABLED] === true) {
+ $this->_serializedData = XML_Util::getDoctypeDeclaration($tagName, $this->options[XML_SERIALIZER_OPTION_DOCTYPE])
+ . $this->options[XML_SERIALIZER_OPTION_LINEBREAKS]
+ . $this->_serializedData;
+ }
+
+ // build xml declaration
+ if ($this->options[XML_SERIALIZER_OPTION_XML_DECL_ENABLED]) {
+ $atts = array();
+ $this->_serializedData = XML_Util::getXMLDeclaration('1.0', $this->options[XML_SERIALIZER_OPTION_XML_ENCODING])
+ . $this->options[XML_SERIALIZER_OPTION_LINEBREAKS]
+ . $this->_serializedData;
+ }
+
+ if ($this->options[XML_SERIALIZER_OPTION_RETURN_RESULT] === true) {
+ $result = $this->_serializedData;
+ } else {
+ $result = true;
+ }
+
+ if ($optionsBak !== null) {
+ $this->options = $optionsBak;
+ }
+
+ return $result;
+ }
+
+ /**
+ * get the result of the serialization
+ *
+ * @access public
+ * @return string serialized XML
+ */
+ function getSerializedData()
+ {
+ if ($this->_serializedData == null) {
+ return $this->raiseError('No serialized data available. Use XML_Serializer::serialize() first.', XML_SERIALIZER_ERROR_NO_SERIALIZATION);
+ }
+ return $this->_serializedData;
+ }
+
+ /**
+ * serialize any value
+ *
+ * This method checks for the type of the value and calls the appropriate method
+ *
+ * @access private
+ * @param mixed $value
+ * @param string $tagName
+ * @param array $attributes
+ * @return string
+ */
+ function _serializeValue($value, $tagName = null, $attributes = array())
+ {
+ if (is_array($value)) {
+ $xml = $this->_serializeArray($value, $tagName, $attributes);
+ } elseif (is_object($value)) {
+ $xml = $this->_serializeObject($value, $tagName);
+ } else {
+ $tag = array(
+ 'qname' => $tagName,
+ 'attributes' => $attributes,
+ 'content' => $value
+ );
+ $xml = $this->_createXMLTag($tag);
+ }
+ return $xml;
+ }
+
+ /**
+ * serialize an array
+ *
+ * @access private
+ * @param array $array array to serialize
+ * @param string $tagName name of the root tag
+ * @param array $attributes attributes for the root tag
+ * @return string $string serialized data
+ * @uses XML_Util::isValidName() to check, whether key has to be substituted
+ */
+ function _serializeArray(&$array, $tagName = null, $attributes = array())
+ {
+ $_content = null;
+ $_comment = null;
+
+ // check for comment
+ if ($this->options[XML_SERIALIZER_OPTION_COMMENT_KEY] !== null) {
+ if (isset($array[$this->options[XML_SERIALIZER_OPTION_COMMENT_KEY]])) {
+ $_comment = $array[$this->options[XML_SERIALIZER_OPTION_COMMENT_KEY]];
+ unset($array[$this->options[XML_SERIALIZER_OPTION_COMMENT_KEY]]);
+ }
+ }
+
+ /**
+ * check for special attributes
+ */
+ if ($this->options[XML_SERIALIZER_OPTION_ATTRIBUTES_KEY] !== null) {
+ if (isset($array[$this->options[XML_SERIALIZER_OPTION_ATTRIBUTES_KEY]])) {
+ $attributes = $array[$this->options[XML_SERIALIZER_OPTION_ATTRIBUTES_KEY]];
+ unset($array[$this->options[XML_SERIALIZER_OPTION_ATTRIBUTES_KEY]]);
+ }
+ /**
+ * check for special content
+ */
+ if ($this->options[XML_SERIALIZER_OPTION_CONTENT_KEY] !== null) {
+ if (isset($array[$this->options[XML_SERIALIZER_OPTION_CONTENT_KEY]])) {
+ $_content = $array[$this->options[XML_SERIALIZER_OPTION_CONTENT_KEY]];
+ unset($array[$this->options[XML_SERIALIZER_OPTION_CONTENT_KEY]]);
+ }
+ }
+ }
+
+ if ($this->options[XML_SERIALIZER_OPTION_IGNORE_NULL] === true) {
+ foreach (array_keys($array) as $key) {
+ if (is_null($array[$key])) {
+ unset($array[$key]);
+ }
+ }
+ }
+
+ /*
+ * if mode is set to simpleXML, check whether
+ * the array is associative or indexed
+ */
+ if (is_array($array) && !empty($array) && $this->options[XML_SERIALIZER_OPTION_MODE] == XML_SERIALIZER_MODE_SIMPLEXML) {
+ $indexed = true;
+ foreach ($array as $key => $val) {
+ if (!is_int($key)) {
+ $indexed = false;
+ break;
+ }
+ }
+
+ if ($indexed && $this->options[XML_SERIALIZER_OPTION_MODE] == XML_SERIALIZER_MODE_SIMPLEXML) {
+ $string = '';
+ foreach ($array as $key => $val) {
+ $string .= $this->_serializeValue( $val, $tagName, $attributes);
+
+ $string .= $this->options[XML_SERIALIZER_OPTION_LINEBREAKS];
+ // do indentation
+ if ($this->options[XML_SERIALIZER_OPTION_INDENT]!==null && $this->_tagDepth>0) {
+ $string .= str_repeat($this->options[XML_SERIALIZER_OPTION_INDENT], $this->_tagDepth);
+ }
+ }
+ return rtrim($string);
+ }
+ }
+
+ $scalarAsAttributes = false;
+ if (is_array($this->options[XML_SERIALIZER_OPTION_SCALAR_AS_ATTRIBUTES]) && isset($this->options[XML_SERIALIZER_OPTION_SCALAR_AS_ATTRIBUTES][$tagName])) {
+ $scalarAsAttributes = $this->options[XML_SERIALIZER_OPTION_SCALAR_AS_ATTRIBUTES][$tagName];
+ } elseif ($this->options[XML_SERIALIZER_OPTION_SCALAR_AS_ATTRIBUTES] === true) {
+ $scalarAsAttributes = true;
+ }
+
+ if ($scalarAsAttributes === true) {
+ $this->expectError('*');
+ foreach ($array as $key => $value) {
+ if (is_scalar($value) && (XML_Util::isValidName($key) === true)) {
+ unset($array[$key]);
+ $attributes[$this->options[XML_SERIALIZER_OPTION_PREPEND_ATTRIBUTES].$key] = $value;
+ }
+ }
+ $this->popExpect();
+ } elseif (is_array($scalarAsAttributes)) {
+ $this->expectError('*');
+ foreach ($scalarAsAttributes as $key) {
+ if (!isset($array[$key])) {
+ continue;
+ }
+ $value = $array[$key];
+ if (is_scalar($value) && (XML_Util::isValidName($key) === true)) {
+ unset($array[$key]);
+ $attributes[$this->options[XML_SERIALIZER_OPTION_PREPEND_ATTRIBUTES].$key] = $value;
+ }
+ }
+ $this->popExpect();
+ }
+
+ // check for empty array => create empty tag
+ if (empty($array)) {
+ $tag = array(
+ 'qname' => $tagName,
+ 'content' => $_content,
+ 'attributes' => $attributes
+ );
+ } else {
+ $this->_tagDepth++;
+ $tmp = $this->options[XML_SERIALIZER_OPTION_LINEBREAKS];
+ foreach ($array as $key => $value) {
+ // do indentation
+ if ($this->options[XML_SERIALIZER_OPTION_INDENT]!==null && $this->_tagDepth>0) {
+ $tmp .= str_repeat($this->options[XML_SERIALIZER_OPTION_INDENT], $this->_tagDepth);
+ }
+
+ if (isset($this->options[XML_SERIALIZER_OPTION_TAGMAP][$key])) {
+ $key = $this->options[XML_SERIALIZER_OPTION_TAGMAP][$key];
+ }
+
+ // copy key
+ $origKey = $key;
+ $this->expectError('*');
+ // key cannot be used as tagname => use default tag
+ $valid = XML_Util::isValidName($key);
+ $this->popExpect();
+ if (PEAR::isError($valid)) {
+ if ($this->options[XML_SERIALIZER_OPTION_CLASSNAME_AS_TAGNAME] && is_object($value)) {
+ $key = get_class($value);
+ } else {
+ $key = $this->_getDefaultTagname($tagName);
+ }
+ }
+ $atts = array();
+ if ($this->options[XML_SERIALIZER_OPTION_TYPEHINTS] === true) {
+ $atts[$this->options[XML_SERIALIZER_OPTION_ATTRIBUTE_TYPE]] = gettype($value);
+ if ($key !== $origKey) {
+ $atts[$this->options[XML_SERIALIZER_OPTION_ATTRIBUTE_KEY]] = (string)$origKey;
+ }
+ }
+
+ $tmp .= $this->_createXMLTag(array(
+ 'qname' => $key,
+ 'attributes' => $atts,
+ 'content' => $value )
+ );
+ $tmp .= $this->options[XML_SERIALIZER_OPTION_LINEBREAKS];
+ }
+
+ $this->_tagDepth--;
+ if ($this->options[XML_SERIALIZER_OPTION_INDENT]!==null && $this->_tagDepth>0) {
+ $tmp .= str_repeat($this->options[XML_SERIALIZER_OPTION_INDENT], $this->_tagDepth);
+ }
+
+ if (trim($tmp) === '') {
+ $tmp = null;
+ }
+
+ $tag = array(
+ 'qname' => $tagName,
+ 'content' => $tmp,
+ 'attributes' => $attributes
+ );
+ }
+ if ($this->options[XML_SERIALIZER_OPTION_TYPEHINTS] === true) {
+ if (!isset($tag['attributes'][$this->options[XML_SERIALIZER_OPTION_ATTRIBUTE_TYPE]])) {
+ $tag['attributes'][$this->options[XML_SERIALIZER_OPTION_ATTRIBUTE_TYPE]] = 'array';
+ }
+ }
+
+ $string = '';
+ if (!is_null($_comment)) {
+ $string .= XML_Util::createComment($_comment);
+ $string .= $this->options[XML_SERIALIZER_OPTION_LINEBREAKS];
+ if ($this->options[XML_SERIALIZER_OPTION_INDENT]!==null && $this->_tagDepth>0) {
+ $string .= str_repeat($this->options[XML_SERIALIZER_OPTION_INDENT], $this->_tagDepth);
+ }
+ }
+ $string .= $this->_createXMLTag($tag, false);
+ return $string;
+ }
+
+ /**
+ * get the name of the default tag.
+ *
+ * The name of the parent tag needs to be passed as the
+ * default name can depend on the context.
+ *
+ * @param string name of the parent tag
+ * @return string default tag name
+ */
+ function _getDefaultTagname($parent)
+ {
+ if (is_string($this->options[XML_SERIALIZER_OPTION_DEFAULT_TAG])) {
+ return $this->options[XML_SERIALIZER_OPTION_DEFAULT_TAG];
+ }
+ if (isset($this->options[XML_SERIALIZER_OPTION_DEFAULT_TAG][$parent])) {
+ return $this->options[XML_SERIALIZER_OPTION_DEFAULT_TAG][$parent];
+ } elseif (isset($this->options[XML_SERIALIZER_OPTION_DEFAULT_TAG]['#default'])) {
+ return $this->options[XML_SERIALIZER_OPTION_DEFAULT_TAG]['#default'];
+ } elseif (isset($this->options[XML_SERIALIZER_OPTION_DEFAULT_TAG]['__default'])) {
+ // keep this for BC
+ return $this->options[XML_SERIALIZER_OPTION_DEFAULT_TAG]['__default'];
+ }
+ return 'XML_Serializer_Tag';
+ }
+
+ /**
+ * serialize an object
+ *
+ * @access private
+ * @param object $object object to serialize
+ * @return string $string serialized data
+ */
+ function _serializeObject(&$object, $tagName = null, $attributes = array())
+ {
+ // check for magic function
+ if (method_exists($object, '__sleep')) {
+ $propNames = $object->__sleep();
+ if (is_array($propNames)) {
+ $properties = array();
+ foreach ($propNames as $propName) {
+ $properties[$propName] = $object->$propName;
+ }
+ } else {
+ $properties = get_object_vars($object);
+ }
+ } else {
+ $properties = get_object_vars($object);
+ }
+
+ if (empty($tagName)) {
+ $tagName = get_class($object);
+ }
+
+ // typehints activated?
+ if ($this->options[XML_SERIALIZER_OPTION_TYPEHINTS] === true) {
+ $attributes[$this->options[XML_SERIALIZER_OPTION_ATTRIBUTE_TYPE]] = 'object';
+ $attributes[$this->options[XML_SERIALIZER_OPTION_ATTRIBUTE_CLASS]] = get_class($object);
+ }
+ $string = $this->_serializeArray($properties, $tagName, $attributes);
+ return $string;
+ }
+
+ /**
+ * create a tag from an array
+ * this method awaits an array in the following format
+ * array(
+ * 'qname' => $tagName,
+ * 'attributes' => array(),
+ * 'content' => $content, // optional
+ * 'namespace' => $namespace // optional
+ * 'namespaceUri' => $namespaceUri // optional
+ * )
+ *
+ * @access private
+ * @param array $tag tag definition
+ * @param boolean $replaceEntities whether to replace XML entities in content or not
+ * @return string $string XML tag
+ */
+ function _createXMLTag($tag, $firstCall = true)
+ {
+ // build fully qualified tag name
+ if ($this->options[XML_SERIALIZER_OPTION_NAMESPACE] !== null) {
+ if (is_array($this->options[XML_SERIALIZER_OPTION_NAMESPACE])) {
+ $tag['qname'] = $this->options[XML_SERIALIZER_OPTION_NAMESPACE][0] . ':' . $tag['qname'];
+ } else {
+ $tag['qname'] = $this->options[XML_SERIALIZER_OPTION_NAMESPACE] . ':' . $tag['qname'];
+ }
+ }
+
+ // attribute indentation
+ if ($this->options[XML_SERIALIZER_OPTION_INDENT_ATTRIBUTES] !== false) {
+ $multiline = true;
+ $indent = str_repeat($this->options[XML_SERIALIZER_OPTION_INDENT], $this->_tagDepth);
+
+ if ($this->options[XML_SERIALIZER_OPTION_INDENT_ATTRIBUTES] == '_auto') {
+ $indent .= str_repeat(' ', (strlen($tag['qname'])+2));
+
+ } else {
+ $indent .= $this->options[XML_SERIALIZER_OPTION_INDENT_ATTRIBUTES];
+ }
+ } else {
+ $multiline = false;
+ $indent = false;
+ }
+
+ if (is_array($tag['content'])) {
+ if (empty($tag['content'])) {
+ $tag['content'] = '';
+ }
+ } elseif(is_scalar($tag['content']) && (string)$tag['content'] == '') {
+ $tag['content'] = '';
+ }
+
+ // replace XML entities (only needed, if this is not a nested call)
+ if ($firstCall === true) {
+ if ($this->options[XML_SERIALIZER_OPTION_CDATA_SECTIONS] === true) {
+ $replaceEntities = XML_UTIL_CDATA_SECTION;
+ } else {
+ $replaceEntities = $this->options[XML_SERIALIZER_OPTION_ENTITIES];
+ }
+ } else {
+ $replaceEntities = XML_SERIALIZER_ENTITIES_NONE;
+ }
+ if (is_scalar($tag['content']) || is_null($tag['content'])) {
+ if ($this->options[XML_SERIALIZER_OPTION_ENCODE_FUNC]) {
+ if ($firstCall === true) {
+ $tag['content'] = call_user_func($this->options[XML_SERIALIZER_OPTION_ENCODE_FUNC], $tag['content']);
+ }
+ $tag['attributes'] = array_map($this->options[XML_SERIALIZER_OPTION_ENCODE_FUNC], $tag['attributes']);
+ }
+ $tag = XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $this->options[XML_SERIALIZER_OPTION_LINEBREAKS]);
+ } elseif (is_array($tag['content'])) {
+ $tag = $this->_serializeArray($tag['content'], $tag['qname'], $tag['attributes']);
+ } elseif (is_object($tag['content'])) {
+ $tag = $this->_serializeObject($tag['content'], $tag['qname'], $tag['attributes']);
+ } elseif (is_resource($tag['content'])) {
+ settype($tag['content'], 'string');
+ if ($this->options[XML_SERIALIZER_OPTION_ENCODE_FUNC]) {
+ if ($replaceEntities === true) {
+ $tag['content'] = call_user_func($this->options[XML_SERIALIZER_OPTION_ENCODE_FUNC], $tag['content']);
+ }
+ $tag['attributes'] = array_map($this->options[XML_SERIALIZER_OPTION_ENCODE_FUNC], $tag['attributes']);
+ }
+ $tag = XML_Util::createTagFromArray($tag, $replaceEntities);
+ }
+ return $tag;
+ }
+}
+?> \ No newline at end of file
diff --git a/libs/XML/Unserializer.php b/libs/XML/Unserializer.php
new file mode 100644
index 0000000000..a5a03dcfc6
--- /dev/null
+++ b/libs/XML/Unserializer.php
@@ -0,0 +1,856 @@
+<?PHP
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * XML_Unserializer
+ *
+ * Parses any XML document into PHP data structures.
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * http://www.php.net/license/3_0.txt. If you did not receive a copy of
+ * the PHP License and are unable to obtain it through the web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category XML
+ * @package XML_Serializer
+ * @author Stephan Schmidt <schst@php.net>
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Unserializer.php,v 1.39 2005/09/28 11:19:56 schst Exp $
+ * @link http://pear.php.net/package/XML_Serializer
+ * @see XML_Unserializer
+ */
+
+/**
+ * uses PEAR error managemt
+ */
+require_once 'PEAR.php';
+
+/**
+ * uses XML_Parser to unserialize document
+ */
+require_once 'XML/Parser.php';
+
+/**
+ * option: Convert nested tags to array or object
+ *
+ * Possible values:
+ * - array
+ * - object
+ * - associative array to define this option per tag name
+ */
+define('XML_UNSERIALIZER_OPTION_COMPLEXTYPE', 'complexType');
+
+/**
+ * option: Name of the attribute that stores the original key
+ *
+ * Possible values:
+ * - any string
+ */
+define('XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY', 'keyAttribute');
+
+/**
+ * option: Name of the attribute that stores the type
+ *
+ * Possible values:
+ * - any string
+ */
+define('XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE', 'typeAttribute');
+
+/**
+ * option: Name of the attribute that stores the class name
+ *
+ * Possible values:
+ * - any string
+ */
+define('XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS', 'classAttribute');
+
+/**
+ * option: Whether to use the tag name as a class name
+ *
+ * Possible values:
+ * - true or false
+ */
+define('XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME', 'tagAsClass');
+
+/**
+ * option: Name of the default class
+ *
+ * Possible values:
+ * - any string
+ */
+define('XML_UNSERIALIZER_OPTION_DEFAULT_CLASS', 'defaultClass');
+
+/**
+ * option: Whether to parse attributes
+ *
+ * Possible values:
+ * - true or false
+ */
+define('XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE', 'parseAttributes');
+
+/**
+ * option: Key of the array to store attributes (if any)
+ *
+ * Possible values:
+ * - any string
+ * - false (disabled)
+ */
+define('XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY', 'attributesArray');
+
+/**
+ * option: string to prepend attribute name (if any)
+ *
+ * Possible values:
+ * - any string
+ * - false (disabled)
+ */
+define('XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND', 'prependAttributes');
+
+/**
+ * option: key to store the content, if XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE is used
+ *
+ * Possible values:
+ * - any string
+ */
+define('XML_UNSERIALIZER_OPTION_CONTENT_KEY', 'contentName');
+
+/**
+ * option: map tag names
+ *
+ * Possible values:
+ * - associative array
+ */
+define('XML_UNSERIALIZER_OPTION_TAG_MAP', 'tagMap');
+
+/**
+ * option: list of tags that will always be enumerated
+ *
+ * Possible values:
+ * - indexed array
+ */
+define('XML_UNSERIALIZER_OPTION_FORCE_ENUM', 'forceEnum');
+
+/**
+ * option: Encoding of the XML document
+ *
+ * Possible values:
+ * - UTF-8
+ * - ISO-8859-1
+ */
+define('XML_UNSERIALIZER_OPTION_ENCODING_SOURCE', 'encoding');
+
+/**
+ * option: Desired target encoding of the data
+ *
+ * Possible values:
+ * - UTF-8
+ * - ISO-8859-1
+ */
+define('XML_UNSERIALIZER_OPTION_ENCODING_TARGET', 'targetEncoding');
+
+/**
+ * option: Callback that will be applied to textual data
+ *
+ * Possible values:
+ * - any valid PHP callback
+ */
+define('XML_UNSERIALIZER_OPTION_DECODE_FUNC', 'decodeFunction');
+
+/**
+ * option: whether to return the result of the unserialization from unserialize()
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ */
+define('XML_UNSERIALIZER_OPTION_RETURN_RESULT', 'returnResult');
+
+/**
+ * option: set the whitespace behaviour
+ *
+ * Possible values:
+ * - XML_UNSERIALIZER_WHITESPACE_KEEP
+ * - XML_UNSERIALIZER_WHITESPACE_TRIM
+ * - XML_UNSERIALIZER_WHITESPACE_NORMALIZE
+ */
+define('XML_UNSERIALIZER_OPTION_WHITESPACE', 'whitespace');
+
+/**
+ * Keep all whitespace
+ */
+define('XML_UNSERIALIZER_WHITESPACE_KEEP', 'keep');
+
+/**
+ * remove whitespace from start and end of the data
+ */
+define('XML_UNSERIALIZER_WHITESPACE_TRIM', 'trim');
+
+/**
+ * normalize whitespace
+ */
+define('XML_UNSERIALIZER_WHITESPACE_NORMALIZE', 'normalize');
+
+/**
+ * option: whether to ovverride all options that have been set before
+ *
+ * Possible values:
+ * - true
+ * - false (default)
+ */
+define('XML_UNSERIALIZER_OPTION_OVERRIDE_OPTIONS', 'overrideOptions');
+
+/**
+ * option: list of tags, that will not be used as keys
+ */
+define('XML_UNSERIALIZER_OPTION_IGNORE_KEYS', 'ignoreKeys');
+
+/**
+ * option: whether to use type guessing for scalar values
+ */
+define('XML_UNSERIALIZER_OPTION_GUESS_TYPES', 'guessTypes');
+
+/**
+ * error code for no serialization done
+ */
+define('XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION', 151);
+
+/**
+ * XML_Unserializer
+ *
+ * class to unserialize XML documents that have been created with
+ * XML_Serializer. To unserialize an XML document you have to add
+ * type hints to the XML_Serializer options.
+ *
+ * If no type hints are available, XML_Unserializer will guess how
+ * the tags should be treated, that means complex structures will be
+ * arrays and tags with only CData in them will be strings.
+ *
+ * <code>
+ * require_once 'XML/Unserializer.php';
+ *
+ * // be careful to always use the ampersand in front of the new operator
+ * $unserializer = &new XML_Unserializer();
+ *
+ * $unserializer->unserialize($xml);
+ *
+ * $data = $unserializer->getUnserializedData();
+ * <code>
+ *
+ *
+ * @category XML
+ * @package XML_Serializer
+ * @author Stephan Schmidt <schst@php.net>
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version Release: @package_version@
+ * @link http://pear.php.net/package/XML_Serializer
+ * @see XML_Serializer
+ */
+class XML_Unserializer extends PEAR
+{
+ /**
+ * list of all available options
+ *
+ * @access private
+ * @var array
+ */
+ var $_knownOptions = array(
+ XML_UNSERIALIZER_OPTION_COMPLEXTYPE,
+ XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY,
+ XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE,
+ XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS,
+ XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME,
+ XML_UNSERIALIZER_OPTION_DEFAULT_CLASS,
+ XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE,
+ XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY,
+ XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND,
+ XML_UNSERIALIZER_OPTION_CONTENT_KEY,
+ XML_UNSERIALIZER_OPTION_TAG_MAP,
+ XML_UNSERIALIZER_OPTION_FORCE_ENUM,
+ XML_UNSERIALIZER_OPTION_ENCODING_SOURCE,
+ XML_UNSERIALIZER_OPTION_ENCODING_TARGET,
+ XML_UNSERIALIZER_OPTION_DECODE_FUNC,
+ XML_UNSERIALIZER_OPTION_RETURN_RESULT,
+ XML_UNSERIALIZER_OPTION_WHITESPACE,
+ XML_UNSERIALIZER_OPTION_IGNORE_KEYS,
+ XML_UNSERIALIZER_OPTION_GUESS_TYPES
+ );
+ /**
+ * default options for the serialization
+ *
+ * @access private
+ * @var array
+ */
+ var $_defaultOptions = array(
+ XML_UNSERIALIZER_OPTION_COMPLEXTYPE => 'array', // complex types will be converted to arrays, if no type hint is given
+ XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY => '_originalKey', // get array key/property name from this attribute
+ XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE => '_type', // get type from this attribute
+ XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS => '_class', // get class from this attribute (if not given, use tag name)
+ XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME => true, // use the tagname as the classname
+ XML_UNSERIALIZER_OPTION_DEFAULT_CLASS => 'stdClass', // name of the class that is used to create objects
+ XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE => false, // parse the attributes of the tag into an array
+ XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY => false, // parse them into sperate array (specify name of array here)
+ XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND => '', // prepend attribute names with this string
+ XML_UNSERIALIZER_OPTION_CONTENT_KEY => '_content', // put cdata found in a tag that has been converted to a complex type in this key
+ XML_UNSERIALIZER_OPTION_TAG_MAP => array(), // use this to map tagnames
+ XML_UNSERIALIZER_OPTION_FORCE_ENUM => array(), // these tags will always be an indexed array
+ XML_UNSERIALIZER_OPTION_ENCODING_SOURCE => null, // specify the encoding character of the document to parse
+ XML_UNSERIALIZER_OPTION_ENCODING_TARGET => null, // specify the target encoding
+ XML_UNSERIALIZER_OPTION_DECODE_FUNC => null, // function used to decode data
+ XML_UNSERIALIZER_OPTION_RETURN_RESULT => false, // unserialize() returns the result of the unserialization instead of true
+ XML_UNSERIALIZER_OPTION_WHITESPACE => XML_UNSERIALIZER_WHITESPACE_TRIM, // remove whitespace around data
+ XML_UNSERIALIZER_OPTION_IGNORE_KEYS => array(), // List of tags that will automatically be added to the parent, instead of adding a new key
+ XML_UNSERIALIZER_OPTION_GUESS_TYPES => false // Whether to use type guessing
+ );
+
+ /**
+ * current options for the serialization
+ *
+ * @access public
+ * @var array
+ */
+ var $options = array();
+
+ /**
+ * unserialized data
+ *
+ * @access private
+ * @var string
+ */
+ var $_unserializedData = null;
+
+ /**
+ * name of the root tag
+ *
+ * @access private
+ * @var string
+ */
+ var $_root = null;
+
+ /**
+ * stack for all data that is found
+ *
+ * @access private
+ * @var array
+ */
+ var $_dataStack = array();
+
+ /**
+ * stack for all values that are generated
+ *
+ * @access private
+ * @var array
+ */
+ var $_valStack = array();
+
+ /**
+ * current tag depth
+ *
+ * @access private
+ * @var int
+ */
+ var $_depth = 0;
+
+ /**
+ * XML_Parser instance
+ *
+ * @access private
+ * @var object XML_Parser
+ */
+ var $_parser = null;
+
+ /**
+ * constructor
+ *
+ * @access public
+ * @param mixed $options array containing options for the unserialization
+ */
+ function XML_Unserializer($options = null)
+ {
+ if (is_array($options)) {
+ $this->options = array_merge($this->_defaultOptions, $options);
+ } else {
+ $this->options = $this->_defaultOptions;
+ }
+ }
+
+ /**
+ * return API version
+ *
+ * @access public
+ * @static
+ * @return string $version API version
+ */
+ function apiVersion()
+ {
+ return '@package_version@';
+ }
+
+ /**
+ * reset all options to default options
+ *
+ * @access public
+ * @see setOption(), XML_Unserializer(), setOptions()
+ */
+ function resetOptions()
+ {
+ $this->options = $this->_defaultOptions;
+ }
+
+ /**
+ * set an option
+ *
+ * You can use this method if you do not want to set all options in the constructor
+ *
+ * @access public
+ * @see resetOption(), XML_Unserializer(), setOptions()
+ */
+ function setOption($name, $value)
+ {
+ $this->options[$name] = $value;
+ }
+
+ /**
+ * sets several options at once
+ *
+ * You can use this method if you do not want to set all options in the constructor
+ *
+ * @access public
+ * @see resetOption(), XML_Unserializer(), setOption()
+ */
+ function setOptions($options)
+ {
+ $this->options = array_merge($this->options, $options);
+ }
+
+ /**
+ * unserialize data
+ *
+ * @access public
+ * @param mixed $data data to unserialize (string, filename or resource)
+ * @param boolean $isFile data should be treated as a file
+ * @param array $options options that will override the global options for this call
+ * @return boolean $success
+ */
+ function unserialize($data, $isFile = false, $options = null)
+ {
+ $this->_unserializedData = null;
+ $this->_root = null;
+
+ // if options have been specified, use them instead
+ // of the previously defined ones
+ if (is_array($options)) {
+ $optionsBak = $this->options;
+ if (isset($options[XML_UNSERIALIZER_OPTION_OVERRIDE_OPTIONS]) && $options[XML_UNSERIALIZER_OPTION_OVERRIDE_OPTIONS] == true) {
+ $this->options = array_merge($this->_defaultOptions, $options);
+ } else {
+ $this->options = array_merge($this->options, $options);
+ }
+ } else {
+ $optionsBak = null;
+ }
+
+ $this->_valStack = array();
+ $this->_dataStack = array();
+ $this->_depth = 0;
+
+ $this->_createParser();
+
+ if (is_string($data)) {
+ if ($isFile) {
+ $result = $this->_parser->setInputFile($data);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $result = $this->_parser->parse();
+ } else {
+ $result = $this->_parser->parseString($data,true);
+ }
+ } else {
+ $this->_parser->setInput($data);
+ $result = $this->_parser->parse();
+ }
+
+ if ($this->options[XML_UNSERIALIZER_OPTION_RETURN_RESULT] === true) {
+ $return = $this->_unserializedData;
+ } else {
+ $return = true;
+ }
+
+ if ($optionsBak !== null) {
+ $this->options = $optionsBak;
+ }
+
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+
+ return $return;
+ }
+
+ /**
+ * get the result of the serialization
+ *
+ * @access public
+ * @return string $serializedData
+ */
+ function getUnserializedData()
+ {
+ if ($this->_root === null) {
+ return $this->raiseError('No unserialized data available. Use XML_Unserializer::unserialize() first.', XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION);
+ }
+ return $this->_unserializedData;
+ }
+
+ /**
+ * get the name of the root tag
+ *
+ * @access public
+ * @return string $rootName
+ */
+ function getRootName()
+ {
+ if ($this->_root === null) {
+ return $this->raiseError('No unserialized data available. Use XML_Unserializer::unserialize() first.', XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION);
+ }
+ return $this->_root;
+ }
+
+ /**
+ * Start element handler for XML parser
+ *
+ * @access private
+ * @param object $parser XML parser object
+ * @param string $element XML element
+ * @param array $attribs attributes of XML tag
+ * @return void
+ */
+ function startHandler($parser, $element, $attribs)
+ {
+ if (isset($attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE]])) {
+ $type = $attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE]];
+ $guessType = false;
+ } else {
+ $type = 'string';
+ if ($this->options[XML_UNSERIALIZER_OPTION_GUESS_TYPES] === true) {
+ $guessType = true;
+ } else {
+ $guessType = false;
+ }
+ }
+
+ if ($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC] !== null) {
+ $attribs = array_map($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC], $attribs);
+ }
+
+ $this->_depth++;
+ $this->_dataStack[$this->_depth] = null;
+
+ if (is_array($this->options[XML_UNSERIALIZER_OPTION_TAG_MAP]) && isset($this->options[XML_UNSERIALIZER_OPTION_TAG_MAP][$element])) {
+ $element = $this->options[XML_UNSERIALIZER_OPTION_TAG_MAP][$element];
+ }
+
+ $val = array(
+ 'name' => $element,
+ 'value' => null,
+ 'type' => $type,
+ 'guessType' => $guessType,
+ 'childrenKeys' => array(),
+ 'aggregKeys' => array()
+ );
+
+ if ($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE] == true && (count($attribs) > 0)) {
+ $val['children'] = array();
+ $val['type'] = $this->_getComplexType($element);
+ $val['class'] = $element;
+
+ if ($this->options[XML_UNSERIALIZER_OPTION_GUESS_TYPES] === true) {
+ $attribs = $this->_guessAndSetTypes($attribs);
+ }
+ if ($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY] != false) {
+ $val['children'][$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY]] = $attribs;
+ } else {
+ foreach ($attribs as $attrib => $value) {
+ $val['children'][$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND].$attrib] = $value;
+ }
+ }
+ }
+
+ $keyAttr = false;
+
+ if (is_string($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY])) {
+ $keyAttr = $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY];
+ } elseif (is_array($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY])) {
+ if (isset($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY][$element])) {
+ $keyAttr = $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY][$element];
+ } elseif (isset($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]['#default'])) {
+ $keyAttr = $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]['#default'];
+ } elseif (isset($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]['__default'])) {
+ // keep this for BC
+ $keyAttr = $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]['__default'];
+ }
+ }
+
+ if ($keyAttr !== false && isset($attribs[$keyAttr])) {
+ $val['name'] = $attribs[$keyAttr];
+ }
+
+ if (isset($attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS]])) {
+ $val['class'] = $attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS]];
+ }
+
+ array_push($this->_valStack, $val);
+ }
+
+ /**
+ * Try to guess the type of several values and
+ * set them accordingly
+ *
+ * @access private
+ * @param array array, containing the values
+ * @return array array, containing the values with their correct types
+ */
+ function _guessAndSetTypes($array)
+ {
+ foreach ($array as $key => $value) {
+ $array[$key] = $this->_guessAndSetType($value);
+ }
+ return $array;
+ }
+
+ /**
+ * Try to guess the type of a value and
+ * set it accordingly
+ *
+ * @access private
+ * @param string character data
+ * @return mixed value with the best matching type
+ */
+ function _guessAndSetType($value)
+ {
+ if ($value === 'true') {
+ return true;
+ }
+ if ($value === 'false') {
+ return false;
+ }
+ if ($value === 'NULL') {
+ return null;
+ }
+ if (preg_match('/^[-+]?[0-9]{1,}$/', $value)) {
+ return intval($value);
+ }
+ if (preg_match('/^[-+]?[0-9]{1,}\.[0-9]{1,}$/', $value)) {
+ return doubleval($value);
+ }
+ return (string)$value;
+ }
+
+ /**
+ * End element handler for XML parser
+ *
+ * @access private
+ * @param object XML parser object
+ * @param string
+ * @return void
+ */
+ function endHandler($parser, $element)
+ {
+ $value = array_pop($this->_valStack);
+ switch ($this->options[XML_UNSERIALIZER_OPTION_WHITESPACE]) {
+ case XML_UNSERIALIZER_WHITESPACE_KEEP:
+ $data = $this->_dataStack[$this->_depth];
+ break;
+ case XML_UNSERIALIZER_WHITESPACE_NORMALIZE:
+ $data = trim(preg_replace('/\s\s+/m', ' ', $this->_dataStack[$this->_depth]));
+ break;
+ case XML_UNSERIALIZER_WHITESPACE_TRIM:
+ default:
+ $data = trim($this->_dataStack[$this->_depth]);
+ break;
+ }
+
+ // adjust type of the value
+ switch(strtolower($value['type'])) {
+
+ // unserialize an object
+ case 'object':
+ if (isset($value['class'])) {
+ $classname = $value['class'];
+ } else {
+ $classname = '';
+ }
+ // instantiate the class
+ if ($this->options[XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME] === true && class_exists($classname)) {
+ $value['value'] = &new $classname;
+ } else {
+ $value['value'] = &new $this->options[XML_UNSERIALIZER_OPTION_DEFAULT_CLASS];
+ }
+ if (trim($data) !== '') {
+ if ($value['guessType'] === true) {
+ $data = $this->_guessAndSetType($data);
+ }
+ $value['children'][$this->options[XML_UNSERIALIZER_OPTION_CONTENT_KEY]] = $data;
+ }
+
+ // set properties
+ foreach ($value['children'] as $prop => $propVal) {
+ // check whether there is a special method to set this property
+ $setMethod = 'set'.$prop;
+ if (method_exists($value['value'], $setMethod)) {
+ call_user_func(array(&$value['value'], $setMethod), $propVal);
+ } else {
+ $value['value']->$prop = $propVal;
+ }
+ }
+ // check for magic function
+ if (method_exists($value['value'], '__wakeup')) {
+ $value['value']->__wakeup();
+ }
+ break;
+
+ // unserialize an array
+ case 'array':
+ if (trim($data) !== '') {
+ if ($value['guessType'] === true) {
+ $data = $this->_guessAndSetType($data);
+ }
+ $value['children'][$this->options[XML_UNSERIALIZER_OPTION_CONTENT_KEY]] = $data;
+ }
+ if (isset($value['children'])) {
+ $value['value'] = $value['children'];
+ } else {
+ $value['value'] = array();
+ }
+ break;
+
+ // unserialize a null value
+ case 'null':
+ $data = null;
+ break;
+
+ // unserialize a resource => this is not possible :-(
+ case 'resource':
+ $value['value'] = $data;
+ break;
+
+ // unserialize any scalar value
+ default:
+ if ($value['guessType'] === true) {
+ $data = $this->_guessAndSetType($data);
+ } else {
+ settype($data, $value['type']);
+ }
+
+ $value['value'] = $data;
+ break;
+ }
+ $parent = array_pop($this->_valStack);
+ if ($parent === null) {
+ $this->_unserializedData = &$value['value'];
+ $this->_root = &$value['name'];
+ return true;
+ } else {
+ // parent has to be an array
+ if (!isset($parent['children']) || !is_array($parent['children'])) {
+ $parent['children'] = array();
+ if (!in_array($parent['type'], array('array', 'object'))) {
+ $parent['type'] = $this->_getComplexType($parent['name']);
+ if ($parent['type'] == 'object') {
+ $parent['class'] = $parent['name'];
+ }
+ }
+ }
+
+ if (in_array($element, $this->options[XML_UNSERIALIZER_OPTION_IGNORE_KEYS])) {
+ $ignoreKey = true;
+ } else {
+ $ignoreKey = false;
+ }
+
+ if (!empty($value['name']) && $ignoreKey === false) {
+ // there already has been a tag with this name
+ if (in_array($value['name'], $parent['childrenKeys']) || in_array($value['name'], $this->options[XML_UNSERIALIZER_OPTION_FORCE_ENUM])) {
+ // no aggregate has been created for this tag
+ if (!in_array($value['name'], $parent['aggregKeys'])) {
+ if (isset($parent['children'][$value['name']])) {
+ $parent['children'][$value['name']] = array($parent['children'][$value['name']]);
+ } else {
+ $parent['children'][$value['name']] = array();
+ }
+ array_push($parent['aggregKeys'], $value['name']);
+ }
+ array_push($parent['children'][$value['name']], $value['value']);
+ } else {
+ $parent['children'][$value['name']] = &$value['value'];
+ array_push($parent['childrenKeys'], $value['name']);
+ }
+ } else {
+ array_push($parent['children'], $value['value']);
+ }
+ array_push($this->_valStack, $parent);
+ }
+
+ $this->_depth--;
+ }
+
+ /**
+ * Handler for character data
+ *
+ * @access private
+ * @param object XML parser object
+ * @param string CDATA
+ * @return void
+ */
+ function cdataHandler($parser, $cdata)
+ {
+ if ($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC] !== null) {
+ $cdata = call_user_func($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC], $cdata);
+ }
+ $this->_dataStack[$this->_depth] .= $cdata;
+ }
+
+ /**
+ * get the complex type, that should be used for a specified tag
+ *
+ * @access private
+ * @param string name of the tag
+ * @return string complex type ('array' or 'object')
+ */
+ function _getComplexType($tagname)
+ {
+ if (is_string($this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE])) {
+ return $this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE];
+ }
+ if (isset($this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE][$tagname])) {
+ return $this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE][$tagname];
+ }
+ if (isset($this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE]['#default'])) {
+ return $this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE]['#default'];
+ }
+ return 'array';
+ }
+
+ /**
+ * create the XML_Parser instance
+ *
+ * @access private
+ * @return boolean
+ */
+ function _createParser()
+ {
+ if (is_object($this->_parser)) {
+ $this->_parser->free();
+ unset($this->_parser);
+ }
+ $this->_parser = &new XML_Parser($this->options[XML_UNSERIALIZER_OPTION_ENCODING_SOURCE], 'event', $this->options[XML_UNSERIALIZER_OPTION_ENCODING_TARGET]);
+ $this->_parser->folding = false;
+ $this->_parser->setHandlerObj($this);
+ return true;
+ }
+}
+?> \ No newline at end of file
diff --git a/libs/XML/Util.php b/libs/XML/Util.php
new file mode 100644
index 0000000000..133de882c9
--- /dev/null
+++ b/libs/XML/Util.php
@@ -0,0 +1,752 @@
+<?PHP
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------+
+// | PHP Version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2002 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 2.0 of the PHP license, |
+// | that is bundled with this package in the file LICENSE, and is |
+// | available at through the world-wide-web at |
+// | http://www.php.net/license/2_02.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +----------------------------------------------------------------------+
+// | Authors: Stephan Schmidt <schst@php-tools.net> |
+// +----------------------------------------------------------------------+
+//
+// $Id: Util.php,v 1.28 2006/12/16 09:42:56 schst Exp $
+
+/**
+ * error code for invalid chars in XML name
+ */
+define("XML_UTIL_ERROR_INVALID_CHARS", 51);
+
+/**
+ * error code for invalid chars in XML name
+ */
+define("XML_UTIL_ERROR_INVALID_START", 52);
+
+/**
+ * error code for non-scalar tag content
+ */
+define("XML_UTIL_ERROR_NON_SCALAR_CONTENT", 60);
+
+/**
+ * error code for missing tag name
+ */
+define("XML_UTIL_ERROR_NO_TAG_NAME", 61);
+
+/**
+ * replace XML entities
+ */
+define("XML_UTIL_REPLACE_ENTITIES", 1);
+
+/**
+ * embedd content in a CData Section
+ */
+define("XML_UTIL_CDATA_SECTION", 5);
+
+/**
+ * do not replace entitites
+ */
+define("XML_UTIL_ENTITIES_NONE", 0);
+
+/**
+ * replace all XML entitites
+ * This setting will replace <, >, ", ' and &
+ */
+define("XML_UTIL_ENTITIES_XML", 1);
+
+/**
+ * replace only required XML entitites
+ * This setting will replace <, " and &
+ */
+define("XML_UTIL_ENTITIES_XML_REQUIRED", 2);
+
+/**
+ * replace HTML entitites
+ * @link http://www.php.net/htmlentities
+ */
+define("XML_UTIL_ENTITIES_HTML", 3);
+
+/**
+ * Collapse all empty tags.
+ */
+define("XML_UTIL_COLLAPSE_ALL", 1);
+
+/**
+ * Collapse only empty XHTML tags that have no end tag.
+ */
+define("XML_UTIL_COLLAPSE_XHTML_ONLY", 2);
+
+/**
+ * utility class for working with XML documents
+ *
+ * @category XML
+ * @package XML_Util
+ * @version 1.1.0
+ * @author Stephan Schmidt <schst@php.net>
+ */
+class XML_Util {
+
+ /**
+ * return API version
+ *
+ * @access public
+ * @static
+ * @return string $version API version
+ */
+ static function apiVersion()
+ {
+ return '1.1';
+ }
+
+ /**
+ * replace XML entities
+ *
+ * With the optional second parameter, you may select, which
+ * entities should be replaced.
+ *
+ * <code>
+ * require_once 'XML/Util.php';
+ *
+ * // replace XML entites:
+ * $string = XML_Util::replaceEntities("This string contains < & >.");
+ * </code>
+ *
+ * @access public
+ * @static
+ * @param string string where XML special chars should be replaced
+ * @param integer setting for entities in attribute values (one of XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML)
+ * @return string string with replaced chars
+ * @see reverseEntities()
+ */
+ static function replaceEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML)
+ {
+ switch ($replaceEntities) {
+ case XML_UTIL_ENTITIES_XML:
+ return strtr($string,array(
+ '&' => '&amp;',
+ '>' => '&gt;',
+ '<' => '&lt;',
+ '"' => '&quot;',
+ '\'' => '&apos;' ));
+ break;
+ case XML_UTIL_ENTITIES_XML_REQUIRED:
+ return strtr($string,array(
+ '&' => '&amp;',
+ '<' => '&lt;',
+ '"' => '&quot;' ));
+ break;
+ case XML_UTIL_ENTITIES_HTML:
+ return htmlentities($string);
+ break;
+ }
+ return $string;
+ }
+
+ /**
+ * reverse XML entities
+ *
+ * With the optional second parameter, you may select, which
+ * entities should be reversed.
+ *
+ * <code>
+ * require_once 'XML/Util.php';
+ *
+ * // reverse XML entites:
+ * $string = XML_Util::reverseEntities("This string contains &lt; &amp; &gt;.");
+ * </code>
+ *
+ * @access public
+ * @static
+ * @param string string where XML special chars should be replaced
+ * @param integer setting for entities in attribute values (one of XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML)
+ * @return string string with replaced chars
+ * @see replaceEntities()
+ */
+ static function reverseEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML)
+ {
+ switch ($replaceEntities) {
+ case XML_UTIL_ENTITIES_XML:
+ return strtr($string,array(
+ '&amp;' => '&',
+ '&gt;' => '>',
+ '&lt;' => '<',
+ '&quot;' => '"',
+ '&apos;' => '\'' ));
+ break;
+ case XML_UTIL_ENTITIES_XML_REQUIRED:
+ return strtr($string,array(
+ '&amp;' => '&',
+ '&lt;' => '<',
+ '&quot;' => '"' ));
+ break;
+ case XML_UTIL_ENTITIES_HTML:
+ $arr = array_flip(get_html_translation_table(HTML_ENTITIES));
+ return strtr($string, $arr);
+ break;
+ }
+ return $string;
+ }
+
+ /**
+ * build an xml declaration
+ *
+ * <code>
+ * require_once 'XML/Util.php';
+ *
+ * // get an XML declaration:
+ * $xmlDecl = XML_Util::getXMLDeclaration("1.0", "UTF-8", true);
+ * </code>
+ *
+ * @access public
+ * @static
+ * @param string $version xml version
+ * @param string $encoding character encoding
+ * @param boolean $standAlone document is standalone (or not)
+ * @return string $decl xml declaration
+ * @uses XML_Util::attributesToString() to serialize the attributes of the XML declaration
+ */
+ static function getXMLDeclaration($version = "1.0", $encoding = null, $standalone = null)
+ {
+ $attributes = array(
+ "version" => $version,
+ );
+ // add encoding
+ if ($encoding !== null) {
+ $attributes["encoding"] = $encoding;
+ }
+ // add standalone, if specified
+ if ($standalone !== null) {
+ $attributes["standalone"] = $standalone ? "yes" : "no";
+ }
+
+ return sprintf("<?xml%s?>", XML_Util::attributesToString($attributes, false));
+ }
+
+ /**
+ * build a document type declaration
+ *
+ * <code>
+ * require_once 'XML/Util.php';
+ *
+ * // get a doctype declaration:
+ * $xmlDecl = XML_Util::getDocTypeDeclaration("rootTag","myDocType.dtd");
+ * </code>
+ *
+ * @access public
+ * @static
+ * @param string $root name of the root tag
+ * @param string $uri uri of the doctype definition (or array with uri and public id)
+ * @param string $internalDtd internal dtd entries
+ * @return string $decl doctype declaration
+ * @since 0.2
+ */
+ static function getDocTypeDeclaration($root, $uri = null, $internalDtd = null)
+ {
+ if (is_array($uri)) {
+ $ref = sprintf( ' PUBLIC "%s" "%s"', $uri["id"], $uri["uri"] );
+ } elseif (!empty($uri)) {
+ $ref = sprintf( ' SYSTEM "%s"', $uri );
+ } else {
+ $ref = "";
+ }
+
+ if (empty($internalDtd)) {
+ return sprintf("<!DOCTYPE %s%s>", $root, $ref);
+ } else {
+ return sprintf("<!DOCTYPE %s%s [\n%s\n]>", $root, $ref, $internalDtd);
+ }
+ }
+
+ /**
+ * create string representation of an attribute list
+ *
+ * <code>
+ * require_once 'XML/Util.php';
+ *
+ * // build an attribute string
+ * $att = array(
+ * "foo" => "bar",
+ * "argh" => "tomato"
+ * );
+ *
+ * $attList = XML_Util::attributesToString($att);
+ * </code>
+ *
+ * @access public
+ * @static
+ * @param array $attributes attribute array
+ * @param boolean|array $sort sort attribute list alphabetically, may also be an assoc array containing the keys 'sort', 'multiline', 'indent', 'linebreak' and 'entities'
+ * @param boolean $multiline use linebreaks, if more than one attribute is given
+ * @param string $indent string used for indentation of multiline attributes
+ * @param string $linebreak string used for linebreaks of multiline attributes
+ * @param integer $entities setting for entities in attribute values (one of XML_UTIL_ENTITIES_NONE, XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML)
+ * @return string string representation of the attributes
+ * @uses XML_Util::replaceEntities() to replace XML entities in attribute values
+ * @todo allow sort also to be an options array
+ */
+ static function attributesToString($attributes, $sort = true, $multiline = false, $indent = ' ', $linebreak = "\n", $entities = XML_UTIL_ENTITIES_XML)
+ {
+ /**
+ * second parameter may be an array
+ */
+ if (is_array($sort)) {
+ if (isset($sort['multiline'])) {
+ $multiline = $sort['multiline'];
+ }
+ if (isset($sort['indent'])) {
+ $indent = $sort['indent'];
+ }
+ if (isset($sort['linebreak'])) {
+ $multiline = $sort['linebreak'];
+ }
+ if (isset($sort['entities'])) {
+ $entities = $sort['entities'];
+ }
+ if (isset($sort['sort'])) {
+ $sort = $sort['sort'];
+ } else {
+ $sort = true;
+ }
+ }
+ $string = '';
+ if (is_array($attributes) && !empty($attributes)) {
+ if ($sort) {
+ ksort($attributes);
+ }
+ if( !$multiline || count($attributes) == 1) {
+ foreach ($attributes as $key => $value) {
+ if ($entities != XML_UTIL_ENTITIES_NONE) {
+ if ($entities === XML_UTIL_CDATA_SECTION) {
+ $entities = XML_UTIL_ENTITIES_XML;
+ }
+ $value = XML_Util::replaceEntities($value, $entities);
+ }
+ $string .= ' '.$key.'="'.$value.'"';
+ }
+ } else {
+ $first = true;
+ foreach ($attributes as $key => $value) {
+ if ($entities != XML_UTIL_ENTITIES_NONE) {
+ $value = XML_Util::replaceEntities($value, $entities);
+ }
+ if ($first) {
+ $string .= " ".$key.'="'.$value.'"';
+ $first = false;
+ } else {
+ $string .= $linebreak.$indent.$key.'="'.$value.'"';
+ }
+ }
+ }
+ }
+ return $string;
+ }
+
+ /**
+ * Collapses empty tags.
+ *
+ * @access public
+ * @static
+ * @param string $xml XML
+ * @param integer $mode Whether to collapse all empty tags (XML_UTIL_COLLAPSE_ALL) or only XHTML (XML_UTIL_COLLAPSE_XHTML_ONLY) ones.
+ * @return string $xml XML
+ */
+ static function collapseEmptyTags($xml, $mode = XML_UTIL_COLLAPSE_ALL) {
+ if ($mode == XML_UTIL_COLLAPSE_XHTML_ONLY) {
+ return preg_replace(
+ '/<(area|base|br|col|hr|img|input|link|meta|param)([^>]*)><\/\\1>/s',
+ '<\\1\\2 />',
+ $xml
+ );
+ } else {
+ return preg_replace(
+ '/<(\w+)([^>]*)><\/\\1>/s',
+ '<\\1\\2 />',
+ $xml
+ );
+ }
+ }
+
+ /**
+ * create a tag
+ *
+ * This method will call XML_Util::createTagFromArray(), which
+ * is more flexible.
+ *
+ * <code>
+ * require_once 'XML/Util.php';
+ *
+ * // create an XML tag:
+ * $tag = XML_Util::createTag("myNs:myTag", array("foo" => "bar"), "This is inside the tag", "http://www.w3c.org/myNs#");
+ * </code>
+ *
+ * @access public
+ * @static
+ * @param string $qname qualified tagname (including namespace)
+ * @param array $attributes array containg attributes
+ * @param mixed $content
+ * @param string $namespaceUri URI of the namespace
+ * @param integer $replaceEntities whether to replace XML special chars in content, embedd it in a CData section or none of both
+ * @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line
+ * @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column)
+ * @param string $linebreak string used for linebreaks
+ * @param boolean $sortAttributes Whether to sort the attributes or not
+ * @return string $string XML tag
+ * @see XML_Util::createTagFromArray()
+ * @uses XML_Util::createTagFromArray() to create the tag
+ */
+ static function createTag($qname, $attributes = array(), $content = null, $namespaceUri = null, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n", $sortAttributes = true)
+ {
+ $tag = array(
+ "qname" => $qname,
+ "attributes" => $attributes
+ );
+
+ // add tag content
+ if ($content !== null) {
+ $tag["content"] = $content;
+ }
+
+ // add namespace Uri
+ if ($namespaceUri !== null) {
+ $tag["namespaceUri"] = $namespaceUri;
+ }
+
+ return XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $linebreak, $sortAttributes);
+ }
+
+ /**
+ * create a tag from an array
+ * this method awaits an array in the following format
+ * <pre>
+ * array(
+ * "qname" => $qname // qualified name of the tag
+ * "namespace" => $namespace // namespace prefix (optional, if qname is specified or no namespace)
+ * "localpart" => $localpart, // local part of the tagname (optional, if qname is specified)
+ * "attributes" => array(), // array containing all attributes (optional)
+ * "content" => $content, // tag content (optional)
+ * "namespaceUri" => $namespaceUri // namespaceUri for the given namespace (optional)
+ * )
+ * </pre>
+ *
+ * <code>
+ * require_once 'XML/Util.php';
+ *
+ * $tag = array(
+ * "qname" => "foo:bar",
+ * "namespaceUri" => "http://foo.com",
+ * "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ),
+ * "content" => "I'm inside the tag",
+ * );
+ * // creating a tag with qualified name and namespaceUri
+ * $string = XML_Util::createTagFromArray($tag);
+ * </code>
+ *
+ * @access public
+ * @static
+ * @param array $tag tag definition
+ * @param integer $replaceEntities whether to replace XML special chars in content, embedd it in a CData section or none of both
+ * @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line
+ * @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column)
+ * @param string $linebreak string used for linebreaks
+ * @param boolean $sortAttributes Whether to sort the attributes or not
+ * @return string $string XML tag
+ * @see XML_Util::createTag()
+ * @uses XML_Util::attributesToString() to serialize the attributes of the tag
+ * @uses XML_Util::splitQualifiedName() to get local part and namespace of a qualified name
+ */
+ static function createTagFromArray($tag, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n", $sortAttributes = true)
+ {
+ if (isset($tag['content']) && !is_scalar($tag['content'])) {
+ return XML_Util::raiseError( 'Supplied non-scalar value as tag content', XML_UTIL_ERROR_NON_SCALAR_CONTENT );
+ }
+
+ if (!isset($tag['qname']) && !isset($tag['localPart'])) {
+ return XML_Util::raiseError( 'You must either supply a qualified name (qname) or local tag name (localPart).', XML_UTIL_ERROR_NO_TAG_NAME );
+ }
+
+ // if no attributes hav been set, use empty attributes
+ if (!isset($tag["attributes"]) || !is_array($tag["attributes"])) {
+ $tag["attributes"] = array();
+ }
+
+ if (isset($tag['namespaces'])) {
+ foreach ($tag['namespaces'] as $ns => $uri) {
+ $tag['attributes']['xmlns:'.$ns] = $uri;
+ }
+ }
+
+ // qualified name is not given
+ if (!isset($tag["qname"])) {
+ // check for namespace
+ if (isset($tag["namespace"]) && !empty($tag["namespace"])) {
+ $tag["qname"] = $tag["namespace"].":".$tag["localPart"];
+ } else {
+ $tag["qname"] = $tag["localPart"];
+ }
+ // namespace URI is set, but no namespace
+ } elseif (isset($tag["namespaceUri"]) && !isset($tag["namespace"])) {
+ $parts = XML_Util::splitQualifiedName($tag["qname"]);
+ $tag["localPart"] = $parts["localPart"];
+ if (isset($parts["namespace"])) {
+ $tag["namespace"] = $parts["namespace"];
+ }
+ }
+
+ if (isset($tag["namespaceUri"]) && !empty($tag["namespaceUri"])) {
+ // is a namespace given
+ if (isset($tag["namespace"]) && !empty($tag["namespace"])) {
+ $tag["attributes"]["xmlns:".$tag["namespace"]] = $tag["namespaceUri"];
+ } else {
+ // define this Uri as the default namespace
+ $tag["attributes"]["xmlns"] = $tag["namespaceUri"];
+ }
+ }
+
+ // check for multiline attributes
+ if ($multiline === true) {
+ if ($indent === "_auto") {
+ $indent = str_repeat(" ", (strlen($tag["qname"])+2));
+ }
+ }
+
+ // create attribute list
+ $attList = XML_Util::attributesToString($tag['attributes'], $sortAttributes, $multiline, $indent, $linebreak, $replaceEntities );
+ if (!isset($tag['content']) || (string)$tag['content'] == '') {
+ $tag = sprintf('<%s%s />', $tag['qname'], $attList);
+ } else {
+ switch ($replaceEntities) {
+ case XML_UTIL_ENTITIES_NONE:
+ break;
+ case XML_UTIL_CDATA_SECTION:
+ $tag['content'] = XML_Util::createCDataSection($tag['content']);
+ break;
+ default:
+ $tag['content'] = XML_Util::replaceEntities($tag['content'], $replaceEntities);
+ break;
+ }
+ $tag = sprintf('<%s%s>%s</%s>', $tag['qname'], $attList, $tag['content'], $tag['qname'] );
+ }
+ return $tag;
+ }
+
+ /**
+ * create a start element
+ *
+ * <code>
+ * require_once 'XML/Util.php';
+ *
+ * // create an XML start element:
+ * $tag = XML_Util::createStartElement("myNs:myTag", array("foo" => "bar") ,"http://www.w3c.org/myNs#");
+ * </code>
+ *
+ * @access public
+ * @static
+ * @param string $qname qualified tagname (including namespace)
+ * @param array $attributes array containg attributes
+ * @param string $namespaceUri URI of the namespace
+ * @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line
+ * @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column)
+ * @param string $linebreak string used for linebreaks
+ * @param boolean $sortAttributes Whether to sort the attributes or not
+ * @return string $string XML start element
+ * @see XML_Util::createEndElement(), XML_Util::createTag()
+ */
+ static function createStartElement($qname, $attributes = array(), $namespaceUri = null, $multiline = false, $indent = '_auto', $linebreak = "\n", $sortAttributes = true)
+ {
+ // if no attributes hav been set, use empty attributes
+ if (!isset($attributes) || !is_array($attributes)) {
+ $attributes = array();
+ }
+
+ if ($namespaceUri != null) {
+ $parts = XML_Util::splitQualifiedName($qname);
+ }
+
+ // check for multiline attributes
+ if ($multiline === true) {
+ if ($indent === "_auto") {
+ $indent = str_repeat(" ", (strlen($qname)+2));
+ }
+ }
+
+ if ($namespaceUri != null) {
+ // is a namespace given
+ if (isset($parts["namespace"]) && !empty($parts["namespace"])) {
+ $attributes["xmlns:".$parts["namespace"]] = $namespaceUri;
+ } else {
+ // define this Uri as the default namespace
+ $attributes["xmlns"] = $namespaceUri;
+ }
+ }
+
+ // create attribute list
+ $attList = XML_Util::attributesToString($attributes, $sortAttributes, $multiline, $indent, $linebreak);
+ $element = sprintf("<%s%s>", $qname, $attList);
+ return $element;
+ }
+
+ /**
+ * create an end element
+ *
+ * <code>
+ * require_once 'XML/Util.php';
+ *
+ * // create an XML start element:
+ * $tag = XML_Util::createEndElement("myNs:myTag");
+ * </code>
+ *
+ * @access public
+ * @static
+ * @param string $qname qualified tagname (including namespace)
+ * @return string $string XML end element
+ * @see XML_Util::createStartElement(), XML_Util::createTag()
+ */
+ static function createEndElement($qname)
+ {
+ $element = sprintf("</%s>", $qname);
+ return $element;
+ }
+
+ /**
+ * create an XML comment
+ *
+ * <code>
+ * require_once 'XML/Util.php';
+ *
+ * // create an XML start element:
+ * $tag = XML_Util::createComment("I am a comment");
+ * </code>
+ *
+ * @access public
+ * @static
+ * @param string $content content of the comment
+ * @return string $comment XML comment
+ */
+ static function createComment($content)
+ {
+ $comment = sprintf("<!-- %s -->", $content);
+ return $comment;
+ }
+
+ /**
+ * create a CData section
+ *
+ * <code>
+ * require_once 'XML/Util.php';
+ *
+ * // create a CData section
+ * $tag = XML_Util::createCDataSection("I am content.");
+ * </code>
+ *
+ * @access public
+ * @static
+ * @param string $data data of the CData section
+ * @return string $string CData section with content
+ */
+ static function createCDataSection($data)
+ {
+ return sprintf("<![CDATA[%s]]>", $data);
+ }
+
+ /**
+ * split qualified name and return namespace and local part
+ *
+ * <code>
+ * require_once 'XML/Util.php';
+ *
+ * // split qualified tag
+ * $parts = XML_Util::splitQualifiedName("xslt:stylesheet");
+ * </code>
+ * the returned array will contain two elements:
+ * <pre>
+ * array(
+ * "namespace" => "xslt",
+ * "localPart" => "stylesheet"
+ * );
+ * </pre>
+ *
+ * @access public
+ * @static
+ * @param string $qname qualified tag name
+ * @param string $defaultNs default namespace (optional)
+ * @return array $parts array containing namespace and local part
+ */
+ static function splitQualifiedName($qname, $defaultNs = null)
+ {
+ if (strstr($qname, ':')) {
+ $tmp = explode(":", $qname);
+ return array(
+ "namespace" => $tmp[0],
+ "localPart" => $tmp[1]
+ );
+ }
+ return array(
+ "namespace" => $defaultNs,
+ "localPart" => $qname
+ );
+ }
+
+ /**
+ * check, whether string is valid XML name
+ *
+ * <p>XML names are used for tagname, attribute names and various
+ * other, lesser known entities.</p>
+ * <p>An XML name may only consist of alphanumeric characters,
+ * dashes, undescores and periods, and has to start with a letter
+ * or an underscore.
+ * </p>
+ *
+ * <code>
+ * require_once 'XML/Util.php';
+ *
+ * // verify tag name
+ * $result = XML_Util::isValidName("invalidTag?");
+ * if (XML_Util::isError($result)) {
+ * print "Invalid XML name: " . $result->getMessage();
+ * }
+ * </code>
+ *
+ * @access public
+ * @static
+ * @param string $string string that should be checked
+ * @return mixed $valid true, if string is a valid XML name, PEAR error otherwise
+ * @todo support for other charsets
+ */
+ static function isValidName($string)
+ {
+ // check for invalid chars
+ if (!preg_match('/^[[:alpha:]_]$/', $string{0})) {
+ return XML_Util::raiseError('XML names may only start with letter or underscore', XML_UTIL_ERROR_INVALID_START);
+ }
+
+ // check for invalid chars
+ if (!preg_match('/^([[:alpha:]_]([[:alnum:]\-\.]*)?:)?[[:alpha:]_]([[:alnum:]\_\-\.]+)?$/', $string)) {
+ return XML_Util::raiseError('XML names may only contain alphanumeric chars, period, hyphen, colon and underscores', XML_UTIL_ERROR_INVALID_CHARS);
+ }
+ // XML name is valid
+ return true;
+ }
+
+ /**
+ * replacement for XML_Util::raiseError
+ *
+ * Avoids the necessity to always require
+ * PEAR.php
+ *
+ * @access public
+ * @param string error message
+ * @param integer error code
+ * @return object PEAR_Error
+ */
+ static function raiseError($msg, $code)
+ {
+ require_once 'PEAR.php';
+ return PEAR::raiseError($msg, $code);
+ }
+}
+?> \ No newline at end of file