source: pro-violet-viettel/sourcecode/application/libraries/nusoap/class.xmlschema.php @ 710

Last change on this file since 710 was 419, checked in by dungnv, 11 years ago
File size: 35.4 KB
Line 
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*/
15class 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 */
969class XMLSchema extends nusoap_xmlschema {
970}
971
972
973?>
Note: See TracBrowser for help on using the repository browser.