source: pmb4.1/trunk/fuentes/pmb/classes/nusoap/class.xmlschema.php @ 478

Last change on this file since 478 was 478, checked in by mabarracus, 4 years ago

copy trusty code 4.1

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