<?php
/************************************************************************
        class.XmlRenderer.php

Copyright (c) 2006, Tommy Gildseth
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice,
  this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.
* Neither the name of the me nor the names of its contributors
  may be used to endorse or promote products derived from this software
  without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
**************************************************************************/



/**
 * class XmlRenderer
 *
 */
class XmlRenderer {

  
/**
   * An array of the objects which should be rendered
   *
   * @access private
   */
  
private $objects;

  
/**
   * An array of nodes which should be added to the final XML
   *
   * The format of this variable is:
   * key = rootnode name
   * value = array(name => node name, value => node value, attribs => array())
   * Where attribs is an associative array of attribute name, attribute value pairs.
   * @access private
   */
  
private $nodes;

  
/**
   * Root node attributes.
   *
   * An associative array of root node attributes where the key is the attribute name
   * and the value is the attribute value.
   * @access private
   */
  
private $attributes;

  
/**
   * An array of arrays which should be rendered
   *
   * The array is an associative array, where the key becomes the root, and the value
   * which should be an array, becomes the sub nodes.
   * @access private
   */
  
private $arrays;

  
/**
   * Character encoding to use for output
   *
   * @access private
   */
  
private $encoding;


  
/**
   *
   *
   * @return void
   * @access public
   */
  
public function XmlRenderer$encoding 'UTF-8' ) {
    
$this->objects     = array();
    
$this->nodes       = array();
    
$this->attributes  = array();
    
$this->arrays      = array();
    
$this->encoding    $encoding;

  } 
// end of member function ObjectXMLRender

  /**
   * Register an Object for rendering as XML
   *
   * @param Renderable object
   * @return void
   * @access public
   */
  
public function renderObject(Renderable $object ) {
    
$this->objects[] = $object;
  } 
// end of member function renderObject

  /**
   * register an Array for rendering as XML
   *
   * @param string name
   * @param Array array
   * @return void
   * @access public
   */
  
public function renderArray$name,  $array ) {
    
$this->arrays[$name] = $array;
  } 
// end of member function renderArray

  /**
   *
   *
   * @param string name
   * @param string value
   * @return void
   * @access public
   */
  
public function rootAttrib$name,  $value ) {
    
$this->attributes[$name] = $value;
  } 
// end of member function rootAttrib

  /**
   *
   *
   * @param string root
   * @param string name
   * @param string value
   * @param Array attribs
   * @return void
   * @access public
   */
  
public function node$root,  $name,  $value '',  $attribs '' ) {
    if (!
is_array($attribs)) $attribs = array();
    
$this->nodes[$root][] = array('name' => $name'value' => $value'attribs' => $attribs);
  } 
// end of member function node

  /**
   *
   *
   * @param string root Name of root node
   * @return void
   * @access public
   */
  
public function renderComplete$root 'root' ) {
    
$xmlString '<'.$root.'>';
    
$xmlString .= $this->renderAllNodes($this->nodes);
    
$xmlString .= $this->renderAllObjects($this->objects);
    
$xmlString .= $this->renderAllArrays($this->arrays);
    
$xmlString '</'.$root.'>';
    return 
$xmlString;
  } 
// end of member function renderComplete


  /**
   *
   *
   * @param string root Name of root node
   * @return void
   * @access public
   */
  
private function renderAllNodes$allNodes ) {
    
$nodes '';
    foreach(
$allNodes as $nodeName => $children) {
      
$nodes .= '<'.$nodeName.'>';
      foreach(
$children as $node) {
        
$name $node['name'];
        
$nodeAttribs = array();
        foreach(
$node['attribs'] as $name => $value) {
          
$nodeAttribs[] = 'name="'.XmlRenderer::nodeValue($value).'"';
        }
        
$nodes .= '<'.$name.' '.implode(' '$nodeAttribs).'>';
        
$nodes .= XmlRenderer::nodeValue($node['value']);
        
$nodes .= '</'.$name.'>';
      }
      
$nodes .= '</'.$nodeName.'>';
    }
  }

  private function 
renderAllObjects$objects ) {
    
$nodes '';
    foreach(
$objects as $object) {
      
$nodes .= $this->renderObjectRecursive($object);
    }

    return 
$nodes;
  }

  private function 
renderObjectRecursive$object ) {
    
$className    strtolower(get_class($object));
    
$renderRules  $object->renderRules();
    
$data         $object->data();
    
$nodes        '';
    
$attributes   = array();

    foreach(
$data as $name => $value) {
      if (
is_object($value) && $value instanceof Renderable) {
        
$nodes .= '<'.$name.'>'.$this->renderObjectRecursive($value).'</'.$name.'>';
      } else if (
is_array($value)) {
        
# DIS IS UNDECIDED
        
$nodes .= $this->renderArrayRecursive($name$value);
      } else {
      }
    }

    
$nodes .= '</'.$className.'>';

    return 
$nodes;
  }

  private function 
renderAllArrays$arrays ) {
    
//(XMLRenderNestedArrayException)
  
}

  private function 
renderArrayRecursive$array ) {
    
//(XMLRenderNestedArrayException)
  
}

  
/**
   * Escape the value of a node in order to make it valid XML
   *
   * @param string value
   * @return string
   * @access private
   */
  
public static function nodeValue$value ) {
    return 
htmlspecialchars(mb_convert_encoding($value$this->_encodingmb_detect_encoding($value)));
  } 
// end of member function nodeValue

// end of XmlRenderer



class XMLRenderNestedArrayException extends Exception {
}
?>