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.15 2004/04/23 17:17:04 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.                          "keyAttribute"       => "_originalKey",        // attribute where original key is stored
  117.                          "typeAttribute"      => "_type",               // attribute for type (only if typeHints => true)
  118.                          "classAttribute"     => "_class",              // attribute for class of objects (only if typeHints => true)
  119.                          "scalarAsAttributes" => false,                 // scalar values (strings, ints,..) will be serialized as attribute
  120.                          "prependAttributes"  => "",                    // prepend string for attributes
  121.                          "indentAttributes"   => false,                 // indent the attributes, if set to '_auto', it will indent attributes so they all start at the same column
  122.                          "mode"               => 'default',             // use 'simplexml' to use parent name as tagname if transforming an indexed array
  123.                          "addDoctype"         => false,                 // add a doctype declaration
  124.                          "doctype"            => null,                  // supply a string or an array with id and uri ({@see XML_Util::getDoctypeDeclaration()}
  125.                          "rootName"           => null,                  // name of the root tag
  126.                          "rootAttributes"     => array()                // attributes of the root tag
  127.                         );
  128.  
  129.    /**
  130.     * options for the serialization
  131.     * @access private
  132.     * @var array $options 
  133.     */
  134.     var $options = array();
  135.  
  136.    /**
  137.     * current tag depth
  138.     * @var integer $_tagDepth 
  139.     */
  140.     var $_tagDepth = 0;
  141.  
  142.    /**
  143.     * serilialized representation of the data
  144.     * @var string $_serializedData 
  145.     */
  146.     var $_serializedData = null;
  147.     
  148.    /**
  149.     * constructor
  150.     *
  151.     * @access   public
  152.     * @param    mixed   $options    array containing options for the serialization
  153.     */
  154.     function XML_Serializer$options = null )
  155.     {
  156.         $this->PEAR();
  157.         if (is_array($options)) {
  158.             $this->options array_merge($this->_defaultOptions$options);
  159.         else {
  160.             $this->options $this->_defaultOptions;
  161.         }
  162.     }
  163.  
  164.    /**
  165.     * return API version
  166.     *
  167.     * @access   public
  168.     * @static
  169.     * @return   string  $version API version
  170.     */
  171.     function apiVersion()
  172.     {
  173.         return "0.9";
  174.     }
  175.  
  176.    /**
  177.     * reset all options to default options
  178.     *
  179.     * @access   public
  180.     * @see      setOption(), XML_Unserializer()
  181.     */
  182.     function resetOptions()
  183.     {
  184.         $this->options $this->_defaultOptions;
  185.     }
  186.  
  187.    /**
  188.     * set an option
  189.     *
  190.     * You can use this method if you do not want to set all options in the constructor
  191.     *
  192.     * @access   public
  193.     * @see      resetOption(), XML_Serializer()
  194.     */
  195.     function setOption($name$value)
  196.     {
  197.         $this->options[$name$value;
  198.     }
  199.     
  200.    /**
  201.     * serialize data
  202.     *
  203.     * @access   public
  204.     * @param    mixed    $data data to serialize
  205.     * @return   boolean  true on success, pear error on failure
  206.     */
  207.     function serialize($data$options = null)
  208.     {
  209.         // if options have been specified, use them instead
  210.         // of the previously defined ones
  211.         if (is_array($options)) {
  212.             $optionsBak $this->options;
  213.             if (isset($options["overrideOptions"]&& $options["overrideOptions"== true{
  214.                 $this->options array_merge($this->_defaultOptions$options);
  215.             else {
  216.                 $this->options array_merge($this->options$options);
  217.             }
  218.         }
  219.         else {
  220.             $optionsBak = null;
  221.         }
  222.         
  223.         // maintain BC
  224.         if (isset($this->options["tagName"])) {
  225.             $this->options["rootName"$this->options["tagName"];
  226.         }
  227.         
  228.         //  start depth is zero
  229.         $this->_tagDepth = 0;
  230.  
  231.         $this->_serializedData "";
  232.         // serialize an array
  233.         if (is_array($data)) {
  234.             if (isset($this->options["rootName"])) {
  235.                 $tagName $this->options["rootName"];
  236.             else {
  237.                 $tagName "array";
  238.             }
  239.  
  240.             $this->_serializedData .= $this->_serializeArray($data$tagName$this->options["rootAttributes"]);
  241.         }
  242.         // serialize an object
  243.         elseif (is_object($data)) {
  244.             if (isset($this->options["rootName"])) {
  245.                 $tagName $this->options["rootName"];
  246.             else {
  247.                 $tagName get_class($data);
  248.             }
  249.             $this->_serializedData .= $this->_serializeObject($data$tagName$this->options["rootAttributes"]);
  250.         }
  251.         
  252.         // add doctype declaration
  253.         if ($this->options["addDoctype"=== true{
  254.             $this->_serializedData = XML_Util::getDoctypeDeclaration($tagName$this->options["doctype"])
  255.                                    . $this->options["linebreak"]
  256.                                    . $this->_serializedData;
  257.         }
  258.  
  259.         //  build xml declaration
  260.         if ($this->options["addDecl"]{
  261.             $atts = array();
  262.             if (isset($this->options["encoding"]) ) {
  263.                 $encoding $this->options["encoding"];
  264.             else {
  265.                 $encoding = null;
  266.             }
  267.             $this->_serializedData = XML_Util::getXMLDeclaration("1.0"$encoding)
  268.                                    . $this->options["linebreak"]
  269.                                    . $this->_serializedData;
  270.         }
  271.         
  272.         
  273.         if ($optionsBak !== null{
  274.             $this->options $optionsBak;
  275.         }
  276.         
  277.         return  true;
  278.     }
  279.  
  280.    /**
  281.     *   get the result of the serialization
  282.     *
  283.     *   @access public
  284.     *   @return string  $serializedData
  285.     */
  286.         function getSerializedData()
  287.         {
  288.             if ($this->_serializedData == null {
  289.                 return  $this->raiseError("No serialized data available. Use XML_Serializer::serialize() first."XML_SERIALIZER_ERROR_NO_SERIALIZATION);
  290.             }
  291.             return $this->_serializedData;
  292.         }
  293.     
  294.    /**
  295.     * serialize any value
  296.     *
  297.     * This method checks for the type of the value and calls the appropriate method
  298.     *
  299.     * @access private
  300.     * @param  mixed     $value 
  301.     * @param  string    $tagName 
  302.     * @param  array     $attributes 
  303.     * @return string 
  304.     */
  305.     function _serializeValue($value$tagName = null$attributes = array())
  306.     {
  307.         if (is_array($value)) {
  308.             $xml $this->_serializeArray($value$tagName$attributes);
  309.         elseif (is_object($value)) {
  310.             $xml $this->_serializeObject($value$tagName);
  311.         else {
  312.             $tag = array(
  313.                           "qname"      => $tagName,
  314.                           "attributes" => $attributes,
  315.                           "content"    => $value
  316.                         );
  317.             $xml $this->_createXMLTag($tag);
  318.         }
  319.         return $xml;
  320.     }
  321.     
  322.    /**
  323.     * serialize an array
  324.     *
  325.     * @access   private
  326.     * @param    array   $array       array to serialize
  327.     * @param    string  $tagName     name of the root tag
  328.     * @param    array   $attributes  attributes for the root tag
  329.     * @return   string  $string      serialized data
  330.     * @uses     XML_Util::isValidName() to check, whether key has to be substituted
  331.     */
  332.     function _serializeArray(&$array$tagName = null$attributes = array())
  333.     {
  334.         /*
  335.         * if mode is set to simpleXML, check whether
  336.         * the array is associative or indexed
  337.         */
  338.         if (is_array($array&& $this->options["mode"== "simplexml"{
  339.             $indexed = true;
  340.             foreach ($array as $key => $val{
  341.                 if (!is_int($key)) {
  342.                     $indexed = false;
  343.                     break;
  344.                 }
  345.             }
  346.  
  347.             if ($indexed{
  348.                 $string "";
  349.                 foreach ($array as $key => $val{
  350.                     $string .= $this->_serializeValue$val$tagName$attributes);
  351.                     
  352.                     $string .= $this->options["linebreak"];
  353.                     //    do indentation
  354.                     if ($this->options["indent"]!==null && $this->_tagDepth>0{
  355.                         $string .= str_repeat($this->options["indent"]$this->_tagDepth);
  356.                     }
  357.                 }
  358.                 return rtrim($string);
  359.             }
  360.         }
  361.         
  362.         $this->_tagDepth++;
  363.  
  364.         if ($this->options["scalarAsAttributes"=== true{
  365.             foreach ($array as $key => $value{
  366.                 if (is_scalar($value&& (XML_Util::isValidName($key=== true)) {
  367.                     unset($array[$key]);
  368.                     $attributes[$this->options["prependAttributes"].$key$value;
  369.                 }
  370.             }
  371.         }
  372.  
  373.         // check for empty array => create empty tag
  374.         if (empty($array)) {
  375.         
  376.         }
  377.         
  378.         $tmp $this->options["linebreak"];
  379.         foreach ($array as $key => $value{
  380.             //    do indentation
  381.             if ($this->options["indent"]!==null && $this->_tagDepth>0{
  382.                 $tmp .= str_repeat($this->options["indent"]$this->_tagDepth);
  383.             }
  384.  
  385.             //    copy key
  386.             $origKey    =    $key;
  387.             //    key cannot be used as tagname => use default tag
  388.             $valid = XML_Util::isValidName($key);
  389.             if (PEAR::isError($valid)) {
  390.                 $key $this->options["defaultTagName"];
  391.                 }
  392.             $atts = array();
  393.             if ($this->options["typeHints"=== true{
  394.                 $atts[$this->options["typeAttribute"]] gettype($value);
  395.                 if ($key !== $origKey{
  396.                     $atts[$this->options["keyAttribute"]] = (string)$origKey;
  397.                 }
  398.  
  399.             }
  400.             
  401.             $tmp .= $this->_createXMLTag(array(
  402.                                                 "qname"      => $key,
  403.                                                 "attributes" => $atts,
  404.                                                 "content"    => $value )
  405.                                         );
  406.             $tmp .= $this->options["linebreak"];
  407.         }
  408.         
  409.         $this->_tagDepth--;
  410.         if ($this->options["indent"]!==null && $this->_tagDepth>0{
  411.             $tmp .= str_repeat($this->options["indent"]$this->_tagDepth);
  412.         }
  413.  
  414.         if (trim($tmp=== ''{
  415.             $tmp = null;
  416.         }
  417.         
  418.         $tag = array(
  419.                         "qname"      => $tagName,
  420.                         "content"    => $tmp,
  421.                         "attributes" => $attributes
  422.                     );
  423.         if ($this->options["typeHints"=== true{
  424.             if (!isset($tag["attributes"][$this->options["typeAttribute"]])) {
  425.                 $tag["attributes"][$this->options["typeAttribute"]] "array";
  426.             }
  427.         }
  428.  
  429.         $string $this->_createXMLTag($tagfalse);
  430.         return $string;
  431.     }
  432.  
  433.    /**
  434.     * serialize an object
  435.     *
  436.     * @access   private
  437.     * @param    object  $object object to serialize
  438.     * @return   string  $string serialized data
  439.     */
  440.     function _serializeObject(&$object$tagName = null$attributes = array())
  441.     {
  442.         //  check for magic function
  443.         if (method_exists($object"__sleep")) {
  444.             $object->__sleep();
  445.         }
  446.  
  447.         $tmp $this->options["linebreak"];
  448.         $properties get_object_vars($object);
  449.         if (empty($tagName)) {
  450.             $tagName get_class($object);
  451.         }
  452.         
  453.         // typehints activated?
  454.         if ($this->options["typeHints"=== true{
  455.             $attributes[$this->options["typeAttribute"]]  "object";
  456.             $attributes[$this->options["classAttribute"]] =  get_class($object);
  457.         }
  458.         
  459.         $string $this->_serializeArray($properties$tagName$attributes);
  460.         return $string;
  461.     }
  462.   
  463.    /**
  464.     * create a tag from an array
  465.     * this method awaits an array in the following format
  466.     * array(
  467.     *       "qname"        => $tagName,
  468.     *       "attributes"   => array(),
  469.     *       "content"      => $content,      // optional
  470.     *       "namespace"    => $namespace     // optional
  471.     *       "namespaceUri" => $namespaceUri  // optional
  472.     *   )
  473.     *
  474.     * @access   private
  475.     * @param    array   $tag tag definition
  476.     * @param    boolean $replaceEntities whether to replace XML entities in content or not
  477.     * @return   string  $string XML tag
  478.     */
  479.     function _createXMLTag$tag$replaceEntities = true )
  480.     {
  481.         if ($this->options["indentAttributes"!== false{
  482.             $multiline = true;
  483.             $indent    str_repeat($this->options["indent"]$this->_tagDepth);
  484.  
  485.             if ($this->options["indentAttributes"== "_auto"{
  486.                 $indent .= str_repeat(" "(strlen($tag["qname"])+2));
  487.  
  488.             else {
  489.                 $indent .= $this->options["indentAttributes"];
  490.             }
  491.         else {
  492.             $multiline = false;
  493.             $indent    = false;
  494.         }
  495.     
  496.         if ((string)$tag["content"== ''{
  497.             $tag["content"=   '';
  498.         }    
  499.     
  500.         if (is_scalar($tag["content"])) {
  501.             $tag = XML_Util::createTagFromArray($tag$replaceEntities$multiline$indent$this->options["linebreak"]);
  502.         elseif (is_array($tag["content"])) {
  503.             $tag    =   $this->_serializeArray($tag["content"]$tag["qname"]$tag["attributes"]);
  504.         elseif (is_object($tag["content"])) {
  505.             $tag    =   $this->_serializeObject($tag["content"]$tag["qname"]$tag["attributes"]);
  506.         elseif (is_resource($tag["content"])) {
  507.             settype($tag["content"]"string");
  508.             $tag    =   XML_Util::createTagFromArray($tag$replaceEntities);
  509.         }
  510.         return  $tag;
  511.     }
  512. }
  513. ?>

Documentation generated on Mon, 11 Mar 2019 10:15:35 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.