<?PHP
require_once('DB.php');
require_once(
'classes/XML/class.XmlNode.php');
// Modification log
// (date)        (author)    (activity/purpose)
// 27.12.2002   T.Gildseth  Added support for multiple queries.
// 27.12.2002   T.Gildseth  Split _getXML() method into two separate methodes.
// 27.12.2002   T.Gildseth  Added method _getRows()
// 27.12.2002   T.Gildseth  Renamed method query() to addQuery()
// 27.12.2002   T.Gildseth  Added method _addRS()
// 27.12.2002   T.Gildseth  Modified XML _getXML(). Now always includes <table>
// 04.08.2003   T.Gildseth  Renamed class to DbToXML instead of dbToXML
// 04.08.2003   T.Gildseth  A complete rewrite of the entire class(allmost).
// 12.09.2003   T.Gildseth  Added function getXmlString()
// 04.11.2003   T.Gildseth  Modified addRS to accept array
// 19.11.2003   T.Gildseth  Added htmlspecialchars() on values going into the XML tree
// 10.12.2003   T.Gildseth  Added ability to customise the name of the root element for
//                          each resultset.
// 12.12.2003   T.Gildseth  Fixed fatel error when retrieving XML string, without
//                          adding any queries or resultsets first.
//
// Todo
// (date)        (author)    (activity/purpose)
// 04.08.2003    T.Gildseth    Add support for XML DTD and/or schema.
// 04.08.2003    T.Gildseth    Improve error handling


/**
 * This class receives a PEAR DB resultset, or a SQL query, and transforms it into an XML tree
 *
 * @author Tommy Gildseth, Akili AS
 * @contact tommy@akili.no
 * @website http://www.akili.no
 * @copyright (C) Akili AS, December 2002
 * @description DbToXML
 * @version 1.0.0
 * @var error Contains the latest error message from the PEAR DB class.
 * @var dbCon the PEAR DB object.
 * @var result if not empty, contains a PEAR resultset object.
 * @var tableName if not empty, contains the content of the <name> element.
 * @var tableElem If there are multiple resultsets or queries added to the object,
 *                this will be the name of the parent node for the <row> elements.
 * @var rootElem The name of the root node
 * @package DB
 */
class DbToXML
    
{
    
/*
    @access public
    */
    
var $error '';
    var 
$resElem 'result';
    var 
$rootElem 'root';

    
/*
    @access private
    */
    
var $dbCon;
    var 
$result = array();
    var 
$tableName = array();

    
/**
     * dbToXML class constructor
     *
     * @param $db Data Source Name. A universal connection string. Format is:
     *            RDBMS://user:pass@host/database. See PEAR documentation for more
     *            details
     * @since 0.0.1
     * @prototype void dbToXML(mixed db)
     */
    
function DbToXML($db)
        {
        if (
is_object($db))
            {
            
$this->dbCon $db;
            }
        else
            {
            
$this->dbCon DB::connect($db);
            }

        if (
DB::isError($this->dbCon))
            
$this->error $this->dbCon->getMessage();
        }

    
/**
     * Execute SQL query in param query, and set this->tableName to param tableName
     *
     * @pre A valid SQL query.
     * @post Resultset stored in this->result
     * @param $query A complete SQL query
     * @param $tableName name of table that will appear in the <name> tag.
     * @param $parentElem name of the element cotaining this resultset
     * @since 0.0.4
     * @return bool Boolean value, indicating success or failure.
     * @prototype bool query(string query, string tableName)
     */
    
function addQuery($query$tableName ''$parentElem null)
        {
        
$this->tableName[] = $tableName;
        if (empty (
$this->error))
            {
            
$rs['rs'] = $this->dbCon->getAll($queryDB_FETCHMODE_ASSOC);
            
$rs['parentElem'] = $parentElem;
            
$this->result[] = $rs;
            
$index count($this->result) - 1;
            if (
DB::isError($this->result[$index]['rs']))
                {
                
$this->error $this->result[$index]['rs']->getMessage();
                
array_pop($this->tableName);
                
array_pop($this->result);
                return 
false;
                }
            else
                {
                return 
true;
                }
            }
        else
            {
            return 
false;
            }
        }

    
/**
     * Add an instance of PEAR DB_Result(or compatible) to the resultsets to process.
     *
     * @pre resultSet is a valid PEAR DB_Result, or an array returned from pear DB::getAll()
     * @post resultSet has been added to this object.
     * @param $resultSet a PEAR DB_Result instance, or an array returned from pear DB::getAll()
     * @since 0.0.5
     * @return void
     * @prototype void addRS(DB_Result resultSet)
     */
    
function addRS($resultSet$tableName ''$parentElem null)
        {
        
$rs['rs'] = array();
        
$rs['parentElem'] = $parentElem;

        if (
is_object($resultSet) && !DB::isError($resultSet))
            {
            while (
$row $resultSet->fetchRow(DB_FETCHMODE_ASSOC))
                {
                
$rs['rs'][] = $row;
                }
            }
        else if(
is_array($resultSet))
            {
            
$rs['rs'] = $resultSet;
            }

        
$this->tableName[] = $tableName;
        
$this->result[] = $rs;
        }

    
/**
     * Retrieve a XML tree representing the resultset returned from the database.
     *
     * @since 0.0.1
     * @return mixed return type. The root node of a XML tree, on success,
     *           or false on failure.
     * @prototype mixed _getXML( )
     */
    
function &getRootNode( )
        {
        if (
count($this->result) !== 0)
            {
            
$root = new XmlNode($this->rootElem);

            
$results count($this->result);
            for (
$i 0$i $results; ++$i)
                {
                if (isset(
$this->result[$i]['parentElem']))
                    
$result = new XmlNode($this->result[$i]['parentElem']);
                else
                    
$result = new XmlNode($this->resElem);

                if (
$this->tableName[$i] !== '')
                    {
                    
$result->addChild('.',
                                      new 
XmlNode('tableName',
                                                  
null,
                                                  
$this->tableName[$i]));
                    }

                foreach(
$this->result[$i]['rs'] as $eachRow)
                    {
                    
$result->addChild('.',  $this->_getRow($eachRow));
                    }
                
$root->addChild('.'$result);
                unset(
$result);
                }
            return 
$root;
            }
        else
            {
            return 
false;
            }
        }

    
/**
     * Retrieve a XML tree representing the resultset returned from the database.
     *
     * @since 0.0.1
     * @return mixed return type. The root node of a XML tree, on success,
     *           or false on failure.
     * @prototype mixed _getXML( )
     */
    
function getXmlString$whitespace NO_WHITESPACE)
        {
        
$root $this->getRootNode();
        
$return "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
        if (
is_object($root))
            
$return .= $root->getXmlString($whitespace);
        else
            
$return .= '<root/>';

        return 
$return;
        }

    
/**
     * Create the XML for each row in a resultset
     *
     * @pre parameter is an associative array
     * @post A row node containing the information from the array
     * @param $row An associative array, where the key is the node name, and
     *             the value is the node value
     * @since 0.0.4
     * @return An XML tree containing a row node, and the row values as it's children.
     * @prototype string _getRows(DB_Result resultset)
     */
    
function _getRow($row)
        {
        
$node = new XmlNode('row');

        foreach(
$row as $colName=>$colVal)
            {
            
$node->addChild('.', new XmlNode($colNamenullhtmlspecialchars($colVal)));
            }
        return 
$node;
        }
    }
?>