[ Index ]

PHP Cross Reference of MantisBT

title

Body

[close]

/library/nusoap/ -> class.xmlschema.php (source)

   1  <?php
   2  
   3  
   4  
   5  
   6  /**
   7  * parses an XML Schema, allows access to it's data, other utility methods.
   8  * imperfect, no validation... yet, but quite functional.
   9  *
  10  * @author   Dietrich Ayala <dietrich@ganx4.com>
  11  * @author   Scott Nichol <snichol@users.sourceforge.net>
  12  * @version  $Id: class.xmlschema.php,v 1.53 2010/04/26 20:15:08 snichol Exp $
  13  * @access   public
  14  */
  15  class nusoap_xmlschema extends nusoap_base  {
  16      
  17      // files
  18      var $schema = '';
  19      var $xml = '';
  20      // namespaces
  21      var $enclosingNamespaces;
  22      // schema info
  23      var $schemaInfo = array();
  24      var $schemaTargetNamespace = '';
  25      // types, elements, attributes defined by the schema
  26      var $attributes = array();
  27      var $complexTypes = array();
  28      var $complexTypeStack = array();
  29      var $currentComplexType = null;
  30      var $elements = array();
  31      var $elementStack = array();
  32      var $currentElement = null;
  33      var $simpleTypes = array();
  34      var $simpleTypeStack = array();
  35      var $currentSimpleType = null;
  36      // imports
  37      var $imports = array();
  38      // parser vars
  39      var $parser;
  40      var $position = 0;
  41      var $depth = 0;
  42      var $depth_array = array();
  43      var $message = array();
  44      var $defaultNamespace = array();
  45      
  46      /**
  47      * constructor
  48      *
  49      * @param    string $schema schema document URI
  50      * @param    string $xml xml document URI
  51      * @param    string $namespaces namespaces defined in enclosing XML
  52      * @access   public
  53      */
  54  	function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){
  55          parent::nusoap_base();
  56          $this->debug('nusoap_xmlschema class instantiated, inside constructor');
  57          // files
  58          $this->schema = $schema;
  59          $this->xml = $xml;
  60  
  61          // namespaces
  62          $this->enclosingNamespaces = $namespaces;
  63          $this->namespaces = array_merge($this->namespaces, $namespaces);
  64  
  65          // parse schema file
  66          if($schema != ''){
  67              $this->debug('initial schema file: '.$schema);
  68              $this->parseFile($schema, 'schema');
  69          }
  70  
  71          // parse xml file
  72          if($xml != ''){
  73              $this->debug('initial xml file: '.$xml);
  74              $this->parseFile($xml, 'xml');
  75          }
  76  
  77      }
  78  
  79      /**
  80      * parse an XML file
  81      *
  82      * @param string $xml path/URL to XML file
  83      * @param string $type (schema | xml)
  84      * @return boolean
  85      * @access public
  86      */
  87  	function parseFile($xml,$type){
  88          // parse xml file
  89          if($xml != ""){
  90              $xmlStr = @join("",@file($xml));
  91              if($xmlStr == ""){
  92                  $msg = 'Error reading XML from '.$xml;
  93                  $this->setError($msg);
  94                  $this->debug($msg);
  95              return false;
  96              } else {
  97                  $this->debug("parsing $xml");
  98                  $this->parseString($xmlStr,$type);
  99                  $this->debug("done parsing $xml");
 100              return true;
 101              }
 102          }
 103          return false;
 104      }
 105  
 106      /**
 107      * parse an XML string
 108      *
 109      * @param    string $xml path or URL
 110      * @param    string $type (schema|xml)
 111      * @access   private
 112      */
 113  	function parseString($xml,$type){
 114          // parse xml string
 115          if($xml != ""){
 116  
 117              // Create an XML parser.
 118              $this->parser = xml_parser_create();
 119              // Set the options for parsing the XML data.
 120              xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
 121  
 122              // Set the object for the parser.
 123              xml_set_object($this->parser, $this);
 124  
 125              // Set the element handlers for the parser.
 126              if($type == "schema"){
 127                  xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
 128                  xml_set_character_data_handler($this->parser,'schemaCharacterData');
 129              } elseif($type == "xml"){
 130                  xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
 131                  xml_set_character_data_handler($this->parser,'xmlCharacterData');
 132              }
 133  
 134              // Parse the XML file.
 135              if(!xml_parse($this->parser,$xml,true)){
 136              // Display an error message.
 137                  $errstr = sprintf('XML error parsing XML schema on line %d: %s',
 138                  xml_get_current_line_number($this->parser),
 139                  xml_error_string(xml_get_error_code($this->parser))
 140                  );
 141                  $this->debug($errstr);
 142                  $this->debug("XML payload:\n" . $xml);
 143                  $this->setError($errstr);
 144              }
 145              
 146              xml_parser_free($this->parser);
 147          } else{
 148              $this->debug('no xml passed to parseString()!!');
 149              $this->setError('no xml passed to parseString()!!');
 150          }
 151      }
 152  
 153      /**
 154       * gets a type name for an unnamed type
 155       *
 156       * @param    string    Element name
 157       * @return    string    A type name for an unnamed type
 158       * @access    private
 159       */
 160  	function CreateTypeName($ename) {
 161          $scope = '';
 162          for ($i = 0; $i < count($this->complexTypeStack); $i++) {
 163              $scope .= $this->complexTypeStack[$i] . '_';
 164          }
 165          return $scope . $ename . '_ContainedType';
 166      }
 167      
 168      /**
 169      * start-element handler
 170      *
 171      * @param    string $parser XML parser object
 172      * @param    string $name element name
 173      * @param    string $attrs associative array of attributes
 174      * @access   private
 175      */
 176  	function schemaStartElement($parser, $name, $attrs) {
 177          
 178          // position in the total number of elements, starting from 0
 179          $pos = $this->position++;
 180          $depth = $this->depth++;
 181          // set self as current value for this depth
 182          $this->depth_array[$depth] = $pos;
 183          $this->message[$pos] = array('cdata' => ''); 
 184          if ($depth > 0) {
 185              $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
 186          } else {
 187              $this->defaultNamespace[$pos] = false;
 188          }
 189  
 190          // get element prefix
 191          if($prefix = $this->getPrefix($name)){
 192              // get unqualified name
 193              $name = $this->getLocalPart($name);
 194          } else {
 195              $prefix = '';
 196          }
 197          
 198          // loop thru attributes, expanding, and registering namespace declarations
 199          if(count($attrs) > 0){
 200              foreach($attrs as $k => $v){
 201                  // if ns declarations, add to class level array of valid namespaces
 202                  if(preg_match('/^xmlns/',$k)){
 203                      //$this->xdebug("$k: $v");
 204                      //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
 205                      if($ns_prefix = substr(strrchr($k,':'),1)){
 206                          //$this->xdebug("Add namespace[$ns_prefix] = $v");
 207                          $this->namespaces[$ns_prefix] = $v;
 208                      } else {
 209                          $this->defaultNamespace[$pos] = $v;
 210                          if (! $this->getPrefixFromNamespace($v)) {
 211                              $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
 212                          }
 213                      }
 214                      if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){
 215                          $this->XMLSchemaVersion = $v;
 216                          $this->namespaces['xsi'] = $v.'-instance';
 217                      }
 218                  }
 219              }
 220              foreach($attrs as $k => $v){
 221                  // expand each attribute
 222                  $k = strpos($k,':') ? $this->expandQname($k) : $k;
 223                  $v = strpos($v,':') ? $this->expandQname($v) : $v;
 224                  $eAttrs[$k] = $v;
 225              }
 226              $attrs = $eAttrs;
 227          } else {
 228              $attrs = array();
 229          }
 230          // find status, register data
 231          switch($name){
 232              case 'all':            // (optional) compositor content for a complexType
 233              case 'choice':
 234              case 'group':
 235              case 'sequence':
 236                  //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
 237                  $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
 238                  //if($name == 'all' || $name == 'sequence'){
 239                  //    $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
 240                  //}
 241              break;
 242              case 'attribute':    // complexType attribute
 243                  //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
 244                  $this->xdebug("parsing attribute:");
 245                  $this->appendDebug($this->varDump($attrs));
 246                  if (!isset($attrs['form'])) {
 247                      // TODO: handle globals
 248                      $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
 249                  }
 250                  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
 251                      $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
 252                      if (!strpos($v, ':')) {
 253                          // no namespace in arrayType attribute value...
 254                          if ($this->defaultNamespace[$pos]) {
 255                              // ...so use the default
 256                              $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
 257                          }
 258                      }
 259                  }
 260                  if(isset($attrs['name'])){
 261                      $this->attributes[$attrs['name']] = $attrs;
 262                      $aname = $attrs['name'];
 263                  } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
 264                      if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
 265                          $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
 266                      } else {
 267                          $aname = '';
 268                      }
 269                  } elseif(isset($attrs['ref'])){
 270                      $aname = $attrs['ref'];
 271                      $this->attributes[$attrs['ref']] = $attrs;
 272                  }
 273                  
 274                  if($this->currentComplexType){    // This should *always* be
 275                      $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
 276                  }
 277                  // arrayType attribute
 278                  if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
 279                      $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
 280                      $prefix = $this->getPrefix($aname);
 281                      if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
 282                          $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
 283                      } else {
 284                          $v = '';
 285                      }
 286                      if(strpos($v,'[,]')){
 287                          $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
 288                      }
 289                      $v = substr($v,0,strpos($v,'[')); // clip the []
 290                      if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
 291                          $v = $this->XMLSchemaVersion.':'.$v;
 292                      }
 293                      $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
 294                  }
 295              break;
 296              case 'complexContent':    // (optional) content for a complexType
 297                  $this->xdebug("do nothing for element $name");
 298              break;
 299              case 'complexType':
 300                  array_push($this->complexTypeStack, $this->currentComplexType);
 301                  if(isset($attrs['name'])){
 302                      // TODO: what is the scope of named complexTypes that appear
 303                      //       nested within other c complexTypes?
 304                      $this->xdebug('processing named complexType '.$attrs['name']);
 305                      //$this->currentElement = false;
 306                      $this->currentComplexType = $attrs['name'];
 307                      $this->complexTypes[$this->currentComplexType] = $attrs;
 308                      $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
 309                      // This is for constructs like
 310                      //           <complexType name="ListOfString" base="soap:Array">
 311                      //                <sequence>
 312                      //                    <element name="string" type="xsd:string"
 313                      //                        minOccurs="0" maxOccurs="unbounded" />
 314                      //                </sequence>
 315                      //            </complexType>
 316                      if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){
 317                          $this->xdebug('complexType is unusual array');
 318                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
 319                      } else {
 320                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
 321                      }
 322                  } else {
 323                      $name = $this->CreateTypeName($this->currentElement);
 324                      $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
 325                      $this->currentComplexType = $name;
 326                      //$this->currentElement = false;
 327                      $this->complexTypes[$this->currentComplexType] = $attrs;
 328                      $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
 329                      // This is for constructs like
 330                      //           <complexType name="ListOfString" base="soap:Array">
 331                      //                <sequence>
 332                      //                    <element name="string" type="xsd:string"
 333                      //                        minOccurs="0" maxOccurs="unbounded" />
 334                      //                </sequence>
 335                      //            </complexType>
 336                      if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){
 337                          $this->xdebug('complexType is unusual array');
 338                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
 339                      } else {
 340                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
 341                      }
 342                  }
 343                  $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'false';
 344              break;
 345              case 'element':
 346                  array_push($this->elementStack, $this->currentElement);
 347                  if (!isset($attrs['form'])) {
 348                      if ($this->currentComplexType) {
 349                          $attrs['form'] = $this->schemaInfo['elementFormDefault'];
 350                      } else {
 351                          // global
 352                          $attrs['form'] = 'qualified';
 353                      }
 354                  }
 355                  if(isset($attrs['type'])){
 356                      $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
 357                      if (! $this->getPrefix($attrs['type'])) {
 358                          if ($this->defaultNamespace[$pos]) {
 359                              $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
 360                              $this->xdebug('used default namespace to make type ' . $attrs['type']);
 361                          }
 362                      }
 363                      // This is for constructs like
 364                      //           <complexType name="ListOfString" base="soap:Array">
 365                      //                <sequence>
 366                      //                    <element name="string" type="xsd:string"
 367                      //                        minOccurs="0" maxOccurs="unbounded" />
 368                      //                </sequence>
 369                      //            </complexType>
 370                      if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
 371                          $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
 372                          $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
 373                      }
 374                      $this->currentElement = $attrs['name'];
 375                      $ename = $attrs['name'];
 376                  } elseif(isset($attrs['ref'])){
 377                      $this->xdebug("processing element as ref to ".$attrs['ref']);
 378                      $this->currentElement = "ref to ".$attrs['ref'];
 379                      $ename = $this->getLocalPart($attrs['ref']);
 380                  } else {
 381                      $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
 382                      $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type);
 383                      $this->currentElement = $attrs['name'];
 384                      $attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
 385                      $ename = $attrs['name'];
 386                  }
 387                  if (isset($ename) && $this->currentComplexType) {
 388                      $this->xdebug("add element $ename to complexType $this->currentComplexType");
 389                      $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
 390                  } elseif (!isset($attrs['ref'])) {
 391                      $this->xdebug("add element $ename to elements array");
 392                      $this->elements[ $attrs['name'] ] = $attrs;
 393                      $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
 394                  }
 395              break;
 396              case 'enumeration':    //    restriction value list member
 397                  $this->xdebug('enumeration ' . $attrs['value']);
 398                  if ($this->currentSimpleType) {
 399                      $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
 400                  } elseif ($this->currentComplexType) {
 401                      $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
 402                  }
 403              break;
 404              case 'extension':    // simpleContent or complexContent type extension
 405                  $this->xdebug('extension ' . $attrs['base']);
 406                  if ($this->currentComplexType) {
 407                      $ns = $this->getPrefix($attrs['base']);
 408                      if ($ns == '') {
 409                          $this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base'];
 410                      } else {
 411                          $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
 412                      }
 413                  } else {
 414                      $this->xdebug('no current complexType to set extensionBase');
 415                  }
 416              break;
 417              case 'import':
 418                  if (isset($attrs['schemaLocation'])) {
 419                      $this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
 420                      $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
 421                  } else {
 422                      $this->xdebug('import namespace ' . $attrs['namespace']);
 423                      $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
 424                      if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
 425                          $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
 426                      }
 427                  }
 428              break;
 429              case 'include':
 430                  if (isset($attrs['schemaLocation'])) {
 431                      $this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']);
 432                      $this->imports[$this->schemaTargetNamespace][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
 433                  } else {
 434                      $this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute');
 435                  }
 436              break;
 437              case 'list':    // simpleType value list
 438                  $this->xdebug("do nothing for element $name");
 439              break;
 440              case 'restriction':    // simpleType, simpleContent or complexContent value restriction
 441                  $this->xdebug('restriction ' . $attrs['base']);
 442                  if($this->currentSimpleType){
 443                      $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
 444                  } elseif($this->currentComplexType){
 445                      $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
 446                      if(strstr($attrs['base'],':') == ':Array'){
 447                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
 448                      }
 449                  }
 450              break;
 451              case 'schema':
 452                  $this->schemaInfo = $attrs;
 453                  $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
 454                  if (isset($attrs['targetNamespace'])) {
 455                      $this->schemaTargetNamespace = $attrs['targetNamespace'];
 456                  }
 457                  if (!isset($attrs['elementFormDefault'])) {
 458                      $this->schemaInfo['elementFormDefault'] = 'unqualified';
 459                  }
 460                  if (!isset($attrs['attributeFormDefault'])) {
 461                      $this->schemaInfo['attributeFormDefault'] = 'unqualified';
 462                  }
 463              break;
 464              case 'simpleContent':    // (optional) content for a complexType
 465                  if ($this->currentComplexType) {    // This should *always* be
 466                      $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'true';
 467                  } else {
 468                      $this->xdebug("do nothing for element $name because there is no current complexType");
 469                  }
 470              break;
 471              case 'simpleType':
 472                  array_push($this->simpleTypeStack, $this->currentSimpleType);
 473                  if(isset($attrs['name'])){
 474                      $this->xdebug("processing simpleType for name " . $attrs['name']);
 475                      $this->currentSimpleType = $attrs['name'];
 476                      $this->simpleTypes[ $attrs['name'] ] = $attrs;
 477                      $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
 478                      $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
 479                  } else {
 480                      $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
 481                      $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
 482                      $this->currentSimpleType = $name;
 483                      //$this->currentElement = false;
 484                      $this->simpleTypes[$this->currentSimpleType] = $attrs;
 485                      $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
 486                  }
 487              break;
 488              case 'union':    // simpleType type list
 489                  $this->xdebug("do nothing for element $name");
 490              break;
 491              default:
 492                  $this->xdebug("do not have any logic to process element $name");
 493          }
 494      }
 495  
 496      /**
 497      * end-element handler
 498      *
 499      * @param    string $parser XML parser object
 500      * @param    string $name element name
 501      * @access   private
 502      */
 503  	function schemaEndElement($parser, $name) {
 504          // bring depth down a notch
 505          $this->depth--;
 506          // position of current element is equal to the last value left in depth_array for my depth
 507          if(isset($this->depth_array[$this->depth])){
 508              $pos = $this->depth_array[$this->depth];
 509          }
 510          // get element prefix
 511          if ($prefix = $this->getPrefix($name)){
 512              // get unqualified name
 513              $name = $this->getLocalPart($name);
 514          } else {
 515              $prefix = '';
 516          }
 517          // move on...
 518          if($name == 'complexType'){
 519              $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
 520              $this->xdebug($this->varDump($this->complexTypes[$this->currentComplexType]));
 521              $this->currentComplexType = array_pop($this->complexTypeStack);
 522              //$this->currentElement = false;
 523          }
 524          if($name == 'element'){
 525              $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
 526              $this->currentElement = array_pop($this->elementStack);
 527          }
 528          if($name == 'simpleType'){
 529              $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
 530              $this->xdebug($this->varDump($this->simpleTypes[$this->currentSimpleType]));
 531              $this->currentSimpleType = array_pop($this->simpleTypeStack);
 532          }
 533      }
 534  
 535      /**
 536      * element content handler
 537      *
 538      * @param    string $parser XML parser object
 539      * @param    string $data element content
 540      * @access   private
 541      */
 542  	function schemaCharacterData($parser, $data){
 543          $pos = $this->depth_array[$this->depth - 1];
 544          $this->message[$pos]['cdata'] .= $data;
 545      }
 546  
 547      /**
 548      * serialize the schema
 549      *
 550      * @access   public
 551      */
 552  	function serializeSchema(){
 553  
 554          $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
 555          $xml = '';
 556          // imports
 557          if (sizeof($this->imports) > 0) {
 558              foreach($this->imports as $ns => $list) {
 559                  foreach ($list as $ii) {
 560                      if ($ii['location'] != '') {
 561                          $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
 562                      } else {
 563                          $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
 564                      }
 565                  }
 566              } 
 567          } 
 568          // complex types
 569          foreach($this->complexTypes as $typeName => $attrs){
 570              $contentStr = '';
 571              // serialize child elements
 572              if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
 573                  foreach($attrs['elements'] as $element => $eParts){
 574                      if(isset($eParts['ref'])){
 575                          $contentStr .= "   <$schemaPrefix:element ref=\"$element\"/>\n";
 576                      } else {
 577                          $contentStr .= "   <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
 578                          foreach ($eParts as $aName => $aValue) {
 579                              // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
 580                              if ($aName != 'name' && $aName != 'type') {
 581                                  $contentStr .= " $aName=\"$aValue\"";
 582                              }
 583                          }
 584                          $contentStr .= "/>\n";
 585                      }
 586                  }
 587                  // compositor wraps elements
 588                  if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
 589                      $contentStr = "  <$schemaPrefix:$attrs[compositor]>\n".$contentStr."  </$schemaPrefix:$attrs[compositor]>\n";
 590                  }
 591              }
 592              // attributes
 593              if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
 594                  foreach($attrs['attrs'] as $attr => $aParts){
 595                      $contentStr .= "    <$schemaPrefix:attribute";
 596                      foreach ($aParts as $a => $v) {
 597                          if ($a == 'ref' || $a == 'type') {
 598                              $contentStr .= " $a=\"".$this->contractQName($v).'"';
 599                          } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
 600                              $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
 601                              $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"';
 602                          } else {
 603                              $contentStr .= " $a=\"$v\"";
 604                          }
 605                      }
 606                      $contentStr .= "/>\n";
 607                  }
 608              }
 609              // if restriction
 610              if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
 611                  $contentStr = "   <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr."   </$schemaPrefix:restriction>\n";
 612                  // complex or simple content
 613                  if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
 614                      $contentStr = "  <$schemaPrefix:complexContent>\n".$contentStr."  </$schemaPrefix:complexContent>\n";
 615                  }
 616              }
 617              // finalize complex type
 618              if($contentStr != ''){
 619                  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
 620              } else {
 621                  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
 622              }
 623              $xml .= $contentStr;
 624          }
 625          // simple types
 626          if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
 627              foreach($this->simpleTypes as $typeName => $eParts){
 628                  $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n  <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n";
 629                  if (isset($eParts['enumeration'])) {
 630                      foreach ($eParts['enumeration'] as $e) {
 631                          $xml .= "  <$schemaPrefix:enumeration value=\"$e\"/>\n";
 632                      }
 633                  }
 634                  $xml .= "  </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
 635              }
 636          }
 637          // elements
 638          if(isset($this->elements) && count($this->elements) > 0){
 639              foreach($this->elements as $element => $eParts){
 640                  $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
 641              }
 642          }
 643          // attributes
 644          if(isset($this->attributes) && count($this->attributes) > 0){
 645              foreach($this->attributes as $attr => $aParts){
 646                  $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
 647              }
 648          }
 649          // finish 'er up
 650          $attr = '';
 651          foreach ($this->schemaInfo as $k => $v) {
 652              if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') {
 653                  $attr .= " $k=\"$v\"";
 654              }
 655          }
 656          $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
 657          foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
 658              $el .= " xmlns:$nsp=\"$ns\"";
 659          }
 660          $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";
 661          return $xml;
 662      }
 663  
 664      /**
 665      * adds debug data to the clas level debug string
 666      *
 667      * @param    string $string debug data
 668      * @access   private
 669      */
 670  	function xdebug($string){
 671          $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
 672      }
 673  
 674      /**
 675      * get the PHP type of a user defined type in the schema
 676      * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays
 677      * returns false if no type exists, or not w/ the given namespace
 678      * else returns a string that is either a native php type, or 'struct'
 679      *
 680      * @param string $type name of defined type
 681      * @param string $ns namespace of type
 682      * @return mixed
 683      * @access public
 684      * @deprecated
 685      */
 686  	function getPHPType($type,$ns){
 687          if(isset($this->typemap[$ns][$type])){
 688              //print "found type '$type' and ns $ns in typemap<br>";
 689              return $this->typemap[$ns][$type];
 690          } elseif(isset($this->complexTypes[$type])){
 691              //print "getting type '$type' and ns $ns from complexTypes array<br>";
 692              return $this->complexTypes[$type]['phpType'];
 693          }
 694          return false;
 695      }
 696  
 697      /**
 698      * returns an associative array of information about a given type
 699      * returns false if no type exists by the given name
 700      *
 701      *    For a complexType typeDef = array(
 702      *    'restrictionBase' => '',
 703      *    'phpType' => '',
 704      *    'compositor' => '(sequence|all)',
 705      *    'elements' => array(), // refs to elements array
 706      *    'attrs' => array() // refs to attributes array
 707      *    ... and so on (see addComplexType)
 708      *    )
 709      *
 710      *   For simpleType or element, the array has different keys.
 711      *
 712      * @param string $type
 713      * @return mixed
 714      * @access public
 715      * @see addComplexType
 716      * @see addSimpleType
 717      * @see addElement
 718      */
 719  	function getTypeDef($type){
 720          //$this->debug("in getTypeDef for type $type");
 721          if (substr($type, -1) == '^') {
 722              $is_element = 1;
 723              $type = substr($type, 0, -1);
 724          } else {
 725              $is_element = 0;
 726          }
 727  
 728          if((! $is_element) && isset($this->complexTypes[$type])){
 729              $this->xdebug("in getTypeDef, found complexType $type");
 730              return $this->complexTypes[$type];
 731          } elseif((! $is_element) && isset($this->simpleTypes[$type])){
 732              $this->xdebug("in getTypeDef, found simpleType $type");
 733              if (!isset($this->simpleTypes[$type]['phpType'])) {
 734                  // get info for type to tack onto the simple type
 735                  // TODO: can this ever really apply (i.e. what is a simpleType really?)
 736                  $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
 737                  $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
 738                  $etype = $this->getTypeDef($uqType);
 739                  if ($etype) {
 740                      $this->xdebug("in getTypeDef, found type for simpleType $type:");
 741                      $this->xdebug($this->varDump($etype));
 742                      if (isset($etype['phpType'])) {
 743                          $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
 744                      }
 745                      if (isset($etype['elements'])) {
 746                          $this->simpleTypes[$type]['elements'] = $etype['elements'];
 747                      }
 748                  }
 749              }
 750              return $this->simpleTypes[$type];
 751          } elseif(isset($this->elements[$type])){
 752              $this->xdebug("in getTypeDef, found element $type");
 753              if (!isset($this->elements[$type]['phpType'])) {
 754                  // get info for type to tack onto the element
 755                  $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
 756                  $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
 757                  $etype = $this->getTypeDef($uqType);
 758                  if ($etype) {
 759                      $this->xdebug("in getTypeDef, found type for element $type:");
 760                      $this->xdebug($this->varDump($etype));
 761                      if (isset($etype['phpType'])) {
 762                          $this->elements[$type]['phpType'] = $etype['phpType'];
 763                      }
 764                      if (isset($etype['elements'])) {
 765                          $this->elements[$type]['elements'] = $etype['elements'];
 766                      }
 767                      if (isset($etype['extensionBase'])) {
 768                          $this->elements[$type]['extensionBase'] = $etype['extensionBase'];
 769                      }
 770                  } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
 771                      $this->xdebug("in getTypeDef, element $type is an XSD type");
 772                      $this->elements[$type]['phpType'] = 'scalar';
 773                  }
 774              }
 775              return $this->elements[$type];
 776          } elseif(isset($this->attributes[$type])){
 777              $this->xdebug("in getTypeDef, found attribute $type");
 778              return $this->attributes[$type];
 779          } elseif (preg_match('/_ContainedType$/', $type)) {
 780              $this->xdebug("in getTypeDef, have an untyped element $type");
 781              $typeDef['typeClass'] = 'simpleType';
 782              $typeDef['phpType'] = 'scalar';
 783              $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
 784              return $typeDef;
 785          }
 786          $this->xdebug("in getTypeDef, did not find $type");
 787          return false;
 788      }
 789  
 790      /**
 791      * returns a sample serialization of a given type, or false if no type by the given name
 792      *
 793      * @param string $type name of type
 794      * @return mixed
 795      * @access public
 796      * @deprecated
 797      */
 798      function serializeTypeDef($type){
 799          //print "in sTD() for type $type<br>";
 800      if($typeDef = $this->getTypeDef($type)){
 801          $str .= '<'.$type;
 802          if(is_array($typeDef['attrs'])){
 803          foreach($typeDef['attrs'] as $attName => $data){
 804              $str .= " $attName=\"{type = ".$data['type']."}\"";
 805          }
 806          }
 807          $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
 808          if(count($typeDef['elements']) > 0){
 809          $str .= ">";
 810          foreach($typeDef['elements'] as $element => $eData){
 811              $str .= $this->serializeTypeDef($element);
 812          }
 813          $str .= "</$type>";
 814          } elseif($typeDef['typeClass'] == 'element') {
 815          $str .= "></$type>";
 816          } else {
 817          $str .= "/>";
 818          }
 819              return $str;
 820      }
 821          return false;
 822      }
 823  
 824      /**
 825      * returns HTML form elements that allow a user
 826      * to enter values for creating an instance of the given type.
 827      *
 828      * @param string $name name for type instance
 829      * @param string $type name of type
 830      * @return string
 831      * @access public
 832      * @deprecated
 833      */
 834  	function typeToForm($name,$type){
 835          // get typedef
 836          if($typeDef = $this->getTypeDef($type)){
 837              // if struct
 838              if($typeDef['phpType'] == 'struct'){
 839                  $buffer .= '<table>';
 840                  foreach($typeDef['elements'] as $child => $childDef){
 841                      $buffer .= "
 842                      <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
 843                      <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
 844                  }
 845                  $buffer .= '</table>';
 846              // if array
 847              } elseif($typeDef['phpType'] == 'array'){
 848                  $buffer .= '<table>';
 849                  for($i=0;$i < 3; $i++){
 850                      $buffer .= "
 851                      <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
 852                      <td><input type='text' name='parameters[".$name."][]'></td></tr>";
 853                  }
 854                  $buffer .= '</table>';
 855              // if scalar
 856              } else {
 857                  $buffer .= "<input type='text' name='parameters[$name]'>";
 858              }
 859          } else {
 860              $buffer .= "<input type='text' name='parameters[$name]'>";
 861          }
 862          return $buffer;
 863      }
 864      
 865      /**
 866      * adds a complex type to the schema
 867      * 
 868      * example: array
 869      * 
 870      * addType(
 871      *     'ArrayOfstring',
 872      *     'complexType',
 873      *     'array',
 874      *     '',
 875      *     'SOAP-ENC:Array',
 876      *     array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),
 877      *     'xsd:string'
 878      * );
 879      * 
 880      * example: PHP associative array ( SOAP Struct )
 881      * 
 882      * addType(
 883      *     'SOAPStruct',
 884      *     'complexType',
 885      *     'struct',
 886      *     'all',
 887      *     array('myVar'=> array('name'=>'myVar','type'=>'string')
 888      * );
 889      * 
 890      * @param name
 891      * @param typeClass (complexType|simpleType|attribute)
 892      * @param phpType: currently supported are array and struct (php assoc array)
 893      * @param compositor (all|sequence|choice)
 894      * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
 895      * @param elements = array ( name = array(name=>'',type=>'') )
 896      * @param attrs = array(
 897      *     array(
 898      *        'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
 899      *        "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
 900      *     )
 901      * )
 902      * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
 903      * @access public
 904      * @see getTypeDef
 905      */
 906  	function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
 907          $this->complexTypes[$name] = array(
 908          'name'        => $name,
 909          'typeClass'    => $typeClass,
 910          'phpType'    => $phpType,
 911          'compositor'=> $compositor,
 912          'restrictionBase' => $restrictionBase,
 913          'elements'    => $elements,
 914          'attrs'        => $attrs,
 915          'arrayType'    => $arrayType
 916          );
 917          
 918          $this->xdebug("addComplexType $name:");
 919          $this->appendDebug($this->varDump($this->complexTypes[$name]));
 920      }
 921      
 922      /**
 923      * adds a simple type to the schema
 924      *
 925      * @param string $name
 926      * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
 927      * @param string $typeClass (should always be simpleType)
 928      * @param string $phpType (should always be scalar)
 929      * @param array $enumeration array of values
 930      * @access public
 931      * @see nusoap_xmlschema
 932      * @see getTypeDef
 933      */
 934  	function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
 935          $this->simpleTypes[$name] = array(
 936          'name'            => $name,
 937          'typeClass'        => $typeClass,
 938          'phpType'        => $phpType,
 939          'type'            => $restrictionBase,
 940          'enumeration'    => $enumeration
 941          );
 942          
 943          $this->xdebug("addSimpleType $name:");
 944          $this->appendDebug($this->varDump($this->simpleTypes[$name]));
 945      }
 946  
 947      /**
 948      * adds an element to the schema
 949      *
 950      * @param array $attrs attributes that must include name and type
 951      * @see nusoap_xmlschema
 952      * @access public
 953      */
 954  	function addElement($attrs) {
 955          if (! $this->getPrefix($attrs['type'])) {
 956              $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
 957          }
 958          $this->elements[ $attrs['name'] ] = $attrs;
 959          $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
 960          
 961          $this->xdebug("addElement " . $attrs['name']);
 962          $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ]));
 963      }
 964  }
 965  
 966  /**
 967   * Backward compatibility
 968   */
 969  class XMLSchema extends nusoap_xmlschema {
 970  }
 971  
 972  
 973  ?>


Generated: Thu Jul 28 15:48:31 2011 Cross-referenced by PHPXref 0.7