Code Coverage for /home/user/workspace/all/Pyrus/src/Pyrus/XMLWriter.php in Config/__get__set__unset__isset/test.phpt

Coverage: 73%

Aggregate Code Coverage for all tests

       1           : <?php
       2           : /**
       3           :  * PEAR2_Pyrus_XMLWriter
       4           :  *
       5           :  * PHP version 5
       6           :  *
       7           :  * @category  PEAR2
       8           :  * @package   PEAR2_Pyrus
       9           :  * @author    Greg Beaver <cellog@php.net>
      10           :  * @copyright 2008 The PEAR Group
      11           :  * @license   http://www.opensource.org/licenses/bsd-license.php New BSD License
      12           :  * @version   SVN: $Id$
      13           :  * @link      http://svn.pear.php.net/wsvn/PEARSVN/Pyrus/
      14           :  */
      15           : 
      16           : /**
      17           :  * Process an array, and serialize it into XML
      18           :  *
      19           :  * @category   PEAR2
      20           :  * @package    PEAR2_Pyrus
      21           :  * @subpackage XML
      22           :  * @author     Greg Beaver <cellog@php.net>
      23           :  * @copyright  2008 The PEAR Group
      24           :  * @license    http://www.opensource.org/licenses/bsd-license.php New BSD License
      25           :  * @link       http://svn.pear.php.net/wsvn/PEARSVN/Pyrus/
      26           :  */
      27           : class PEAR2_Pyrus_XMLWriter
      28         1 : {
      29           :     private $_array;
      30           :     private $_state;
      31           :     /**
      32           :      * @var XMLWriter
      33           :      */
      34           :     private $_writer;
      35           :     private $_iter;
      36           :     private $_tagStack;
      37           :     private $_namespaces;
      38           :     private $_tag;
      39           :     private $_expectedDepth;
      40           :     private $_type;
      41           :     private $_lastkey;
      42           :     
      43           :     /**
      44           :      * Construct a new xml writer object.
      45           :      * <code>
      46           :      * $xmlarray = array('channel'=>array('name'=>'pear2.php.net'));
      47           :      * $channel = new PEAR2_Pyrus_XMLWriter($xmlarray);
      48           :      * </code>
      49           :      * 
      50           :      * @param array $array Array representing the XML data.
      51           :      */
      52           :     function __construct(array $array)
      53           :     {
      54         1 :         if (count($array) != 1) {
      55           :             throw new PEAR2_Pyrus_XMLWriter_Exception('Cannot serialize array to' .
      56           :                 'XML, array must have exactly 1 element');
      57           :         }
      58         1 :         $this->_array  = $array;
      59         1 :         $this->_writer = new XMLWriter;
      60         1 :     }
      61           : 
      62           :     /**
      63           :      * Return the raw xml string representation.
      64           :      * 
      65           :      * @return string
      66           :      */
      67           :     function __toString()
      68           :     {
      69         1 :         $this->_writer->openMemory();
      70         1 :         return $this->_serialize();
      71           :     }
      72           : 
      73           :     function toFile($file)
      74           :     {
      75           :         $this->_writer->openUri($file);
      76           :         return $this->_serialize();
      77           :     }
      78           : 
      79           :     private function _pushState()
      80           :     {
      81         1 :         $this->_state[] = array($this->_type, $this->_tag, $this->_expectedDepth,
      82         1 :             $this->_namespaces);
      83         1 :     }
      84           : 
      85           :     private function _popState()
      86           :     {
      87         1 :         $save = $this->_namespaces;
      88           :         
      89         1 :         list($this->_type, $this->_tag, $this->_expectedDepth, $this->_namespaces) =
      90         1 :             array_pop($this->_state);
      91         1 :         foreach ($save as $ns) {
      92           :             if (!isset($this->_namespaces[$ns])) {
      93           :                 // all namespaces must exist - only overriding is allowed
      94           :                 $this->_namespaces = $save;
      95           :                 return;
      96           :             }
      97         1 :         }
      98         1 :     }
      99           : 
     100           :     private function _finish($key, $values)
     101           :     {
     102         1 :         switch ($this->_type) {
     103         1 :         case 'Attribs' :
     104         1 :                 $this->_popState();
     105         1 :                 return false;
     106         1 :         case 'Tag' :
     107         1 :                 $this->_popState();
     108         1 :                 $this->_writer->endElement();
     109         1 :                 return false;
     110         1 :         case 'Sibling' :
     111         1 :                 $this->_popState();
     112         1 :                 return false;
     113           :         }
     114           :     }
     115           : 
     116           :     private function _startElement($key, $values)
     117           :     {
     118           :         // new element
     119         1 :         if (strpos($key, ':')) {
     120           :             // namespaced element
     121           :             list($ns, $element) = explode(':', $key);
     122           :         }
     123         1 :         if (isset($element) && !isset($this->_namespaces[$ns])) {
     124           :             if (is_string($values)) {
     125           :                 if (strlen($values)) {
     126           :                     $this->_writer->writeElementNs($ns, $element, $this->_namespaces[$ns], $values);
     127           :                 } else {
     128           :                     $this->_writer->writeElementNs($ns, $element, $this->_namespaces[$ns]);
     129           :                 }
     130           :             } else {
     131           :                 $this->_writer->startElementNs($ns, $element, $this->_namespaces[$ns]);
     132           :             }
     133           :         } else {
     134         1 :             if (is_string($values) || is_int($values)) {
     135         1 :                 if (strlen($values)) {
     136         1 :                     $this->_writer->writeElement($key, $values);
     137         1 :                 } else {
     138           :                     $this->_writer->writeElement($key);
     139           :                 }
     140         1 :             } else {
     141         1 :                 $this->_writer->startElement($key);
     142           :             }
     143           :         }
     144         1 :     }
     145           : 
     146           :     /**
     147           :      * Handle an individual tag/element in the XML
     148           :      * 
     149           :      * @param mixed $key    The key for this element.
     150           :      * @param mixed $values The contents of this tag/element.
     151           :      */
     152           :     private function _handleTag($key, $values)
     153           :     {
     154         1 :         if (is_int($key)) {
     155         1 :             $this->_type          = 'Sibling';
     156         1 :             $this->_expectedDepth = $this->_iter->getDepth();
     157         1 :             $this->_pushState();
     158           :             // handle sibling tags
     159         1 :             return '_handleSibling';
     160           :         }
     161         1 :         $this->_startElement($key, $values);
     162         1 :         if (!is_string($values)) {
     163         1 :             $this->_expectedDepth = $this->_iter->getDepth();
     164         1 :             $this->_pushState();
     165         1 :             $this->_tag = $key;
     166         1 :         }
     167           :         // cycle to next key
     168         1 :         return false;
     169           :     }
     170           : 
     171           :     private function _handleSibling($key, $values)
     172           :     {
     173         1 :         if (is_int($key) && $this->_iter->getDepth() == $this->_expectedDepth) {
     174         1 :             if ($key) {
     175         1 :                 $this->_startElement($this->_tag, $values);
     176         1 :                 if (!is_string($values)) {
     177         1 :                     $this->_pushState();
     178         1 :                 }
     179         1 :             } else {
     180         1 :                 if (is_string($values)) {
     181           :                     $this->_writer->text($values);
     182           :                     $this->_writer->endElement();
     183           :                 }
     184           :             }
     185         1 :         }
     186         1 :         if (!is_string($values)) {
     187         1 :             $this->_type          = 'Tag';
     188         1 :             $this->_expectedDepth = $this->_iter->getDepth() + 1;
     189           :             // handle internal tags
     190         1 :         }
     191           :         // cycle to next key
     192         1 :         return false;
     193           :     }
     194           : 
     195           :     private function _handleAttribs($key, $values)
     196           :     {
     197           :         // xmlwriter converts these to &#10; and &#13;.  Bad.
     198         1 :         $values = str_replace(array("\n","\r"), array('', ''), $values);
     199         1 :         if (strpos($key, ':')) {
     200           :             // namespaced
     201           :             list($ns, $attr) = explode(':', $key);
     202           :             if ($ns == 'xmlns' || isset($this->_namespaces[$ns])) {
     203           :                 if ($ns == 'xmlns') {
     204           :                     // new namespace declaration
     205           :                     $this->_namespaces[$attr] = $values;
     206           :                 }
     207           :                 $this->_writer->writeAttribute($key, $values);
     208           :             } else {
     209           :                 $this->_writer->writeAttributeNS($ns, $attr, $values, $values);
     210           :             }
     211           :         } else { // default namespace
     212         1 :             $this->_writer->writeAttribute($key, $values);
     213           :         }
     214           :         // cycle to next key
     215         1 :         return false;
     216           :     }
     217           : 
     218           :     /**
     219           :      * @access private
     220           :      * 
     221           :      * @return bool
     222           :      */
     223           :     public static function _filter($a)
     224           :     {
     225         1 :         if ($a === false) {
     226         1 :             return false;
     227           :         }
     228         1 :         return true;
     229           :     }
     230           : 
     231           :     /**
     232           :      * Utilize custom serialization for XMLWriter object, to convert object
     233           :      * to SQL.
     234           :      * 
     235           :      * @return string
     236           :      */
     237           :     private function _serialize()
     238           :     {
     239         1 :         $this->_writer->setIndent(true);
     240         1 :         $this->_writer->setIndentString(' ');
     241         1 :         $this->_writer->startDocument('1.0', 'UTF-8');
     242         1 :         $this->_namespaces    = array();
     243         1 :         $this->_tagStack      = array();
     244         1 :         $this->_state         = array();
     245         1 :         $this->_type          = 'Tag';
     246         1 :         $this->_expectedDepth = 0;
     247         1 :         $this->_lastkey       = array();
     248         1 :         $lastdepth            = 0;
     249         1 :         foreach ($this->_iter = new RecursiveIteratorIterator(
     250         1 :                         new RecursiveArrayIterator($this->_array),
     251         1 :                         RecursiveIteratorIterator::SELF_FIRST) as $key => $values) {
     252         1 :             $depth = $this->_iter->getDepth();
     253         1 :             while ($depth < $this->_expectedDepth) {
     254           :                 // finished with this tag
     255         1 :                 $this->_finish($key, $values);
     256         1 :                 $lastdepth--;
     257         1 :             }
     258         1 :             if (isset($this->_lastkey[$depth]) && $key != $this->_lastkey[$depth]) {
     259         1 :                 while ($lastdepth > $depth) {
     260         1 :                     $this->_finish($key, $values);
     261         1 :                     $lastdepth--;
     262         1 :                 }
     263         1 :             }
     264         1 :             $this->_lastkey[$depth] = $key;
     265         1 :             foreach ($this->_lastkey as $d => &$k) {
     266         1 :                 if ($d > $depth) {
     267         1 :                     $k = false;
     268         1 :                 }
     269         1 :             }
     270         1 :             $this->_lastkey = array_filter($this->_lastkey,
     271         1 :                 array('PEAR2_Pyrus_XMLWriter', '_filter'));
     272         1 :             $lastdepth = $depth;
     273         1 :             if ($this->_type !== 'Attribs') {
     274         1 :                 if ($key === '_content') {
     275         1 :                     $this->_writer->text($values);
     276         1 :                     continue;
     277           :                 }
     278         1 :                 if ($key === 'attribs') {
     279           :                     // attributes are 1 depth higher
     280         1 :                     $this->_pushState();
     281         1 :                     $this->_expectedDepth = $this->_iter->getDepth() + 1;
     282         1 :                     $this->_type          = 'Attribs';
     283           :                     // cycle to first attribute
     284         1 :                     continue;
     285           :                 }
     286         1 :             }
     287         1 :             $next = '_handle' . $this->_type;
     288         1 :             while ($next = $this->{$next}($key, $values));
     289         1 :         }
     290         1 :         while ($lastdepth) {
     291         1 :             $this->_finish($key, $values);
     292         1 :             $lastdepth--;
     293         1 :         }
     294         1 :         $this->_writer->endDocument();
     295         1 :         return $this->_writer->flush();
     296           :     }
     297         1 : }