XML_Serializer
[ class tree: XML_Serializer ] [ index: XML_Serializer ] [ all elements ]

Source for file Serializer.php

Documentation is available at Serializer.php

  1. <?PHP
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2002 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Stephan Schmidt <schst@php-tools.net>                       |
  17. // +----------------------------------------------------------------------+
  18. //
  19. //    $Id: Serializer.php,v 1.22 2004/08/24 13:28:38 schst Exp $
  20.  
  21. /**
  22.  * uses PEAR error management
  23.  */
  24. require_once 'PEAR.php';
  25.  
  26. /**
  27.  * uses XML_Util to create XML tags
  28.  */
  29. require_once 'XML/Util.php';
  30.  
  31. /**
  32.  * error code for no serialization done
  33.  */
  34. define('XML_SERIALIZER_ERROR_NO_SERIALIZATION'51);
  35.  
  36. /**
  37.  * XML_Serializer
  38.  * class that serializes various structures into an XML document
  39.  *
  40.  * this class can be used in two modes:
  41.  *
  42.  *  1. create an XML document from an array or object that is processed by other
  43.  *    applications. That means, you can create a RDF document from an array in the
  44.  *    following format:
  45.  *
  46.  *    $data = array(
  47.  *              'channel' => array(
  48.  *                            'title' => 'Example RDF channel',
  49.  *                            'link'  => 'http://www.php-tools.de',
  50.  *                            'image' => array(
  51.  *                                        'title' => 'Example image',
  52.  *                                        'url'   => 'http://www.php-tools.de/image.gif',
  53.  *                                        'link'  => 'http://www.php-tools.de'
  54.  *                                           ),
  55.  *                            array(
  56.  *                                 'title' => 'Example item',
  57.  *                                 'link'  => 'http://example.com'
  58.  *                                 ),
  59.  *                            array(
  60.  *                                 'title' => 'Another Example item',
  61.  *                                 'link'  => 'http://example.org'
  62.  *                                 )
  63.  *                              )
  64.  *             );
  65.  *
  66.  *   to create a RDF document from this array do the following:
  67.  *
  68.  *   require_once 'XML/Serializer.php';
  69.  *
  70.  *   $options = array(
  71.  *                     'indent'         => "\t",        // indent with tabs
  72.  *                     'linebreak'      => "\n",        // use UNIX line breaks
  73.  *                     'rootName'       => 'rdf:RDF',   // root tag
  74.  *                     'defaultTagName' => 'item'       // tag for values with numeric keys
  75.  *   );
  76.  *
  77.  *   $serializer = new XML_Serializer($options);
  78.  *   $rdf        = $serializer->serialize($data);
  79.  *
  80.  * You will get a complete XML document that can be processed like any RDF document.
  81.  *
  82.  *
  83.  * 2. this classes can be used to serialize any data structure in a way that it can
  84.  *    later be unserialized again.
  85.  *    XML_Serializer will store the type of the value and additional meta information
  86.  *    in attributes of the surrounding tag. This meat information can later be used
  87.  *    to restore the original data structure in PHP. If you want XML_Serializer
  88.  *    to add meta information to the tags, add
  89.  *
  90.  *      'typeHints' => true
  91.  *
  92.  *    to the options array in the constructor.
  93.  *
  94.  *    Future versions of this package will include an XML_Unserializer, that does
  95.  *    the unserialization automatically for you.
  96.  *
  97.  * @category XML
  98.  * @package  XML_Serializer
  99.  * @version  0.9.1
  100.  * @author   Stephan Schmidt <schst@php.net>
  101.  * @uses     XML_Util
  102.  */
  103. class XML_Serializer extends PEAR
  104. {
  105.    /**
  106.     * default options for the serialization
  107.     * @access private
  108.     * @var array $_defaultOptions 
  109.     */
  110.     var $_defaultOptions = array(
  111.                          'indent'             => '',                    // string used for indentation
  112.                          'linebreak'          => '\n',                  // string used for newlines
  113.                          'typeHints'          => false,                 // automatically add type hin attributes
  114.                          'addDecl'            => false,                 // add an XML declaration
  115.                          'defaultTagName'     => 'XML_Serializer_Tag',  // tag used for indexed arrays or invalid names
  116.                          'classAsTagName'     => false,                 // use classname for objects in indexed arrays
  117.                          'keyAttribute'       => '_originalKey',        // attribute where original key is stored
  118.                          'typeAttribute'      => '_type',               // attribute for type (only if typeHints => true)
  119.                          'classAttribute'     => '_class',              // attribute for class of objects (only if typeHints => true)
  120.                          'scalarAsAttributes' => false,                 // scalar values (strings, ints,..) will be serialized as attribute
  121.                          'prependAttributes'  => '',                    // prepend string for attributes
  122.                          'indentAttributes'   => false,                 // indent the attributes, if set to '_auto', it will indent attributes so they all start at the same column
  123.                          'mode'               => 'default',             // use 'simplexml' to use parent name as tagname if transforming an indexed array
  124.                          'addDoctype'         => false,                 // add a doctype declaration
  125.                          'doctype'            => null,                  // supply a string or an array with id and uri ({@see XML_Util::getDoctypeDeclaration()}
  126.                          'rootName'           => null,                  // name of the root tag
  127.                          'rootAttributes'     => array(),               // attributes of the root tag
  128.                          'attributesArray'    => null,                  // all values in this key will be treated as attributes
  129.                          'contentName'        => null                   // this value will be used directly as content, instead of creating a new tag, may only be used in conjuction with attributesArray
  130.                         );
  131.  
  132.    /**
  133.     * options for the serialization
  134.     * @access private
  135.     * @var array $options 
  136.     */
  137.     var $options = array();
  138.  
  139.    /**
  140.     * current tag depth
  141.     * @var integer $_tagDepth 
  142.     */
  143.     var $_tagDepth = 0;
  144.  
  145.    /**
  146.     * serilialized representation of the data
  147.     * @var string $_serializedData 
  148.     */
  149.     var $_serializedData = null;
  150.     
  151.    /**
  152.     * constructor
  153.     *
  154.     * @access   public
  155.     * @param    mixed   $options    array containing options for the serialization
  156.     */
  157.     function XML_Serializer$options = null )
  158.     {
  159.         $this->PEAR();
  160.         if (is_array($options)) {
  161.             $this->options array_merge($this->_defaultOptions$options);
  162.         else {
  163.             $this->options $this->_defaultOptions;
  164.         }
  165.     }
  166.  
  167.    /**
  168.     * return API version
  169.     *
  170.     * @access   public
  171.     * @static
  172.     * @return   string  $version API version
  173.     */
  174.     function apiVersion()
  175.     {
  176.         return '0.9';
  177.     }
  178.  
  179.    /**
  180.     * reset all options to default options
  181.     *
  182.     * @access   public
  183.     * @see      setOption(), XML_Unserializer()
  184.     */
  185.     function resetOptions()
  186.     {
  187.         $this->options $this->_defaultOptions;
  188.     }
  189.  
  190.    /**
  191.     * set an option
  192.     *
  193.     * You can use this method if you do not want to set all options in the constructor
  194.     *
  195.     * @access   public
  196.     * @see      resetOption(), XML_Serializer()
  197.     */
  198.     function setOption($name$value)
  199.     {
  200.         $this->options[$name$value;
  201.     }
  202.     
  203.    /**
  204.     * sets several options at once
  205.     *
  206.     * You can use this method if you do not want to set all options in the constructor
  207.     *
  208.     * @access   public
  209.     * @see      resetOption(), XML_Unserializer(), setOption()
  210.     */
  211.     function setOptions($options)
  212.     {
  213.         $this->options array_merge($this->options$options);
  214.     }
  215.  
  216.    /**
  217.     * serialize data
  218.     *
  219.     * @access   public
  220.     * @param    mixed    $data data to serialize
  221.     * @return   boolean  true on success, pear error on failure
  222.     */
  223.     function serialize($data$options = null)
  224.     {
  225.         // if options have been specified, use them instead
  226.         // of the previously defined ones
  227.         if (is_array($options)) {
  228.             $optionsBak $this->options;
  229.             if (isset($options['overrideOptions']&& $options['overrideOptions'== true{
  230.                 $this->options array_merge($this->_defaultOptions$options);
  231.             else {
  232.                 $this->options array_merge($this->options$options);
  233.             }
  234.         }
  235.         else {
  236.             $optionsBak = null;
  237.         }
  238.         
  239.         // maintain BC
  240.         if (isset($this->options['tagName'])) {
  241.             $this->options['rootName'$this->options['tagName'];
  242.         }
  243.         
  244.         //  start depth is zero
  245.         $this->_tagDepth = 0;
  246.  
  247.         $this->_serializedData '';
  248.         // serialize an array
  249.         if (is_array($data)) {
  250.             if (isset($this->options['rootName'])) {
  251.                 $tagName $this->options['rootName'];
  252.             else {
  253.                 $tagName 'array';
  254.             }
  255.  
  256.             $this->_serializedData .= $this->_serializeArray($data$tagName$this->options['rootAttributes']);
  257.         }
  258.         // serialize an object
  259.         elseif (is_object($data)) {
  260.             if (isset($this->options['rootName'])) {
  261.                 $tagName $this->options['rootName'];
  262.             else {
  263.                 $tagName get_class($data);
  264.             }
  265.             $this->_serializedData .= $this->_serializeObject($data$tagName$this->options['rootAttributes']);
  266.         }
  267.         
  268.         // add doctype declaration
  269.         if ($this->options['addDoctype'=== true{
  270.             $this->_serializedData = XML_Util::getDoctypeDeclaration($tagName$this->options['doctype'])
  271.                                    . $this->options['linebreak']
  272.                                    . $this->_serializedData;
  273.         }
  274.  
  275.         //  build xml declaration
  276.         if ($this->options['addDecl']{
  277.             $atts = array();
  278.             if (isset($this->options['encoding']) ) {
  279.                 $encoding $this->options['encoding'];
  280.             else {
  281.                 $encoding = null;
  282.             }
  283.             $this->_serializedData = XML_Util::getXMLDeclaration('1.0'$encoding)
  284.                                    . $this->options['linebreak']
  285.                                    . $this->_serializedData;
  286.         }
  287.         
  288.         
  289.         if ($optionsBak !== null{
  290.             $this->options $optionsBak;
  291.         }
  292.         
  293.         return  true;
  294.     }
  295.  
  296.    /**
  297.     * get the result of the serialization
  298.     *
  299.     * @access public
  300.     * @return string serialized XML
  301.     */
  302.     function getSerializedData()
  303.     {
  304.         if ($this->_serializedData == null {
  305.             return  $this->raiseError('No serialized data available. Use XML_Serializer::serialize() first.'XML_SERIALIZER_ERROR_NO_SERIALIZATION);
  306.         }
  307.         return $this->_serializedData;
  308.     }
  309.     
  310.    /**
  311.     * serialize any value
  312.     *
  313.     * This method checks for the type of the value and calls the appropriate method
  314.     *
  315.     * @access private
  316.     * @param  mixed     $value 
  317.     * @param  string    $tagName 
  318.     * @param  array     $attributes 
  319.     * @return string 
  320.     */
  321.     function _serializeValue($value$tagName = null$attributes = array())
  322.     {
  323.         if (is_array($value)) {
  324.             $xml $this->_serializeArray($value$tagName$attributes);
  325.         elseif (is_object($value)) {
  326.             $xml $this->_serializeObject($value$tagName);
  327.         else {
  328.             $tag = array(
  329.                           'qname'      => $tagName,
  330.                           'attributes' => $attributes,
  331.                           'content'    => $value
  332.                         );
  333.             $xml $this->_createXMLTag($tag);
  334.         }
  335.         return $xml;
  336.     }
  337.     
  338.    /**
  339.     * serialize an array
  340.     *
  341.     * @access   private
  342.     * @param    array   $array       array to serialize
  343.     * @param    string  $tagName     name of the root tag
  344.     * @param    array   $attributes  attributes for the root tag
  345.     * @return   string  $string      serialized data
  346.     * @uses     XML_Util::isValidName() to check, whether key has to be substituted
  347.     */
  348.     function _serializeArray(&$array$tagName = null$attributes = array())
  349.     {
  350.         $_content = null;
  351.         
  352.         /**
  353.          * check for special attributes
  354.          */
  355.         if ($this->options['attributesArray'!== null{
  356.             if (isset($array[$this->options['attributesArray']])) {
  357.                 $attributes $array[$this->options['attributesArray']];
  358.                 unset($array[$this->options['attributesArray']]);
  359.             }
  360.             /**
  361.              * check for special content
  362.              */
  363.             if ($this->options['contentName'!== null{
  364.                 if (isset($array[$this->options['contentName']])) {
  365.                     $_content $array[$this->options['contentName']];
  366.                     unset($array[$this->options['contentName']]);
  367.                 }
  368.             }
  369.         }
  370.  
  371.         /*
  372.         * if mode is set to simpleXML, check whether
  373.         * the array is associative or indexed
  374.         */
  375.         if (is_array($array&& $this->options['mode'== 'simplexml'{
  376.             $indexed = true;
  377.             foreach ($array as $key => $val{
  378.                 if (!is_int($key)) {
  379.                     $indexed = false;
  380.                     break;
  381.                 }
  382.             }
  383.  
  384.             if ($indexed && $this->options['mode'== 'simplexml'{
  385.                 $string '';
  386.                 foreach ($array as $key => $val{
  387.                     $string .= $this->_serializeValue$val$tagName$attributes);
  388.                     
  389.                     $string .= $this->options['linebreak'];
  390.                     //    do indentation
  391.                     if ($this->options['indent']!==null && $this->_tagDepth>0{
  392.                         $string .= str_repeat($this->options['indent']$this->_tagDepth);
  393.                     }
  394.                 }
  395.                 return rtrim($string);
  396.             }
  397.         }
  398.         
  399.         if ($this->options['scalarAsAttributes'=== true{
  400.             foreach ($array as $key => $value{
  401.                 if (is_scalar($value&& (XML_Util::isValidName($key=== true)) {
  402.                     unset($array[$key]);
  403.                     $attributes[$this->options['prependAttributes'].$key$value;
  404.                 }
  405.             }
  406.         }
  407.  
  408.         // check for empty array => create empty tag
  409.         if (empty($array)) {
  410.             $tag = array(
  411.                             'qname'      => $tagName,
  412.                             'content'    => $_content,
  413.                             'attributes' => $attributes
  414.                         );
  415.  
  416.         else {
  417.             $this->_tagDepth++;
  418.             $tmp $this->options['linebreak'];
  419.             foreach ($array as $key => $value{
  420.                 //    do indentation
  421.                 if ($this->options['indent']!==null && $this->_tagDepth>0{
  422.                     $tmp .= str_repeat($this->options['indent']$this->_tagDepth);
  423.                 }
  424.     
  425.                 //    copy key
  426.                 $origKey    =    $key;
  427.                 //    key cannot be used as tagname => use default tag
  428.                 $valid = XML_Util::isValidName($key);
  429.                 if (PEAR::isError($valid)) {
  430.                     if ($this->options['classAsTagName'&& is_object($value)) {
  431.                         $key get_class($value);
  432.                     else {
  433.                         $key $this->options['defaultTagName'];
  434.                     }
  435.                     }
  436.                 $atts = array();
  437.                 if ($this->options['typeHints'=== true{
  438.                     $atts[$this->options['typeAttribute']] gettype($value);
  439.                     if ($key !== $origKey{
  440.                         $atts[$this->options['keyAttribute']] = (string)$origKey;
  441.                     }
  442.     
  443.                 }
  444.                 
  445.                 $tmp .= $this->_createXMLTag(array(
  446.                                                     'qname'      => $key,
  447.                                                     'attributes' => $atts,
  448.                                                     'content'    => $value )
  449.                                             );
  450.                 $tmp .= $this->options['linebreak'];
  451.             }
  452.             
  453.             $this->_tagDepth--;
  454.             if ($this->options['indent']!==null && $this->_tagDepth>0{
  455.                 $tmp .= str_repeat($this->options['indent']$this->_tagDepth);
  456.             }
  457.     
  458.             if (trim($tmp=== ''{
  459.                 $tmp = null;
  460.             }
  461.             
  462.             $tag = array(
  463.                             'qname'      => $tagName,
  464.                             'content'    => $tmp,
  465.                             'attributes' => $attributes
  466.                         );
  467.         }
  468.         if ($this->options['typeHints'=== true{
  469.             if (!isset($tag['attributes'][$this->options['typeAttribute']])) {
  470.                 $tag['attributes'][$this->options['typeAttribute']] 'array';
  471.             }
  472.         }
  473.  
  474.         $string $this->_createXMLTag($tagfalse);
  475.         return $string;
  476.     }
  477.  
  478.    /**
  479.     * serialize an object
  480.     *
  481.     * @access   private
  482.     * @param    object  $object object to serialize
  483.     * @return   string  $string serialized data
  484.     */
  485.     function _serializeObject(&$object$tagName = null$attributes = array())
  486.     {
  487.         //  check for magic function
  488.         if (method_exists($object'__sleep')) {
  489.             $object->__sleep();
  490.         }
  491.  
  492.         $tmp $this->options['linebreak'];
  493.         $properties get_object_vars($object);
  494.         if (empty($tagName)) {
  495.             $tagName get_class($object);
  496.         }
  497.         
  498.         // typehints activated?
  499.         if ($this->options['typeHints'=== true{
  500.             $attributes[$this->options['typeAttribute']]  'object';
  501.             $attributes[$this->options['classAttribute']] =  get_class($object);
  502.         }
  503.         
  504.         $string $this->_serializeArray($properties$tagName$attributes);
  505.         return $string;
  506.     }
  507.   
  508.    /**
  509.     * create a tag from an array
  510.     * this method awaits an array in the following format
  511.     * array(
  512.     *       'qname'        => $tagName,
  513.     *       'attributes'   => array(),
  514.     *       'content'      => $content,      // optional
  515.     *       'namespace'    => $namespace     // optional
  516.     *       'namespaceUri' => $namespaceUri  // optional
  517.     *   )
  518.     *
  519.     * @access   private
  520.     * @param    array   $tag tag definition
  521.     * @param    boolean $replaceEntities whether to replace XML entities in content or not
  522.     * @return   string  $string XML tag
  523.     */
  524.     function _createXMLTag$tag$replaceEntities = true )
  525.     {
  526.         if ($this->options['indentAttributes'!== false{
  527.             $multiline = true;
  528.             $indent    str_repeat($this->options['indent']$this->_tagDepth);
  529.  
  530.             if ($this->options['indentAttributes'== '_auto'{
  531.                 $indent .= str_repeat(' '(strlen($tag['qname'])+2));
  532.  
  533.             else {
  534.                 $indent .= $this->options['indentAttributes'];
  535.             }
  536.         else {
  537.             $multiline = false;
  538.             $indent    = false;
  539.         }
  540.     
  541.         if (is_array($tag['content'])) {
  542.             if (empty($tag['content'])) {
  543.                 $tag['content'=   '';
  544.             }
  545.         elseif(is_scalar($tag['content']&& (string)$tag['content'== ''{
  546.             $tag['content'=   '';
  547.         }
  548.     
  549.         if (is_scalar($tag['content']|| is_null($tag['content'])) {
  550.             $tag = XML_Util::createTagFromArray($tag$replaceEntities$multiline$indent$this->options['linebreak']);
  551.         elseif (is_array($tag['content'])) {
  552.             $tag    =   $this->_serializeArray($tag['content']$tag['qname']$tag['attributes']);
  553.         elseif (is_object($tag['content'])) {
  554.             $tag    =   $this->_serializeObject($tag['content']$tag['qname']$tag['attributes']);
  555.         elseif (is_resource($tag['content'])) {
  556.             settype($tag['content']'string');
  557.             $tag    =   XML_Util::createTagFromArray($tag$replaceEntities);
  558.         }
  559.         return  $tag;
  560.     }
  561. }
  562. ?>

Documentation generated on Mon, 11 Mar 2019 13:55:03 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.