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

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