Aquarionics

/home/a/aquarion/sites/www.aquarionics.com/epistula/include/nusoap.php

All my code (That is, anything not in the "Others" list on the right) is BSD licenced.

You can also view this page as text/plain or colour-coded source


<?php

/*

NuSOAP - Web Services Toolkit for PHP

Copyright (c) 2002 NuSphere Corporation

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

If you have any questions or comments, please email:

Dietrich Ayala
dietrich@ganx4.com
http://dietrich.ganx4.com/nusoap

NuSphere Corporation
http://www.nusphere.com

*/

// make errors handle properly in windows (thx, thong@xmethods.com)
//error_reporting(2039);
//error_reporting(E_ALL);

/* load classes

// necessary classes
require_once('class.soapclient.php');
require_once('class.soap_val.php');
require_once('class.soap_parser.php');
require_once('class.soap_fault.php');

// transport classes
require_once('class.soap_transport_http.php');

// optional add-on classes
require_once('class.xmlschema.php');
require_once('class.wsdl.php');

// server class
require_once('class.soap_server.php');*/

/**
*
* nusoap_base
*
* @author   Dietrich Ayala <dietrich@ganx4.com>
* @version  v 0.6.3
* @access   public
*/
class nusoap_base {

    var $title = 'NuSOAP';
    var $version = '0.6.3';
    var $error_str = false;
    var $debug_str = '';
    // toggles automatic encoding of special characters
    var $charencoding = true;

    /**
    *  set schema version
    *
    * @var      XMLSchemaVersion
    * @access   public
    */
    var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
    
    /**
    *  set default encoding
    *
    * @var      soap_defencoding
    * @access   public
    */
    //var $soap_defencoding = 'UTF-8';
    var $soap_defencoding = 'ISO-8859-1';

    /**
    *  load namespace uris into an array of uri => prefix
    *
    * @var      namespaces
    * @access   public
    */
    var $namespaces = array(
        'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
        'xsd' => 'http://www.w3.org/2001/XMLSchema',
        'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
        'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/',
        'si' => 'http://soapinterop.org/xsd');
    /**
    * load types into typemap array
    * is this legacy yet?
    * no, this is used by the xmlschema class to verify type => namespace mappings.
    * @var      typemap
    * @access   public
    */
    var $typemap = array(
    'http://www.w3.org/2001/XMLSchema' => array(
        'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
        'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
        'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
        // derived datatypes
        'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
        'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
        'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
        'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
    'http://www.w3.org/1999/XMLSchema' => array(
        'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
        'float'=>'double','dateTime'=>'string',
        'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
    'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
    'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
    'http://xml.apache.org/xml-soap' => array('Map')
    );

    /**
    *  entities to convert
    *
    * @var      xmlEntities
    * @access   public
    */
    var $xmlEntities = array('quot' => '"','amp' => '&',
        'lt' => '<','gt' => '>','apos' => "'");

    /**
    * adds debug data to the class level debug string
    *
    * @param    string $string debug data
    * @access   private
    */
    function debug($string){
        $this->debug_str .= get_class($this).": $string\n";
    }

    /**
    * returns error string if present
    *
    * @return   boolean $string error string
    * @access   public
    */
    function getError(){
        if($this->error_str != ''){
            return $this->error_str;
        }
        return false;
    }

    /**
    * sets error string
    *
    * @return   boolean $string error string
    * @access   private
    */
    function setError($str){
        $this->error_str = $str;
    }

    /**
    * serializes PHP values in accordance w/ section 5
    * @return    string
    * @access    public
    */
    function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false){
        if(is_object($val) && get_class($val) == 'soapval'){
            return $val->serialize();
        }
        $this->debug( "in serialize_val: $val, $name, $type, $name_ns, $type_ns");
        // if no name, use item
        $name = (!$name|| is_numeric($name)) ? 'soapVal' : $name;
        // if name has ns, add ns prefix to name
        $xmlns = '';
        if($name_ns){
            $prefix = 'nu'.rand(1000,9999);
            $name = $prefix.':'.$name;
            $xmlns .= " xmlns:$prefix=\"$name_ns\"";
        }
        // if type is prefixed, create type prefix
        if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
            // need to fix this. shouldn't default to xsd if no ns specified
            // w/o checking against typemap
            $type_prefix = 'xsd';
        } elseif($type_ns){
            $type_prefix = 'ns'.rand(1000,9999);
            $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
        }
        // serialize attributes if present
        if($attributes){
            foreach($attributes as $k => $v){
                $atts .= " $k=\"$v\"";
            }
        }
        // serialize if an xsd built-in primitive type
        if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
            return "<$name$xmlns xsi:type=\"xsd:$type\">$val</$name>";
        }
        // detect type and serialize
        $xml = '';
        $atts = '';
        switch(true) {
            case ($type == '' && is_null($val)):
                $xml .= "<$name$xmlns xsi:type=\"xsd:nil\"/>";
                break;
            case (is_bool($val) || $type == 'boolean'):
                if(!$val){
                    $val = 0;
                }
                $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
                break;
            case (is_int($val) || is_long($val) || $type == 'int'):
                $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
                break;
            case (is_float($val)|| is_double($val) || $type == 'float'):
                $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
                break;
            case (is_string($val) || $type == 'string'):
                if($this->charencoding){
                    $val = htmlspecialchars($val, ENT_QUOTES);
                }
                $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
                break;
            case is_object($val):
                break;
            break;
            case (is_array($val) || $type):
                // detect if struct or array
                $keyList = array_keys($val);
                $valueType = 'arraySimple';
                foreach($keyList as $keyListValue){
                    if(!is_int($keyListValue)){
                        $valueType = 'arrayStruct';
                    }
                }
                if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){
                    foreach($val as $v){
                        if(is_object($v) && get_class($v) == 'soapval'){
                            $tt = $v->type;
                        } else {
                            $tt = gettype($v);
                        }
                        $array_types[$tt] = 1;
                        $xml .= $this->serialize_val($v,'item');
                        $i = 0;
                        if(is_array($v) && is_numeric(key($v))){
                            $i += sizeof($v);
                        } else {
                            $i += 1;
                        }
                    }
                    if(count($array_types) > 1){
                        $array_typename = 'xsd:ur-type';
                    } elseif(isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
                        $array_typename = 'xsd:'.$tt;
                    } elseif($tt == 'array' || $tt == 'Array'){
                        $array_typename = 'SOAP-ENC:Array';
                    } else {
                        $array_typename = $tt;
                    }
                    if(isset($array_types['array'])){
                        $array_type = $i.",".$i;
                    } else {
                        $array_type = $i;
                    }
                    $xml = "<$name xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"$atts>".$xml."</$name>";
                } else {
                    // got a struct
                    if(isset($type) && isset($type_prefix)){
                        $type_str = " xsi:type=\"$type_prefix:$type\"";
                    } else {
                        $type_str = '';
                    }
                    $xml .= "<$name$xmlns$type_str$atts>";
                    foreach($val as $k => $v){
                        $xml .= $this->serialize_val($v,$k);
                    }
                    $xml .= "</$name>";
                }
                break;
            default:
                $xml .= 'not detected, got '.gettype($val).' for '.$val;
                break;
        }
        return $xml;
    }

    /**
    * serialize message
    *
    * @param string body
    * @param string headers
    * @param array namespaces
    * @return string message
    * @access public
    */
    function serializeEnvelope($body,$headers=false,$namespaces=array()){
    // serialize namespaces
    $ns_string = '';
    foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
        $ns_string .= "  xmlns:$k=\"$v\"";
    }
    // serialize headers
    if($headers){
        $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
    }
    // serialize envelope
    return
    '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
    '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">".
    $headers.
    "<SOAP-ENV:Body>".
        $body.
    "</SOAP-ENV:Body>".
    "</SOAP-ENV:Envelope>";
    }

    function formatDump($str){
        $str = htmlspecialchars($str);
        return nl2br($str);
    }

    /**
    * returns the local part of a prefixed string
    * returns the original string, if not prefixed
    *
    * @param string
    * @return string
    * @access public
    */
    function getLocalPart($str){
        if($sstr = strrchr($str,':')){
            // get unqualified name
            return substr( $sstr, 1 );
        } else {
            return $str;
        }
    }

    /**
    * returns the prefix part of a prefixed string
    * returns false, if not prefixed
    *
    * @param string
    * @return mixed
    * @access public
    */
    function getPrefix($str){
        if($pos = strrpos($str,':')){
            // get prefix
            return substr($str,0,$pos);
        }
        return false;
    }

    function varDump($data) {
        ob_start();
        var_dump($data);
        $ret_val = ob_get_contents();
        ob_end_clean();
        return $ret_val;
    }
}

// XML Schema Datatype Helper Functions

//xsd:dateTime helpers

/**
* convert unix timestamp to ISO 8601 compliant date string
*
* @param    string $timestamp Unix time stamp
* @access   public
*/
function timestamp_to_iso8601($timestamp,$utc=true){
    $datestr = date('Y-m-d\TH:i:sO',$timestamp);
    if($utc){
        $eregStr =
        '([0-9]{4})-'.    // centuries & years CCYY-
        '([0-9]{2})-'.    // months MM-
        '([0-9]{2})'.    // days DD
        'T'.            // separator T
        '([0-9]{2}):'.    // hours hh:
        '([0-9]{2}):'.    // minutes mm:
        '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
        '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's

        if(ereg($eregStr,$datestr,$regs)){
            return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
        }
        return false;
    } else {
        return $datestr;
    }
}

/**
* convert ISO 8601 compliant date string to unix timestamp
*
* @param    string $datestr ISO 8601 compliant date string
* @access   public
*/
function iso8601_to_timestamp($datestr){
    $eregStr =
    '([0-9]{4})-'.    // centuries & years CCYY-
    '([0-9]{2})-'.    // months MM-
    '([0-9]{2})'.    // days DD
    'T'.            // separator T
    '([0-9]{2}):'.    // hours hh:
    '([0-9]{2}):'.    // minutes mm:
    '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
    '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
    if(ereg($eregStr,$datestr,$regs)){
        // not utc
        if($regs[8] != 'Z'){
            $op = substr($regs[8],0,1);
            $h = substr($regs[8],1,2);
            $m = substr($regs[8],strlen($regs[8])-2,2);
            if($op == '-'){
                $regs[4] = $regs[4] + $h;
                $regs[5] = $regs[5] + $m;
            } elseif($op == '+'){
                $regs[4] = $regs[4] - $h;
                $regs[5] = $regs[5] - $m;
            }
        }
        return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
    } else {
        return false;
    }
}

?><?php

/**
* soap_fault class, allows for creation of faults
* mainly used for returning faults from deployed functions
* in a server instance.
* @author   Dietrich Ayala <dietrich@ganx4.com>
* @version  v 0.6.3
* @access public
*/
class soap_fault extends nusoap_base {

    var $faultcode;
    var $faultactor;
    var $faultstring;
    var $faultdetail;

    /**
    * constructor
    *
    * @param string $faultcode (client | server)
    * @param string $faultactor only used when msg routed between multiple actors
    * @param string $faultstring human readable error message
    * @param string $faultdetail
    */
    function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
        $this->faultcode = $faultcode;
        $this->faultactor = $faultactor;
        $this->faultstring = $faultstring;
        $this->faultdetail = $faultdetail;
    }

    /**
    * serialize a fault
    *
    * @access   public
    */
    function serialize(){
        $ns_string = '';
        foreach($this->namespaces as $k => $v){
            $ns_string .= "\n  xmlns:$k=\"$v\"";
        }
        $return_msg =
            '<?xml version="1.0"?'.">\n".
            '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
                '<SOAP-ENV:Body>'.
                '<SOAP-ENV:Fault>'.
                    '<faultcode>'.$this->faultcode.'</faultcode>'.
                    '<faultactor>'.$this->faultactor.'</faultactor>'.
                    '<faultstring>'.$this->faultstring.'</faultstring>'.
                    '<detail>'.$this->serialize_val($this->faultdetail).'</detail>'.
                '</SOAP-ENV:Fault>'.
                '</SOAP-ENV:Body>'.
            '</SOAP-ENV:Envelope>';
        return $return_msg;
    }
}

?><?php

/**
* parses an XML Schema, allows access to it's data, other utility methods
* no validation... yet.
* very experimental and limited. As is discussed on XML-DEV, I'm one of the people
* that just doesn't have time to read the spec(s) thoroughly, and just have a couple of trusty
* tutorials I refer to :)
*
* @author   Dietrich Ayala <dietrich@ganx4.com>
* @version  v 0.6.3
* @access   public
*/
class XMLSchema extends nusoap_base  {
    
    // files
    var $schema = '';
    var $xml = '';
    // define internal arrays of bindings, ports, operations, messages, etc.
    var $complexTypes = array();
    // target namespace
    var $schemaTargetNamespace = '';
    // parser vars
    var $parser;
    var $position;
    var $depth = 0;
    var $depth_array = array();
    
    /**
    * constructor
    *
    * @param    string $schema schema document URI
    * @param    string $xml xml document URI
    * @access   public
    */
    function XMLSchema($schema='',$xml=''){

        $this->debug('xmlschema class instantiated, inside constructor');
        // files
        $this->schema = $schema;
        $this->xml = $xml;

        // parse schema file
        if($schema != ''){
            $this->debug('initial schema file: '.$schema);
            $this->parseFile($schema);
        }

        // parse xml file
        if($xml != ''){
            $this->debug('initial xml file: '.$xml);
            $this->parseFile($xml);
        }

    }

    /**
    * parse an XML file
    *
    * @param string $xml, path/URL to XML file
    * @param string $type, (schema | xml)
    * @return boolean
    * @access public
    */
    function parseFile($xml,$type){
        // parse xml file
        if($xml != ""){
            $this->debug('parsing $xml');
            $xmlStr = @join("",@file($xml));
            if($xmlStr == ""){
                $this->setError('No file at the specified URL: '.$xml);
            return false;
            } else {
                $this->parseString($xmlStr,$type);
            return true;
            }
        }
        return false;
    }

    /**
    * parse an XML string
    *
    * @param    string $xml path or URL
    * @param string $type, (schema|xml)
    * @access   private
    */
    function parseString($xml,$type){
        // parse xml string
        if($xml != ""){

            // Create an XML parser.
            $this->parser = xml_parser_create();
            // Set the options for parsing the XML data.
            xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);

            // Set the object for the parser.
            xml_set_object($this->parser, $this);

            // Set the element handlers for the parser.
            if($type == "schema"){
                xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
                xml_set_character_data_handler($this->parser,'schemaCharacterData');
            } elseif($type == "xml"){
                xml_set_element_handler($this->parser, 'xmlStartElement"','xmlEndElement');
                xml_set_character_data_handler($this->parser,'xmlCharacterData');
            }

            // Parse the XML file.
            if(!xml_parse($this->parser,$xml,true)){
            // Display an error message.
                $errstr = sprintf('XML error on line %d: %s',
                xml_get_current_line_number($this->parser),
                xml_error_string(xml_get_error_code($this->parser))
                );
                $this->debug('XML parse error: '.$errstr);
                $this->setError('Parser error: '.$errstr);
            }
            
            xml_parser_free($this->parser);
        } else{
            $this->debug('no xml passed to parseString()!!');
            $this->setError('no xml passed to parseString()!!');
        }
    }

    /**
    * start-element handler
    *
    * @param    string $parser XML parser object
    * @param    string $name element name
    * @param    string $attrs associative array of attributes
    * @access   private
    */
    function schemaStartElement($parser, $name, $attrs) {
        
        // position in the total number of elements, starting from 0
        $pos = $this->position++;
        $depth = $this->depth++;
        // set self as current value for this depth
        $this->depth_array[$depth] = $pos;

        // get element prefix
        if($prefix = $this->getPrefix($name)){
            // get unqualified name
            $name = $this->getLocalPart($name);
        } else {
            $prefix = '';
        }
        
        // loop thru attributes, expanding, and registering namespace declarations
        if(count($attrs) > 0){
            foreach($attrs as $k => $v){
                // if ns declarations, add to class level array of valid namespaces
                if(ereg("^xmlns",$k)){
                    //$this->xdebug("$k: $v");
                    //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
                    if($ns_prefix = substr(strrchr($k,':'),1)){
                        $this->namespaces[$ns_prefix] = $v;
                    } else {
                        $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
                    }
                    if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema'){
                        $this->XMLSchemaVersion = $v;
                        $this->namespaces['xsi'] = $v.'-instance';
                    }
                }
                // expand each attribute
                $k = strpos($k,':') ? $this->expandQname($k) : $k;
                $v = strpos($v,':') ? $this->expandQname($v) : $v;
                $eAttrs[$k] = $v;
            }
            $attrs = $eAttrs;
        } else {
            $attrs = array();
        }
        // find status, register data
        switch($name){
            case ('all'|'choice'|'sequence'):
                //$this->complexTypes[$this->currentComplexType]['compositor'] = 'all';
                $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
                if($name == 'all'){
                    $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
                }
            break;
            case 'attribute':
                //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
                if(isset($attrs['name'])){
                    $this->attributes[$attrs['name']] = $attrs;
                    $aname = $attrs['name'];
                } elseif($attrs['ref']){
                    $aname = $attrs['ref'];
                    $this->attributes[$attrs['ref']] = $attrs;
                }
                
                if(isset($this->currentComplexType)){
                    $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
                } elseif(isset($this->currentElement)){
                    $this->elements[$this->currentElement]['attrs'][$aname] = $attrs;
                }
                // arrayType attribute
                if($this->getLocalPart($aname) == 'arrayType'){
                    $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
                    if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
                        $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
                    } else {
                        $v = '';
                    }
                    if(strpos($v,'[,]')){
                        $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
                    }
                    $v = substr($v,0,strpos($v,'[')); // clip the []
                    if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
                        $v = $this->XMLSchemaVersion.':'.$v;
                    }
                    $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
                }
            break;
            case 'complexType':
                if(isset($attrs['name'])){
                    $this->currentElement = false;
                    $this->currentComplexType = $attrs['name'];
                    $this->complexTypes[$this->currentComplexType] = $attrs;
                    $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
                    if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
                        $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
                    } else {
                        $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
                    }
                    $this->xdebug('processing complexType '.$attrs['name']);
                }
            break;
            case 'element':
                if(isset($attrs['type'])){
                    $this->xdebug("processing element ".$attrs['name']);
                    $this->currentElement = $attrs['name'];
                    $this->elements[ $attrs['name'] ] = $attrs;
                    $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
                    $ename = $attrs['name'];
                } elseif(isset($attrs['ref'])){
                    $ename = $attrs['ref'];
                } else {
                    $this->xdebug('adding complexType '.$attrs['name']);
                    $this->currentComplexType = $attrs['name'];
                    $this->complexTypes[ $attrs['name'] ] = $attrs;
                    $this->complexTypes[ $attrs['name'] ]['element'] = 1;
                    $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
                }
                if(isset($ename) && $this->currentComplexType){
                    $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
                }
            break;
            case 'restriction':
                $this->xdebug("in restriction for ct: $this->currentComplexType and ce: $this->currentElement");
                if($this->currentElement){
                    $this->elements[$this->currentElement]['type'] = $attrs['base'];
                } elseif($this->currentComplexType){
                    $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
                    if(strstr($attrs['base'],':') == ':Array'){
                        $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
                    }
                }
            break;
            case 'schema':
                $this->schema = $attrs;
                $this->schema['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
            break;
            case 'simpleType':
                $this->currentElement = $attrs['name'];
                $this->elements[ $attrs['name'] ] = $attrs;
                $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
            break;
        }
    }

    /**
    * end-element handler
    *
    * @param    string $parser XML parser object
    * @param    string $name element name
    * @access   private
    */
    function schemaEndElement($parser, $name) {
        // position of current element is equal to the last value left in depth_array for my depth
        if(isset($this->depth_array[$this->depth])){
            $pos = $this->depth_array[$this->depth];
        }
        // bring depth down a notch
        $this->depth--;
        // move on...
        if($name == 'complexType'){
            $this->currentComplexType = false;
            $this->currentElement = false;
        }
        if($name == 'element'){
            $this->currentElement = false;
        }
    }

    /**
    * element content handler
    *
    * @param    string $parser XML parser object
    * @param    string $data element content
    * @access   private
    */
    function schemaCharacterData($parser, $data){
        $pos = $this->depth_array[$this->depth];
        $this->message[$pos]['cdata'] .= $data;
    }

    /**
    * serialize the schema
    *
    * @access   public
    */
    function serializeSchema(){

        $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
        $xml = '';
        // complex types
        foreach($this->complexTypes as $typeName => $attrs){
            $contentStr = '';
            // serialize child elements
            if(count($attrs['elements']) > 0){
                foreach($attrs['elements'] as $element => $eParts){
                    if(isset($eParts['ref'])){
                        $contentStr .= "<element ref=\"$element\"/>";
                    } else {
                        $contentStr .= "<element name=\"$element\" type=\"$eParts[type]\"/>";
                    }
                }
            }
            // attributes
            if(count($attrs['attrs']) >= 1){
                foreach($attrs['attrs'] as $attr => $aParts){
                    $contentStr .= '<attribute ref="'.$aParts['ref'].'"';
                    if(isset($aParts['wsdl:arrayType'])){
                        $contentStr .= ' wsdl:arrayType="'.$aParts['wsdl:arrayType'].'"';
                    }
                    $contentStr .= '/>';
                }
            }
            // if restriction
            if( isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
                $contentStr = "<$schemaPrefix:restriction base=\"".$attrs['restrictionBase']."\">".$contentStr."</$schemaPrefix:restriction>";
            }
            // "all" compositor obviates complex/simple content
            if(isset($attrs['compositor']) && $attrs['compositor'] == 'all'){
                $contentStr = "<$schemaPrefix:$attrs[compositor]>".$contentStr."</$schemaPrefix:$attrs[compositor]>";
            }
            // complex or simple content
            elseif( count($attrs['elements']) > 0 || count($attrs