Source for file Parser.php
Documentation is available at Parser.php
// +----------------------------------------------------------------------+
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Shane Caraveo <Shane@Caraveo.com> Port to PEAR and more |
// | Authors: Dietrich Ayala <dietrich@ganx4.com> Original Author |
// +----------------------------------------------------------------------+
// $Id: Parser.php,v 1.33 2003/04/20 01:05:34 shane Exp $
require_once 'SOAP/Base.php';
require_once 'SOAP/Value.php';
* this class is used by SOAP::Message and SOAP::Server to parse soap packets
* originaly based on SOAPx4 by Dietrich Ayala http://dietrich.ganx4.com/soapx4
* @version $Id: Parser.php,v 1.33 2003/04/20 01:05:34 shane Exp $
* @author Shane Caraveo <shane@php.net> Conversion to PEAR and updates
* @author Dietrich Ayala <dietrich@ganx4.com> Original Author
var $entities = array ( '&' => '&', '<' => '<', '>' => '>', "'" => ''', '"' => '"' );
var $bodyDepth; // used to handle non-root elements before root body element
* SOAP_Parser constructor
* @param string xml content
* @param string xml character encoding, defaults to 'UTF-8'
function SOAP_Parser(&$xml, $encoding = SOAP_DEFAULT_ENCODING , $attachments=NULL )
$this->attachments = $attachments;
// check the xml tag for encoding
if (preg_match('/<\?xml[^>]+encoding\s*?=\s*?(\'([^\']*)\'|"([^"]*)")[^>]*?[\?]>/',$xml,$m)) {
// determines where in the message we are (envelope,header,body,method)
// Check whether content has been read.
// prepare the xml parser
// some lame soap implementations add null bytes at the
// end of the soap stream, and expat choaks on that
$err = sprintf('XML error on line %d col %d byte %d %s',
* recurse to build a multi-dim array, used by buildResponse
function domulti ($d, &$ar, &$r, &$v, $ad=0 )
$this->domulti ($d-1 , $ar, $r[$ar[$ad]], $v, $ad+1 );
* loop through msg, building response structures
function &buildResponse ($pos)
if (isset ($this->message[$pos]['children'])) {
foreach ($children as $c => $child_pos) {
if ($this->message[$child_pos]['type'] != NULL ) {
$response[] = & $this->buildResponse ($child_pos);
for ($i = 0; $i < $ardepth; $i++ ) {
$ar[$i] += $this->message[$pos]['arrayOffset'][$i];
for ($i = 0; $i < $elc; $i++ ) {
// recurse to build a multi-dim array
$this->domulti ($ardepth, $ar, $newresp, $response[$i]);
# increment our array pointers
while ($ad > 0 && $ar[$ad] >= $this->message[$pos]['arraySize'][$ad]) {
} else if (isset ($this->message[$pos]['arrayOffset']) &&
$this->message[$pos]['arrayOffset'][0 ] > 0 ) {
$pad = $this->message[$pos]['arrayOffset'][0 ]+ count($response)*-1;
foreach ($this->message[$pos]['attrs'] as $atn => $atv) {
!strpos($atn, ':')) $attrs[$atn]= $atv;
// add current node's value
$nqn = & new Qname ($this->message[$pos]['name'],$this->message[$pos]['namespace']);
$tqn = & new Qname ($this->message[$pos]['type'],$this->message[$pos]['type_namespace']);
$response = & new SOAP_Value($nqn->fqn (), $tqn->fqn (), $response, $attrs);
if (isset ($this->message[$pos]['arrayType'])) $response->arrayType = $this->message[$pos]['arrayType'];
$nqn = & new Qname ($this->message[$pos]['name'],$this->message[$pos]['namespace']);
$tqn = & new Qname ($this->message[$pos]['type'],$this->message[$pos]['type_namespace']);
$response = & new SOAP_Value($nqn->fqn (), $tqn->fqn (), $this->message[$pos]['cdata'], $attrs);
// handle header attribute that we need
$response->actor = $this->message[$pos]['actor'];
$response->mustunderstand = $this->message[$pos]['mustUnderstand'];
* start-element handler used with xml parser
function startElement ($parser, $name, $attrs)
// position in a total number of elements, starting from 0
// update class level pos
$this->message[$pos]['type_namespace'] = '';
$this->message[$pos]['cdata'] = '';
$this->message[$pos]['pos'] = $pos;
// parent/child/depth determinations
// depth = how many levels removed from root?
// set mine as current global depth and increment global depth value
// else add self as child to whoever the current parent is
// set self as current value for this depth
// set self as current parent
$qname = & new QName($name);
$this->message[$pos]['type'] = 'Struct';
} elseif ($this->status == 'body') {
// is this element allowed to be a root?
// XXX this needs to be optimized, we loop through attrs twice now
foreach ($attrs as $key => $value) {
if (stristr($key, ':root') && !$value) {
$this->message[$pos]['type'] = 'Struct';
$this->message[$pos]['attrs'] = $attrs;
// loop through atts, logging ns and type declarations
foreach ($attrs as $key => $value) {
// if ns declarations, add to class level array of valid namespaces
if ($kqn->ns == 'xmlns') {
if (in_array($value, $this->_XMLSchema)) {
$this->_setSchemaVersion ($value);
$this->_namespaces[$value] = $prefix;
#if ($name == $this->curent_root_struct_name) {
# $this->methodNamespace = $value;
} elseif ($key == 'xmlns') {
$qname->ns = $this->_getNamespacePrefix ($value);
$qname->namespace = $value;
} elseif ($kqn->name == 'actor') {
$this->message[$pos]['actor'] = $value;
} elseif ($kqn->name == 'mustUnderstand') {
$this->message[$pos]['mustUnderstand'] = $value;
// if it's a type declaration, set type
} elseif ($kqn->name == 'type') {
$vqn = & new QName($value);
$this->message[$pos]['type'] = $vqn->name;
$this->message[$pos]['type_namespace'] = $this->_getNamespaceForPrefix ($vqn->ns );
#print "set type for {$this->message[$pos]['name']} to {$this->message[$pos]['type']}\n";
// should do something here with the namespace of specified type?
} elseif ($kqn->name == 'arrayType') {
$vqn = & new QName($value);
$this->message[$pos]['type'] = 'Array';
if (isset ($vqn->arraySize ))
$this->message[$pos]['arraySize'] = $vqn->arraySize;
#$sa = strpos($type,'[');
# $this->message[$pos]['arraySize'] = split(',',substr($type,$sa+1, strlen($type)-$sa-2));
# $type = substr($type, 0, $sa);
$this->message[$pos]['arrayType'] = $vqn->name;
} elseif ($kqn->name == 'offset') {
} elseif ($kqn->name == 'id') {
# save id to reference array
$this->message[$pos]['id'] = $value;
} elseif ($kqn->name == 'href') {
$this->message[$pos]['children'] = &$this->message[$ref_pos]['children'];
$this->message[$pos]['arraySize'] = &$this->message[$ref_pos]['arraySize'];
$this->message[$pos]['arrayType'] = &$this->message[$ref_pos]['arrayType'];
# reverse reference, store in 'need reference'
} else if (isset ($this->attachments[$value])) {
$this->message[$pos]['cdata'] = $this->attachments[$value];
// see if namespace is defined in tag
$namespace = $attrs['xmlns:'. $qname->ns ];
} else if ($qname->ns && !$qname->namespace ) {
$namespace = $this->_getNamespaceForPrefix ($qname->ns );
$this->message[$pos]['namespace'] = $namespace;
* end-element handler used with xml parser
function endElement ($parser, $name)
// position of current element is equal to the last value left in depth_array for my depth
// bring depth down a notch
$qname = & new QName($name);
// get type if not explicitly declared in an xsi:type attribute
// XXX check on integrating wsdl validation here
if ($this->message[$pos]['type'] == '') {
if (isset ($this->message[$pos]['children'])) {
/* this is slow, need to look at some faster method
$children = explode('|',$this->message[$pos]['children']);
if (count($children) > 2 &&
$this->message[$children[1]]['name'] == $this->message[$children[2]]['name']) {
$this->message[$pos]['type'] = 'Array';
$this->message[$pos]['type'] = 'Struct';
$this->message[$pos]['type'] = 'Struct';
$parent = $this->message[$pos]['parent'];
if ($this->message[$parent]['type'] == 'Array' &&
$this->message[$pos]['type'] = 'string';
// if tag we are currently closing is the method wrapper
} elseif ($qname->name == 'Body' || $qname->name == 'Header') {
// set parent back to my parent
# handle any reverse references now
$idref = $this->message[$pos]['id'];
#XXX is this stuff there already?
$this->message[$ref_pos]['children'] = &$this->message[$pos]['children'];
$this->message[$ref_pos]['arraySize'] = &$this->message[$pos]['arraySize'];
$this->message[$ref_pos]['arrayType'] = &$this->message[$pos]['arrayType'];
# wipe out our waiting list
# $this->need_references[$idref] = array();
* element content handler used with xml parser
function characterData ($parser, $data)
if (isset ($this->message[$pos]['cdata']))
$this->message[$pos]['cdata'] .= $data;
$this->message[$pos]['cdata'] = $data;
* returns an array of responses
* after parsing a soap message, use this to get the response
return $this->_raiseSoapFault ("couldn't build response");
* returns an array of header responses
* after parsing a soap message, use this to get the response
// we don't fault if there are no headers
// that can be handled by the app if necessary
* removes entities from text
function decodeEntities ($text)
return strtr($text, $trans_tbl);
Documentation generated on Mon, 11 Mar 2019 13:59:46 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|