shop.balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

class.soap_parser.php (25130B)


      1 <?php
      2 
      3 
      4 
      5 
      6 /**
      7 *
      8 * nusoap_parser class parses SOAP XML messages into native PHP values
      9 *
     10 * @author   Dietrich Ayala <dietrich@ganx4.com>
     11 * @author   Scott Nichol <snichol@users.sourceforge.net>
     12 * @version  $Id: class.soap_parser.php,v 1.42 2010/04/26 20:15:08 snichol Exp $
     13 * @access   public
     14 */
     15 class nusoap_parser extends nusoap_base {
     16 
     17 	var $xml = '';
     18 	var $xml_encoding = '';
     19 	var $method = '';
     20 	var $root_struct = '';
     21 	var $root_struct_name = '';
     22 	var $root_struct_namespace = '';
     23 	var $root_header = '';
     24     var $document = '';			// incoming SOAP body (text)
     25 	// determines where in the message we are (envelope,header,body,method)
     26 	var $status = '';
     27 	var $position = 0;
     28 	var $depth = 0;
     29 	var $default_namespace = '';
     30 	var $namespaces = array();
     31 	var $message = array();
     32     var $parent = '';
     33 	var $fault = false;
     34 	var $fault_code = '';
     35 	var $fault_str = '';
     36 	var $fault_detail = '';
     37 	var $depth_array = array();
     38 	var $debug_flag = true;
     39 	var $soapresponse = NULL;	// parsed SOAP Body
     40 	var $soapheader = NULL;		// parsed SOAP Header
     41 	var $responseHeaders = '';	// incoming SOAP headers (text)
     42 	var $body_position = 0;
     43 	// for multiref parsing:
     44 	// array of id => pos
     45 	var $ids = array();
     46 	// array of id => hrefs => pos
     47 	var $multirefs = array();
     48 	// toggle for auto-decoding element content
     49 	var $decode_utf8 = true;
     50 
     51 	/**
     52 	* constructor that actually does the parsing
     53 	*
     54 	* @param    string $xml SOAP message
     55 	* @param    string $encoding character encoding scheme of message
     56 	* @param    string $method method for which XML is parsed (unused?)
     57 	* @param    string $decode_utf8 whether to decode UTF-8 to ISO-8859-1
     58 	* @access   public
     59 	*/
     60 	function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){
     61 		parent::nusoap_base();
     62 		$this->xml = $xml;
     63 		$this->xml_encoding = $encoding;
     64 		$this->method = $method;
     65 		$this->decode_utf8 = $decode_utf8;
     66 
     67 		// Check whether content has been read.
     68 		if(!empty($xml)){
     69 			// Check XML encoding
     70 			$pos_xml = strpos($xml, '<?xml');
     71 			if ($pos_xml !== FALSE) {
     72 				$xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);
     73 				if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
     74 					$xml_encoding = $res[1];
     75 					if (strtoupper($xml_encoding) != $encoding) {
     76 						$err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
     77 						$this->debug($err);
     78 						if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') {
     79 							$this->setError($err);
     80 							return;
     81 						}
     82 						// when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
     83 					} else {
     84 						$this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
     85 					}
     86 				} else {
     87 					$this->debug('No encoding specified in XML declaration');
     88 				}
     89 			} else {
     90 				$this->debug('No XML declaration');
     91 			}
     92 			$this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding);
     93 			// Create an XML parser - why not xml_parser_create_ns?
     94 			$this->parser = xml_parser_create($this->xml_encoding);
     95 			// Set the options for parsing the XML data.
     96 			//xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
     97 			xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
     98 			xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
     99 			// Set the object for the parser.
    100 			xml_set_object($this->parser, $this);
    101 			// Set the element handlers for the parser.
    102 			xml_set_element_handler($this->parser, 'start_element','end_element');
    103 			xml_set_character_data_handler($this->parser,'character_data');
    104 
    105 			// Parse the XML file.
    106 			if(!xml_parse($this->parser,$xml,true)){
    107 			    // Display an error message.
    108 			    $err = sprintf('XML error parsing SOAP payload on line %d: %s',
    109 			    xml_get_current_line_number($this->parser),
    110 			    xml_error_string(xml_get_error_code($this->parser)));
    111 				$this->debug($err);
    112 				$this->debug("XML payload:\n" . $xml);
    113 				$this->setError($err);
    114 			} else {
    115 				$this->debug('in nusoap_parser ctor, message:');
    116 				$this->appendDebug($this->varDump($this->message));
    117 				$this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);
    118 				// get final value
    119 				$this->soapresponse = $this->message[$this->root_struct]['result'];
    120 				// get header value
    121 				if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){
    122 					$this->soapheader = $this->message[$this->root_header]['result'];
    123 				}
    124 				// resolve hrefs/ids
    125 				if(sizeof($this->multirefs) > 0){
    126 					foreach($this->multirefs as $id => $hrefs){
    127 						$this->debug('resolving multirefs for id: '.$id);
    128 						$idVal = $this->buildVal($this->ids[$id]);
    129 						if (is_array($idVal) && isset($idVal['!id'])) {
    130 							unset($idVal['!id']);
    131 						}
    132 						foreach($hrefs as $refPos => $ref){
    133 							$this->debug('resolving href at pos '.$refPos);
    134 							$this->multirefs[$id][$refPos] = $idVal;
    135 						}
    136 					}
    137 				}
    138 			}
    139 			xml_parser_free($this->parser);
    140 		} else {
    141 			$this->debug('xml was empty, didn\'t parse!');
    142 			$this->setError('xml was empty, didn\'t parse!');
    143 		}
    144 	}
    145 
    146 	/**
    147 	* start-element handler
    148 	*
    149 	* @param    resource $parser XML parser object
    150 	* @param    string $name element name
    151 	* @param    array $attrs associative array of attributes
    152 	* @access   private
    153 	*/
    154 	function start_element($parser, $name, $attrs) {
    155 		// position in a total number of elements, starting from 0
    156 		// update class level pos
    157 		$pos = $this->position++;
    158 		// and set mine
    159 		$this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
    160 		// depth = how many levels removed from root?
    161 		// set mine as current global depth and increment global depth value
    162 		$this->message[$pos]['depth'] = $this->depth++;
    163 
    164 		// else add self as child to whoever the current parent is
    165 		if($pos != 0){
    166 			$this->message[$this->parent]['children'] .= '|'.$pos;
    167 		}
    168 		// set my parent
    169 		$this->message[$pos]['parent'] = $this->parent;
    170 		// set self as current parent
    171 		$this->parent = $pos;
    172 		// set self as current value for this depth
    173 		$this->depth_array[$this->depth] = $pos;
    174 		// get element prefix
    175 		if(strpos($name,':')){
    176 			// get ns prefix
    177 			$prefix = substr($name,0,strpos($name,':'));
    178 			// get unqualified name
    179 			$name = substr(strstr($name,':'),1);
    180 		}
    181 		// set status
    182 		if ($name == 'Envelope' && $this->status == '') {
    183 			$this->status = 'envelope';
    184 		} elseif ($name == 'Header' && $this->status == 'envelope') {
    185 			$this->root_header = $pos;
    186 			$this->status = 'header';
    187 		} elseif ($name == 'Body' && $this->status == 'envelope'){
    188 			$this->status = 'body';
    189 			$this->body_position = $pos;
    190 		// set method
    191 		} elseif($this->status == 'body' && $pos == ($this->body_position+1)) {
    192 			$this->status = 'method';
    193 			$this->root_struct_name = $name;
    194 			$this->root_struct = $pos;
    195 			$this->message[$pos]['type'] = 'struct';
    196 			$this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
    197 		}
    198 		// set my status
    199 		$this->message[$pos]['status'] = $this->status;
    200 		// set name
    201 		$this->message[$pos]['name'] = htmlspecialchars($name);
    202 		// set attrs
    203 		$this->message[$pos]['attrs'] = $attrs;
    204 
    205 		// loop through atts, logging ns and type declarations
    206         $attstr = '';
    207 		foreach($attrs as $key => $value){
    208         	$key_prefix = $this->getPrefix($key);
    209 			$key_localpart = $this->getLocalPart($key);
    210 			// if ns declarations, add to class level array of valid namespaces
    211             if($key_prefix == 'xmlns'){
    212 				if(preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/',$value)){
    213 					$this->XMLSchemaVersion = $value;
    214 					$this->namespaces['xsd'] = $this->XMLSchemaVersion;
    215 					$this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';
    216 				}
    217                 $this->namespaces[$key_localpart] = $value;
    218 				// set method namespace
    219 				if($name == $this->root_struct_name){
    220 					$this->methodNamespace = $value;
    221 				}
    222 			// if it's a type declaration, set type
    223         } elseif($key_localpart == 'type'){
    224         		if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') {
    225         			// do nothing: already processed arrayType
    226         		} else {
    227 	            	$value_prefix = $this->getPrefix($value);
    228 	                $value_localpart = $this->getLocalPart($value);
    229 					$this->message[$pos]['type'] = $value_localpart;
    230 					$this->message[$pos]['typePrefix'] = $value_prefix;
    231 	                if(isset($this->namespaces[$value_prefix])){
    232 	                	$this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
    233 	                } else if(isset($attrs['xmlns:'.$value_prefix])) {
    234 						$this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
    235 	                }
    236 					// should do something here with the namespace of specified type?
    237 				}
    238 			} elseif($key_localpart == 'arrayType'){
    239 				$this->message[$pos]['type'] = 'array';
    240 				/* do arrayType ereg here
    241 				[1]    arrayTypeValue    ::=    atype asize
    242 				[2]    atype    ::=    QName rank*
    243 				[3]    rank    ::=    '[' (',')* ']'
    244 				[4]    asize    ::=    '[' length~ ']'
    245 				[5]    length    ::=    nextDimension* Digit+
    246 				[6]    nextDimension    ::=    Digit+ ','
    247 				*/
    248 				$expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/';
    249 				if(preg_match($expr,$value,$regs)){
    250 					$this->message[$pos]['typePrefix'] = $regs[1];
    251 					$this->message[$pos]['arrayTypePrefix'] = $regs[1];
    252 	                if (isset($this->namespaces[$regs[1]])) {
    253 	                	$this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
    254 	                } else if (isset($attrs['xmlns:'.$regs[1]])) {
    255 						$this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]];
    256 	                }
    257 					$this->message[$pos]['arrayType'] = $regs[2];
    258 					$this->message[$pos]['arraySize'] = $regs[3];
    259 					$this->message[$pos]['arrayCols'] = $regs[4];
    260 				}
    261 			// specifies nil value (or not)
    262 			} elseif ($key_localpart == 'nil'){
    263 				$this->message[$pos]['nil'] = ($value == 'true' || $value == '1');
    264 			// some other attribute
    265 			} elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') {
    266 				$this->message[$pos]['xattrs']['!' . $key] = $value;
    267 			}
    268 
    269 			if ($key == 'xmlns') {
    270 				$this->default_namespace = $value;
    271 			}
    272 			// log id
    273 			if($key == 'id'){
    274 				$this->ids[$value] = $pos;
    275 			}
    276 			// root
    277 			if($key_localpart == 'root' && $value == 1){
    278 				$this->status = 'method';
    279 				$this->root_struct_name = $name;
    280 				$this->root_struct = $pos;
    281 				$this->debug("found root struct $this->root_struct_name, pos $pos");
    282 			}
    283             // for doclit
    284             $attstr .= " $key=\"$value\"";
    285 		}
    286         // get namespace - must be done after namespace atts are processed
    287 		if(isset($prefix)){
    288 			$this->message[$pos]['namespace'] = $this->namespaces[$prefix];
    289 			$this->default_namespace = $this->namespaces[$prefix];
    290 		} else {
    291 			$this->message[$pos]['namespace'] = $this->default_namespace;
    292 		}
    293         if($this->status == 'header'){
    294         	if ($this->root_header != $pos) {
    295 	        	$this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
    296 	        }
    297         } elseif($this->root_struct_name != ''){
    298         	$this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
    299         }
    300 	}
    301 
    302 	/**
    303 	* end-element handler
    304 	*
    305 	* @param    resource $parser XML parser object
    306 	* @param    string $name element name
    307 	* @access   private
    308 	*/
    309 	function end_element($parser, $name) {
    310 		// position of current element is equal to the last value left in depth_array for my depth
    311 		$pos = $this->depth_array[$this->depth--];
    312 
    313         // get element prefix
    314 		if(strpos($name,':')){
    315 			// get ns prefix
    316 			$prefix = substr($name,0,strpos($name,':'));
    317 			// get unqualified name
    318 			$name = substr(strstr($name,':'),1);
    319 		}
    320 		
    321 		// build to native type
    322 		if(isset($this->body_position) && $pos > $this->body_position){
    323 			// deal w/ multirefs
    324 			if(isset($this->message[$pos]['attrs']['href'])){
    325 				// get id
    326 				$id = substr($this->message[$pos]['attrs']['href'],1);
    327 				// add placeholder to href array
    328 				$this->multirefs[$id][$pos] = 'placeholder';
    329 				// add set a reference to it as the result value
    330 				$this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
    331             // build complexType values
    332 			} elseif($this->message[$pos]['children'] != ''){
    333 				// if result has already been generated (struct/array)
    334 				if(!isset($this->message[$pos]['result'])){
    335 					$this->message[$pos]['result'] = $this->buildVal($pos);
    336 				}
    337 			// build complexType values of attributes and possibly simpleContent
    338 			} elseif (isset($this->message[$pos]['xattrs'])) {
    339 				if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
    340 					$this->message[$pos]['xattrs']['!'] = null;
    341 				} elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
    342 	            	if (isset($this->message[$pos]['type'])) {
    343 						$this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
    344 					} else {
    345 						$parent = $this->message[$pos]['parent'];
    346 						if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
    347 							$this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
    348 						} else {
    349 							$this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
    350 						}
    351 					}
    352 				}
    353 				$this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
    354 			// set value of simpleType (or nil complexType)
    355 			} else {
    356             	//$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
    357 				if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
    358 					$this->message[$pos]['xattrs']['!'] = null;
    359 				} elseif (isset($this->message[$pos]['type'])) {
    360 					$this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
    361 				} else {
    362 					$parent = $this->message[$pos]['parent'];
    363 					if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
    364 						$this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
    365 					} else {
    366 						$this->message[$pos]['result'] = $this->message[$pos]['cdata'];
    367 					}
    368 				}
    369 
    370 				/* add value to parent's result, if parent is struct/array
    371 				$parent = $this->message[$pos]['parent'];
    372 				if($this->message[$parent]['type'] != 'map'){
    373 					if(strtolower($this->message[$parent]['type']) == 'array'){
    374 						$this->message[$parent]['result'][] = $this->message[$pos]['result'];
    375 					} else {
    376 						$this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
    377 					}
    378 				}
    379 				*/
    380 			}
    381 		}
    382 		
    383         // for doclit
    384         if($this->status == 'header'){
    385         	if ($this->root_header != $pos) {
    386 	        	$this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
    387 	        }
    388         } elseif($pos >= $this->root_struct){
    389         	$this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
    390         }
    391 		// switch status
    392 		if ($pos == $this->root_struct){
    393 			$this->status = 'body';
    394 			$this->root_struct_namespace = $this->message[$pos]['namespace'];
    395 		} elseif ($pos == $this->root_header) {
    396 			$this->status = 'envelope';
    397 		} elseif ($name == 'Body' && $this->status == 'body') {
    398 			$this->status = 'envelope';
    399 		} elseif ($name == 'Header' && $this->status == 'header') { // will never happen
    400 			$this->status = 'envelope';
    401 		} elseif ($name == 'Envelope' && $this->status == 'envelope') {
    402 			$this->status = '';
    403 		}
    404 		// set parent back to my parent
    405 		$this->parent = $this->message[$pos]['parent'];
    406 	}
    407 
    408 	/**
    409 	* element content handler
    410 	*
    411 	* @param    resource $parser XML parser object
    412 	* @param    string $data element content
    413 	* @access   private
    414 	*/
    415 	function character_data($parser, $data){
    416 		$pos = $this->depth_array[$this->depth];
    417 		if ($this->xml_encoding=='UTF-8'){
    418 			// TODO: add an option to disable this for folks who want
    419 			// raw UTF-8 that, e.g., might not map to iso-8859-1
    420 			// TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
    421 			if($this->decode_utf8){
    422 				$data = utf8_decode($data);
    423 			}
    424 		}
    425         $this->message[$pos]['cdata'] .= $data;
    426         // for doclit
    427         if($this->status == 'header'){
    428         	$this->responseHeaders .= $data;
    429         } else {
    430         	$this->document .= $data;
    431         }
    432 	}
    433 
    434 	/**
    435 	* get the parsed message (SOAP Body)
    436 	*
    437 	* @return	mixed
    438 	* @access   public
    439 	* @deprecated	use get_soapbody instead
    440 	*/
    441 	function get_response(){
    442 		return $this->soapresponse;
    443 	}
    444 
    445 	/**
    446 	* get the parsed SOAP Body (NULL if there was none)
    447 	*
    448 	* @return	mixed
    449 	* @access   public
    450 	*/
    451 	function get_soapbody(){
    452 		return $this->soapresponse;
    453 	}
    454 
    455 	/**
    456 	* get the parsed SOAP Header (NULL if there was none)
    457 	*
    458 	* @return	mixed
    459 	* @access   public
    460 	*/
    461 	function get_soapheader(){
    462 		return $this->soapheader;
    463 	}
    464 
    465 	/**
    466 	* get the unparsed SOAP Header
    467 	*
    468 	* @return	string XML or empty if no Header
    469 	* @access   public
    470 	*/
    471 	function getHeaders(){
    472 	    return $this->responseHeaders;
    473 	}
    474 
    475 	/**
    476 	* decodes simple types into PHP variables
    477 	*
    478 	* @param    string $value value to decode
    479 	* @param    string $type XML type to decode
    480 	* @param    string $typens XML type namespace to decode
    481 	* @return	mixed PHP value
    482 	* @access   private
    483 	*/
    484 	function decodeSimple($value, $type, $typens) {
    485 		// TODO: use the namespace!
    486 		if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
    487 			return (string) $value;
    488 		}
    489 		if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
    490 			return (int) $value;
    491 		}
    492 		if ($type == 'float' || $type == 'double' || $type == 'decimal') {
    493 			return (double) $value;
    494 		}
    495 		if ($type == 'boolean') {
    496 			if (strtolower($value) == 'false' || strtolower($value) == 'f') {
    497 				return false;
    498 			}
    499 			return (boolean) $value;
    500 		}
    501 		if ($type == 'base64' || $type == 'base64Binary') {
    502 			$this->debug('Decode base64 value');
    503 			return base64_decode($value);
    504 		}
    505 		// obscure numeric types
    506 		if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
    507 			|| $type == 'nonNegativeInteger' || $type == 'positiveInteger'
    508 			|| $type == 'unsignedInt'
    509 			|| $type == 'unsignedShort' || $type == 'unsignedByte') {
    510 			return (int) $value;
    511 		}
    512 		// bogus: parser treats array with no elements as a simple type
    513 		if ($type == 'array') {
    514 			return array();
    515 		}
    516 		// everything else
    517 		return (string) $value;
    518 	}
    519 
    520 	/**
    521 	* builds response structures for compound values (arrays/structs)
    522 	* and scalars
    523 	*
    524 	* @param    integer $pos position in node tree
    525 	* @return	mixed	PHP value
    526 	* @access   private
    527 	*/
    528 	function buildVal($pos){
    529 		if(!isset($this->message[$pos]['type'])){
    530 			$this->message[$pos]['type'] = '';
    531 		}
    532 		$this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);
    533 		// if there are children...
    534 		if($this->message[$pos]['children'] != ''){
    535 			$this->debug('in buildVal, there are children');
    536 			$children = explode('|',$this->message[$pos]['children']);
    537 			array_shift($children); // knock off empty
    538 			// md array
    539 			if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){
    540             	$r=0; // rowcount
    541             	$c=0; // colcount
    542             	foreach($children as $child_pos){
    543 					$this->debug("in buildVal, got an MD array element: $r, $c");
    544 					$params[$r][] = $this->message[$child_pos]['result'];
    545 				    $c++;
    546 				    if($c == $this->message[$pos]['arrayCols']){
    547 				    	$c = 0;
    548 						$r++;
    549 				    }
    550                 }
    551             // array
    552 			} elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){
    553                 $this->debug('in buildVal, adding array '.$this->message[$pos]['name']);
    554                 foreach($children as $child_pos){
    555                 	$params[] = &$this->message[$child_pos]['result'];
    556                 }
    557             // apache Map type: java hashtable
    558             } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){
    559                 $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']);
    560                 foreach($children as $child_pos){
    561                 	$kv = explode("|",$this->message[$child_pos]['children']);
    562                    	$params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
    563                 }
    564             // generic compound type
    565             //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
    566 		    } else {
    567 	    		// Apache Vector type: treat as an array
    568                 $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']);
    569 				if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
    570 					$notstruct = 1;
    571 				} else {
    572 					$notstruct = 0;
    573 	            }
    574             	//
    575             	foreach($children as $child_pos){
    576             		if($notstruct){
    577             			$params[] = &$this->message[$child_pos]['result'];
    578             		} else {
    579             			if (isset($params[$this->message[$child_pos]['name']])) {
    580             				// de-serialize repeated element name into an array
    581             				if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) {
    582             					$params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
    583             				}
    584             				$params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
    585             			} else {
    586 					    	$params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
    587 					    }
    588                 	}
    589                 }
    590 			}
    591 			if (isset($this->message[$pos]['xattrs'])) {
    592                 $this->debug('in buildVal, handling attributes');
    593 				foreach ($this->message[$pos]['xattrs'] as $n => $v) {
    594 					$params[$n] = $v;
    595 				}
    596 			}
    597 			// handle simpleContent
    598 			if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
    599                 $this->debug('in buildVal, handling simpleContent');
    600             	if (isset($this->message[$pos]['type'])) {
    601 					$params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
    602 				} else {
    603 					$parent = $this->message[$pos]['parent'];
    604 					if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
    605 						$params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
    606 					} else {
    607 						$params['!'] = $this->message[$pos]['cdata'];
    608 					}
    609 				}
    610 			}
    611 			$ret = is_array($params) ? $params : array();
    612 			$this->debug('in buildVal, return:');
    613 			$this->appendDebug($this->varDump($ret));
    614 			return $ret;
    615 		} else {
    616         	$this->debug('in buildVal, no children, building scalar');
    617 			$cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : '';
    618         	if (isset($this->message[$pos]['type'])) {
    619 				$ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
    620 				$this->debug("in buildVal, return: $ret");
    621 				return $ret;
    622 			}
    623 			$parent = $this->message[$pos]['parent'];
    624 			if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
    625 				$ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
    626 				$this->debug("in buildVal, return: $ret");
    627 				return $ret;
    628 			}
    629            	$ret = $this->message[$pos]['cdata'];
    630 			$this->debug("in buildVal, return: $ret");
    631            	return $ret;
    632 		}
    633 	}
    634 }
    635 
    636 /**
    637  * Backward compatibility
    638  */
    639 class soap_parser extends nusoap_parser {
    640 }
    641 
    642 
    643 ?>