Completed
Push — master ( 26cc59...c51bd4 )
by Asmir
03:44
created

src/SchemaReader.php (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
declare(strict_types=1);
4
5
namespace GoetasWebservices\XML\XSDReader;
6
7
use Closure;
8
use DOMDocument;
9
use DOMElement;
10
use DOMNode;
11
use GoetasWebservices\XML\XSDReader\Documentation\DocumentationReader;
12
use GoetasWebservices\XML\XSDReader\Documentation\StandardDocumentationReader;
13
use GoetasWebservices\XML\XSDReader\Exception\IOException;
14
use GoetasWebservices\XML\XSDReader\Exception\TypeException;
15
use GoetasWebservices\XML\XSDReader\Schema\Attribute\Attribute;
16
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeContainer;
17
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeDef;
18
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeItem;
19
use GoetasWebservices\XML\XSDReader\Schema\Attribute\Group as AttributeGroup;
20
use GoetasWebservices\XML\XSDReader\Schema\Element\Element;
21
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementContainer;
22
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementDef;
23
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementRef;
24
use GoetasWebservices\XML\XSDReader\Schema\Element\Group;
25
use GoetasWebservices\XML\XSDReader\Schema\Element\InterfaceSetMinMax;
26
use GoetasWebservices\XML\XSDReader\Schema\Element\GroupRef;
27
use GoetasWebservices\XML\XSDReader\Schema\Exception\TypeNotFoundException;
28
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Base;
29
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Extension;
30
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Restriction;
31
use GoetasWebservices\XML\XSDReader\Schema\Item;
32
use GoetasWebservices\XML\XSDReader\Schema\Schema;
33
use GoetasWebservices\XML\XSDReader\Schema\SchemaItem;
34
use GoetasWebservices\XML\XSDReader\Schema\Type\BaseComplexType;
35
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType;
36
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexTypeSimpleContent;
37
use GoetasWebservices\XML\XSDReader\Schema\Type\SimpleType;
38
use GoetasWebservices\XML\XSDReader\Schema\Type\Type;
39
use GoetasWebservices\XML\XSDReader\Utils\UrlUtils;
40
41
class SchemaReader
42
{
43
    public const XSD_NS = 'http://www.w3.org/2001/XMLSchema';
44
45
    public const XML_NS = 'http://www.w3.org/XML/1998/namespace';
46
47
    /**
48
     * @var DocumentationReader
49
     */
50
    private $documentationReader;
51
52
    /**
53
     * @var Schema[]
54
     */
55
    private $loadedFiles = array();
56
57
    /**
58
     * @var Schema[][]
59
     */
60
    private $loadedSchemas = array();
61
62
    /**
63
     * @var string[]
64
     */
65
    protected $knownLocationSchemas = [
66
        'http://www.w3.org/2001/xml.xsd' => (
67
            __DIR__.'/Resources/xml.xsd'
68
        ),
69
        'http://www.w3.org/2001/XMLSchema.xsd' => (
70
            __DIR__.'/Resources/XMLSchema.xsd'
71
        ),
72
        'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' => (
73
            __DIR__.'/Resources/oasis-200401-wss-wssecurity-secext-1.0.xsd'
74
        ),
75
        'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd' => (
76
            __DIR__.'/Resources/oasis-200401-wss-wssecurity-utility-1.0.xsd'
77
        ),
78
        'https://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd' => (
79
            __DIR__.'/Resources/xmldsig-core-schema.xsd'
80
        ),
81
        'http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd' => (
82
            __DIR__.'/Resources/xmldsig-core-schema.xsd'
83
        ),
84
    ];
85
86
    /**
87
     * @var string[]
88
     */
89
    protected static $globalSchemaInfo = array(
90
        self::XML_NS => 'http://www.w3.org/2001/xml.xsd',
91
        self::XSD_NS => 'http://www.w3.org/2001/XMLSchema.xsd',
92
    );
93
94 58
    public function __construct(DocumentationReader $documentationReader = null)
95
    {
96 58
        if (null === $documentationReader) {
97 58
            $documentationReader = new StandardDocumentationReader();
98
        }
99 58
        $this->documentationReader = $documentationReader;
100 58
    }
101
102
    public function addKnownSchemaLocation(string $remote, string $local): void
103
    {
104
        $this->knownLocationSchemas[$remote] = $local;
105
    }
106
107 49
    private function loadAttributeGroup(
108
        Schema $schema,
109
        DOMElement $node
110
    ): Closure {
111 49
        $attGroup = new AttributeGroup($schema, $node->getAttribute('name'));
112 49
        $attGroup->setDoc($this->getDocumentation($node));
113 49
        $schema->addAttributeGroup($attGroup);
114
115 49
        return function () use ($schema, $node, $attGroup) {
116 49
            SchemaReader::againstDOMNodeList(
117 49
                $node,
118 49
                function (
119
                    DOMElement $node,
120
                    DOMElement $childNode
121
                ) use (
122 49
                    $schema,
123 49
                    $attGroup
124
                ) {
125 49
                    switch ($childNode->localName) {
126 49
                        case 'attribute':
127 49
                            $attribute = $this->getAttributeFromAttributeOrRef(
128 49
                                $childNode,
129 49
                                $schema,
130 49
                                $node
131
                            );
132 49
                            $attGroup->addAttribute($attribute);
133 49
                            break;
134 49
                        case 'attributeGroup':
135 1
                            $this->findSomethingLikeAttributeGroup(
136 1
                                $schema,
137 1
                                $node,
138 1
                                $childNode,
139 1
                                $attGroup
140
                            );
141 1
                            break;
142
                    }
143 49
                }
144
            );
145 49
        };
146
    }
147
148 49
    private function getAttributeFromAttributeOrRef(
149
        DOMElement $childNode,
150
        Schema $schema,
151
        DOMElement $node
152
    ): AttributeItem {
153 49
        if ($childNode->hasAttribute('ref')) {
154 49
            $attribute = $this->findAttributeItem($schema, $node, $childNode->getAttribute('ref'));
155
        } else {
156
            /**
157
             * @var Attribute
158
             */
159 49
            $attribute = $this->loadAttribute($schema, $childNode);
160
        }
161
162 49
        return $attribute;
163
    }
164
165 49
    private function loadAttribute(
166
        Schema $schema,
167
        DOMElement $node
168
    ): Attribute {
169 49
        $attribute = new Attribute($schema, $node->getAttribute('name'));
170 49
        $attribute->setDoc($this->getDocumentation($node));
171 49
        $this->fillItem($attribute, $node);
172
173 49
        if ($node->hasAttribute('nillable')) {
174 1
            $attribute->setNil($node->getAttribute('nillable') == 'true');
175
        }
176 49
        if ($node->hasAttribute('form')) {
177 1
            $attribute->setQualified($node->getAttribute('form') == 'qualified');
178
        }
179 49
        if ($node->hasAttribute('use')) {
180 49
            $attribute->setUse($node->getAttribute('use'));
181
        }
182
183 49
        return $attribute;
184
    }
185
186 49
    private function loadAttributeOrElementDef(
187
        Schema $schema,
188
        DOMElement $node,
189
        bool $attributeDef
190
    ): Closure {
191 49
        $name = $node->getAttribute('name');
192 49
        if ($attributeDef) {
193 49
            $attribute = new AttributeDef($schema, $name);
194 49
            $schema->addAttribute($attribute);
195
        } else {
196 49
            $attribute = new ElementDef($schema, $name);
197 49
            $schema->addElement($attribute);
198
        }
199
200 49
        return function () use ($attribute, $node) {
201 49
            $this->fillItem($attribute, $node);
202 49
        };
203
    }
204
205 49
    private function loadAttributeDef(Schema $schema, DOMElement $node): Closure
206
    {
207 49
        return $this->loadAttributeOrElementDef($schema, $node, true);
208
    }
209
210 49
    private function getDocumentation(DOMElement $node): string
211
    {
212 49
        return $this->documentationReader->get($node);
213
    }
214
215
    /**
216
     * @return Closure[]
217
     */
218 49
    private function schemaNode(Schema $schema, DOMElement $node, Schema $parent = null): array
219
    {
220 49
        $this->setSchemaThingsFromNode($schema, $node, $parent);
221 49
        $functions = array();
222
223 49
        static::againstDOMNodeList(
224 49
            $node,
225 49
            function (
226
                DOMElement $node,
227
                DOMElement $childNode
228
            ) use (
229 49
                $schema,
230 49
                &$functions
231
            ) {
232 49
                $callback = null;
233
234 49
                switch ($childNode->localName) {
235 49
                    case 'attributeGroup':
236 49
                        $callback = $this->loadAttributeGroup($schema, $childNode);
237 49
                        break;
238 49
                    case 'include':
239 49
                    case 'import':
240 49
                        $callback = $this->loadImport($schema, $childNode);
241 49
                        break;
242 49
                    case 'element':
243 49
                        $callback = $this->loadElementDef($schema, $childNode);
244 49
                        break;
245 49
                    case 'attribute':
246 49
                        $callback = $this->loadAttributeDef($schema, $childNode);
247 49
                        break;
248 49
                    case 'group':
249 49
                        $callback = $this->loadGroup($schema, $childNode);
250 49
                        break;
251 49
                    case 'complexType':
252 49
                        $callback = $this->loadComplexType($schema, $childNode);
253 49
                        break;
254 49
                    case 'simpleType':
255 49
                        $callback = $this->loadSimpleType($schema, $childNode);
256 49
                        break;
257
                }
258
259 49
                if ($callback instanceof Closure) {
260 49
                    $functions[] = $callback;
261
                }
262 49
            }
263
        );
264
265 49
        return $functions;
266
    }
267
268 49
    private function loadGroupRef(Group $referenced, DOMElement $node): GroupRef
269
    {
270 49
        $ref = new GroupRef($referenced);
271 49
        $ref->setDoc($this->getDocumentation($node));
272
273 49
        self::maybeSetMax($ref, $node);
274 49
        self::maybeSetMin($ref, $node);
275
276 49
        return $ref;
277
    }
278
279 49
    private static function maybeSetMax(InterfaceSetMinMax $ref, DOMElement $node): InterfaceSetMinMax
280
    {
281
        if (
282 49
            $node->hasAttribute('maxOccurs')
283
        ) {
284 49
            $ref->setMax($node->getAttribute('maxOccurs') == 'unbounded' ? -1 : (int) $node->getAttribute('maxOccurs'));
285
        }
286
287 49
        return $ref;
288
    }
289
290 49
    private static function maybeSetMin(InterfaceSetMinMax $ref, DOMElement $node): InterfaceSetMinMax
291
    {
292 49
        if ($node->hasAttribute('minOccurs')) {
293 49
            $ref->setMin((int) $node->getAttribute('minOccurs'));
294
        }
295
296 49
        return $ref;
297
    }
298
299 49
    private function loadSequence(ElementContainer $elementContainer, DOMElement $node, int $max = null): void
300
    {
301
        $max =
302
        (
303 49
            (is_int($max) && (bool) $max) ||
304 49
            $node->getAttribute('maxOccurs') == 'unbounded' ||
305 49
            $node->getAttribute('maxOccurs') > 1
306
        )
307 49
            ? 2
308 49
            : null;
309
310 49
        static::againstDOMNodeList(
311 49
            $node,
312 49
            function (
313
                DOMElement $node,
314
                DOMElement $childNode
315
            ) use (
316 49
                $elementContainer,
317 49
                $max
318
            ) {
319 49
                $this->loadSequenceChildNode(
320 49
                    $elementContainer,
321 49
                    $node,
322 49
                    $childNode,
323 49
                    $max
324
                );
325 49
            }
326
        );
327 49
    }
328
329
    /**
330
     * @param int|null $max
331
     */
332 49
    private function loadSequenceChildNode(
333
        ElementContainer $elementContainer,
334
        DOMElement $node,
335
        DOMElement $childNode,
336
        $max
337
    ): void {
338 49
        switch ($childNode->localName) {
339 49
            case 'sequence':
340 49
            case 'choice':
341 49
            case 'all':
342 49
                $this->loadSequence(
343 49
                    $elementContainer,
344 49
                    $childNode,
345 49
                    $max
346
                );
347 49
                break;
348 49
            case 'element':
349 49
                $this->loadSequenceChildNodeLoadElement(
350 49
                    $elementContainer,
351 49
                    $node,
352 49
                    $childNode,
353 49
                    $max
354
                );
355 49
                break;
356 49
            case 'group':
357 49
                $this->addGroupAsElement(
358 49
                    $elementContainer->getSchema(),
359 49
                    $node,
360 49
                    $childNode,
361 49
                    $elementContainer
362
                );
363 49
                break;
364
        }
365 49
    }
366
367
    /**
368
     * @param int|null $max
369
     */
370 49
    private function loadSequenceChildNodeLoadElement(
371
        ElementContainer $elementContainer,
372
        DOMElement $node,
373
        DOMElement $childNode,
374
        $max
375
    ): void {
376 49
        if ($childNode->hasAttribute('ref')) {
377 49
            $element = new ElementRef(
378 49
                $this->findElement($elementContainer->getSchema(), $node, $childNode->getAttribute('ref'))
379
            );
380 49
            $element->setDoc($this->getDocumentation($childNode));
381
382 49
            self::maybeSetMax($element, $childNode);
383 49
            self::maybeSetMin($element, $childNode);
384 49
            if ($childNode->hasAttribute('nillable')) {
385
                $element->setNil($childNode->getAttribute('nillable') == 'true');
386
            }
387 49
            if ($childNode->hasAttribute('form')) {
388 49
                $element->setQualified($childNode->getAttribute('form') == 'qualified');
389
            }
390
        } else {
391 49
            $element = $this->loadElement(
392 49
                $elementContainer->getSchema(),
393 49
                $childNode
394
            );
395
        }
396 49
        if ($max > 1) {
397
            /*
398
            * although one might think the typecast is not needed with $max being `? int $max` after passing > 1,
399
            * phpstan@a4f89fa still thinks it's possibly null.
400
            * see https://github.com/phpstan/phpstan/issues/577 for related issue
401
            */
402 49
            $element->setMax((int) $max);
403
        }
404 49
        $elementContainer->addElement($element);
405 49
    }
406
407 49
    private function addGroupAsElement(
408
        Schema $schema,
409
        DOMElement $node,
410
        DOMElement $childNode,
411
        ElementContainer $elementContainer
412
    ): void {
413 49
        $referencedGroup = $this->findGroup(
414 49
            $schema,
415 49
            $node,
416 49
            $childNode->getAttribute('ref')
417
        );
418
419 49
        $group = $this->loadGroupRef($referencedGroup, $childNode);
420 49
        $elementContainer->addElement($group);
421 49
    }
422
423 49
    private function loadGroup(Schema $schema, DOMElement $node): Closure
424
    {
425 49
        $group = new Group($schema, $node->getAttribute('name'));
426 49
        $group->setDoc($this->getDocumentation($node));
427
428 49
        if ($node->hasAttribute('maxOccurs')) {
429
            /**
430
             * @var GroupRef
431
             */
432
            $group = self::maybeSetMax(new GroupRef($group), $node);
433
        }
434 49
        if ($node->hasAttribute('minOccurs')) {
435
            /**
436
             * @var GroupRef
437
             */
438
            $group = self::maybeSetMin(
439
                $group instanceof GroupRef ? $group : new GroupRef($group),
440
                $node
441
            );
442
        }
443
444 49
        $schema->addGroup($group);
445
446 49
        return function () use ($group, $node) {
447 49
            static::againstDOMNodeList(
448 49
                $node,
449 49
                function (DOMelement $node, DOMElement $childNode) use ($group) {
450 49
                    switch ($childNode->localName) {
451 49
                        case 'sequence':
452 49
                        case 'choice':
453 49
                        case 'all':
454 49
                            $this->loadSequence($group, $childNode);
455 49
                            break;
456
                    }
457 49
                }
458
            );
459 49
        };
460
    }
461
462 49
    private function loadComplexType(Schema $schema, DOMElement $node, Closure $callback = null): Closure
463
    {
464
        /**
465
         * @var bool
466
         */
467 49
        $isSimple = false;
468
469 49
        static::againstDOMNodeList(
470 49
            $node,
471 49
            function (
472
                DOMElement $node,
473
                DOMElement $childNode
474
            ) use (
475 49
                &$isSimple
476
            ) {
477 49
                if ($isSimple) {
478 1
                    return;
479
                }
480 49
                if ($childNode->localName === 'simpleContent') {
481 2
                    $isSimple = true;
482
                }
483 49
            }
484
        );
485
486 49
        $type = $isSimple ? new ComplexTypeSimpleContent($schema, $node->getAttribute('name')) : new ComplexType($schema, $node->getAttribute('name'));
487
488 49
        $type->setDoc($this->getDocumentation($node));
489 49
        if ($node->getAttribute('name')) {
490 49
            $schema->addType($type);
491
        }
492
493 49
        return function () use ($type, $node, $schema, $callback) {
494 49
            $this->fillTypeNode($type, $node, true);
495
496 49
            static::againstDOMNodeList(
497 49
                $node,
498 49
                function (
499
                    DOMElement $node,
500
                    DOMElement $childNode
501
                ) use (
502 49
                    $schema,
503 49
                    $type
504
                ) {
505 49
                    $this->loadComplexTypeFromChildNode(
506 49
                        $type,
507 49
                        $node,
508 49
                        $childNode,
509 49
                        $schema
510
                    );
511 49
                }
512
            );
513
514 49
            if ($callback instanceof Closure) {
515 49
                call_user_func($callback, $type);
516
            }
517 49
        };
518
    }
519
520 49
    private function loadComplexTypeFromChildNode(
521
        BaseComplexType $type,
522
        DOMElement $node,
523
        DOMElement $childNode,
524
        Schema $schema
525
    ): void {
526 49
        switch ($childNode->localName) {
527 49
            case 'sequence':
528 49
            case 'choice':
529 49
            case 'all':
530 49
                if ($type instanceof ElementContainer) {
531 49
                    $this->loadSequence(
532 49
                        $type,
533 49
                        $childNode
534
                    );
535
                }
536 49
                break;
537 49
            case 'attribute':
538 49
                $this->addAttributeFromAttributeOrRef(
539 49
                    $type,
540 49
                    $childNode,
541 49
                    $schema,
542 49
                    $node
543
                );
544 49
                break;
545 49
            case 'attributeGroup':
546 2
                $this->findSomethingLikeAttributeGroup(
547 2
                    $schema,
548 2
                    $node,
549 2
                    $childNode,
550 2
                    $type
551
                );
552 2
                break;
553 49
            case 'group':
554
                if (
555 1
                    $type instanceof ComplexType
556
                ) {
557 1
                    $this->addGroupAsElement(
558 1
                        $schema,
559 1
                        $node,
560 1
                        $childNode,
561 1
                        $type
562
                    );
563
                }
564 1
                break;
565
        }
566 49
    }
567
568 49
    private function loadSimpleType(Schema $schema, DOMElement $node, Closure $callback = null): Closure
569
    {
570 49
        $type = new SimpleType($schema, $node->getAttribute('name'));
571 49
        $type->setDoc($this->getDocumentation($node));
572 49
        if ($node->getAttribute('name')) {
573 49
            $schema->addType($type);
574
        }
575
576 49
        return function () use ($type, $node, $callback) {
577 49
            $this->fillTypeNode($type, $node, true);
578
579 49
            static::againstDOMNodeList(
580 49
                $node,
581 49
                function (DOMElement $node, DOMElement $childNode) use ($type) {
582 49
                    switch ($childNode->localName) {
583 49
                        case 'union':
584 49
                            $this->loadUnion($type, $childNode);
585 49
                            break;
586 49
                        case 'list':
587 49
                            $this->loadList($type, $childNode);
588 49
                            break;
589
                    }
590 49
                }
591
            );
592
593 49
            if ($callback instanceof Closure) {
594 49
                call_user_func($callback, $type);
595
            }
596 49
        };
597
    }
598
599 49
    private function loadList(SimpleType $type, DOMElement $node): void
600
    {
601 49
        if ($node->hasAttribute('itemType')) {
602
            /**
603
             * @var SimpleType
604
             */
605 49
            $listType = $this->findSomeType($type, $node, 'itemType');
606 49
            $type->setList($listType);
607
        } else {
608 49
            self::againstDOMNodeList(
609 49
                $node,
610 49
                function (
611
                    DOMElement $node,
612
                    DOMElement $childNode
613
                ) use (
614 49
                    $type
615
                ) {
616 49
                    $this->loadTypeWithCallback(
617 49
                        $type->getSchema(),
618 49
                        $childNode,
619 49
                        function (SimpleType $list) use ($type) {
620 49
                            $type->setList($list);
621 49
                        }
622
                    );
623 49
                }
624
            );
625
        }
626 49
    }
627
628 49
    private function findSomeType(
629
        SchemaItem $fromThis,
630
        DOMElement $node,
631
        string $attributeName
632
    ): SchemaItem {
633 49
        return $this->findSomeTypeFromAttribute(
634 49
            $fromThis,
635 49
            $node,
636 49
            $node->getAttribute($attributeName)
637
        );
638
    }
639
640 49
    private function findSomeTypeFromAttribute(
641
        SchemaItem $fromThis,
642
        DOMElement $node,
643
        string $attributeName
644
    ): SchemaItem {
645 49
        $out = $this->findType(
646 49
            $fromThis->getSchema(),
647 49
            $node,
648 49
            $attributeName
649
        );
650
651 49
        return $out;
652
    }
653
654 49
    private function loadUnion(SimpleType $type, DOMElement $node): void
655
    {
656 49
        if ($node->hasAttribute('memberTypes')) {
657 49
            $types = preg_split('/\s+/', $node->getAttribute('memberTypes'));
658 49
            foreach ($types as $typeName) {
659
                /**
660
                 * @var SimpleType
661
                 */
662 49
                $unionType = $this->findSomeTypeFromAttribute(
663 49
                    $type,
664 49
                    $node,
665 49
                    $typeName
666
                );
667 49
                $type->addUnion($unionType);
668
            }
669
        }
670 49
        self::againstDOMNodeList(
671 49
            $node,
672 49
            function (
673
                DOMElement $node,
674
                DOMElement $childNode
675
            ) use (
676 49
                $type
677
            ) {
678 49
                $this->loadTypeWithCallback(
679 49
                    $type->getSchema(),
680 49
                    $childNode,
681 49
                    function (SimpleType $unType) use ($type) {
682 49
                        $type->addUnion($unType);
683 49
                    }
684
                );
685 49
            }
686
        );
687 49
    }
688
689 49
    private function fillTypeNode(Type $type, DOMElement $node, bool $checkAbstract = false): void
690
    {
691 49
        if ($checkAbstract) {
692 49
            $type->setAbstract($node->getAttribute('abstract') === 'true' || $node->getAttribute('abstract') === '1');
693
        }
694
695 49
        static::againstDOMNodeList(
696 49
            $node,
697 49
            function (DOMElement $node, DOMElement $childNode) use ($type) {
698 49
                switch ($childNode->localName) {
699 49
                    case 'restriction':
700 49
                        $this->loadRestriction($type, $childNode);
701 49
                        break;
702 49
                    case 'extension':
703 49
                        if ($type instanceof BaseComplexType) {
704 49
                            $this->loadExtension($type, $childNode);
705
                        }
706 49
                        break;
707 49
                    case 'simpleContent':
708 49
                    case 'complexContent':
709 49
                        $this->fillTypeNode($type, $childNode);
710 49
                        break;
711
                }
712 49
            }
713
        );
714 49
    }
715
716 49
    private function loadExtension(BaseComplexType $type, DOMElement $node): void
717
    {
718 49
        $extension = new Extension();
719 49
        $type->setExtension($extension);
720
721 49
        if ($node->hasAttribute('base')) {
722 49
            $this->findAndSetSomeBase(
723 49
                $type,
724 49
                $extension,
725 49
                $node
726
            );
727
        }
728 49
        $this->loadExtensionChildNodes($type, $node);
729 49
    }
730
731 49
    private function findAndSetSomeBase(
732
        Type $type,
733
        Base $setBaseOnThis,
734
        DOMElement $node
735
    ): void {
736
        /**
737
         * @var Type
738
         */
739 49
        $parent = $this->findSomeType($type, $node, 'base');
740 49
        $setBaseOnThis->setBase($parent);
741 49
    }
742
743 49
    private function loadExtensionChildNodes(
744
        BaseComplexType $type,
745
        DOMElement $node
746
    ) {
747 49
        static::againstDOMNodeList(
748 49
            $node,
749 49
            function (
750
                DOMElement $node,
751
                DOMElement $childNode
752
            ) use (
753 49
                $type
754
            ) {
755 49
                switch ($childNode->localName) {
756 49
                    case 'sequence':
757 49
                    case 'choice':
758 49
                    case 'all':
759 49
                        if ($type instanceof ElementContainer) {
760 49
                            $this->loadSequence(
761 49
                                $type,
762 49
                                $childNode
763
                            );
764
                        }
765 49
                        break;
766 49
                    case 'attribute':
767 49
                        $this->addAttributeFromAttributeOrRef(
768 49
                            $type,
769 49
                            $childNode,
770 49
                            $type->getSchema(),
771 49
                            $node
772
                        );
773 49
                        break;
774 49
                    case 'attributeGroup':
775 49
                        $this->findSomethingLikeAttributeGroup(
776 49
                            $type->getSchema(),
777 49
                            $node,
778 49
                            $childNode,
779 49
                            $type
780
                        );
781 49
                        break;
782
                }
783 49
            }
784
        );
785 49
    }
786
787 49
    private function loadRestriction(Type $type, DOMElement $node): void
788
    {
789 49
        $restriction = new Restriction();
790 49
        $type->setRestriction($restriction);
791 49
        if ($node->hasAttribute('base')) {
792 49
            $this->findAndSetSomeBase($type, $restriction, $node);
793
        } else {
794 49
            self::againstDOMNodeList(
795 49
                $node,
796 49
                function (
797
                    DOMElement $node,
798
                    DOMElement $childNode
799
                ) use (
800 49
                    $type,
801 49
                    $restriction
802
                ) {
803 49
                    $this->loadTypeWithCallback(
804 49
                        $type->getSchema(),
805 49
                        $childNode,
806 49
                        function (Type $restType) use ($restriction) {
807 49
                            $restriction->setBase($restType);
808 49
                        }
809
                    );
810 49
                }
811
            );
812
        }
813 49
        self::againstDOMNodeList(
814 49
            $node,
815 49
            function (
816
                DOMElement $node,
817
                DOMElement $childNode
818
            ) use (
819 49
                $restriction
820
            ) {
821
                if (
822 49
                    in_array(
823 49
                        $childNode->localName,
824
                        [
825 49
                            'enumeration',
826
                            'pattern',
827
                            'length',
828
                            'minLength',
829
                            'maxLength',
830
                            'minInclusive',
831
                            'maxInclusive',
832
                            'minExclusive',
833
                            'maxExclusive',
834
                            'fractionDigits',
835
                            'totalDigits',
836
                            'whiteSpace',
837
                        ],
838 49
                        true
839
                    )
840
                ) {
841 49
                    $restriction->addCheck(
842 49
                        $childNode->localName,
843
                        [
844 49
                            'value' => $childNode->getAttribute('value'),
845 49
                            'doc' => $this->getDocumentation($childNode),
846
                        ]
847
                    );
848
                }
849 49
            }
850
        );
851 49
    }
852
853
    /**
854
     * @return mixed[]
855
     */
856 49
    private static function splitParts(DOMElement $node, string $typeName): array
857
    {
858 49
        $prefix = null;
859 49
        $name = $typeName;
860 49
        if (strpos($typeName, ':') !== false) {
861 49
            list($prefix, $name) = explode(':', $typeName);
862
        }
863
864 49
        $namespace = $node->lookupNamespaceUri($prefix ?: '');
865
866
        return array(
867 49
            $name,
868 49
            $namespace,
869 49
            $prefix,
870
        );
871
    }
872
873 49
    private function findAttributeItem(Schema $schema, DOMElement $node, string $typeName): AttributeItem
874
    {
875 49
        list($name, $namespace) = static::splitParts($node, $typeName);
876
877 49
        $namespace = $namespace ?: $schema->getTargetNamespace();
878
879
        try {
880 49
            return $schema->findAttribute($name, $namespace);
881
        } catch (TypeNotFoundException $e) {
882
            throw new TypeException(
883
                sprintf(
884
                    "Can't find %s named {%s}#%s, at line %d in %s ",
885
                    'attribute',
886
                    $namespace,
887
                    $name,
888
                    $node->getLineNo(),
889
                    $node->ownerDocument->documentURI
890
                ),
891
                0,
892
                $e
893
            );
894
        }
895
    }
896
897 49
    private function findAttributeGroup(Schema $schema, DOMElement $node, string $typeName): AttributeGroup
898
    {
899 49
        list($name, $namespace) = static::splitParts($node, $typeName);
900
901 49
        $namespace = $namespace ?: $schema->getTargetNamespace();
902
903
        try {
904 49
            return $schema->findAttributeGroup($name, $namespace);
905
        } catch (TypeNotFoundException $e) {
906
            throw new TypeException(
907
                sprintf(
908
                    "Can't find %s named {%s}#%s, at line %d in %s ",
909
                    'attributegroup',
910
                    $namespace,
911
                    $name,
912
                    $node->getLineNo(),
913
                    $node->ownerDocument->documentURI
914
                ),
915
                0,
916
                $e
917
            );
918
        }
919
    }
920
921 49
    private function findElement(Schema $schema, DOMElement $node, string $typeName): ElementDef
922
    {
923 49
        list($name, $namespace) = static::splitParts($node, $typeName);
924
925 49
        $namespace = $namespace ?: $schema->getTargetNamespace();
926
927
        try {
928 49
            return $schema->findElement($name, $namespace);
929
        } catch (TypeNotFoundException $e) {
930
            throw new TypeException(
931
                sprintf(
932
                    "Can't find %s named {%s}#%s, at line %d in %s ",
933
                    'element',
934
                    $namespace,
935
                    $name,
936
                    $node->getLineNo(),
937
                    $node->ownerDocument->documentURI
938
                ),
939
                0,
940
                $e
941
            );
942
        }
943
    }
944
945 49
    private function findGroup(Schema $schema, DOMElement $node, string $typeName): Group
946
    {
947 49
        list($name, $namespace) = static::splitParts($node, $typeName);
948
949 49
        $namespace = $namespace ?: $schema->getTargetNamespace();
950
951
        try {
952 49
            return $schema->findGroup($name, $namespace);
953
        } catch (TypeNotFoundException $e) {
954
            throw new TypeException(
955
                sprintf(
956
                    "Can't find %s named {%s}#%s, at line %d in %s ",
957
                    'group',
958
                    $namespace,
959
                    $name,
960
                    $node->getLineNo(),
961
                    $node->ownerDocument->documentURI
962
                ),
963
                0,
964
                $e
965
            );
966
        }
967
    }
968
969 49
    private function findType(Schema $schema, DOMElement $node, string $typeName): SchemaItem
970
    {
971 49
        list($name, $namespace) = static::splitParts($node, $typeName);
972
973 49
        $namespace = $namespace ?: $schema->getTargetNamespace();
974
975
        try {
976 49
            return $schema->findType($name, $namespace);
977
        } catch (TypeNotFoundException $e) {
978
            throw new TypeException(
979
                sprintf(
980
                    "Can't find %s named {%s}#%s, at line %d in %s ",
981
                    'type',
982
                    $namespace,
983
                    $name,
984
                    $node->getLineNo(),
985
                    $node->ownerDocument->documentURI
986
                ),
987
                0,
988
                $e
989
            );
990
        }
991
    }
992
993
    /**
994
     * @return Closure
995
     */
996 49
    private function loadElementDef(Schema $schema, DOMElement $node): Closure
997
    {
998 49
        return $this->loadAttributeOrElementDef($schema, $node, false);
999
    }
1000
1001 49
    private function fillItem(Item $element, DOMElement $node)
1002
    {
1003
        /**
1004
         * @var bool
1005
         */
1006 49
        $skip = false;
1007 49
        static::againstDOMNodeList(
1008 49
            $node,
1009 49
            function (
1010
                DOMElement $node,
1011
                DOMElement $childNode
1012
            ) use (
1013 49
                $element,
1014 49
                &$skip
1015
            ) {
1016
                if (
1017 49
                    !$skip &&
1018 49
                    in_array(
1019 49
                        $childNode->localName,
1020
                        [
1021 49
                            'complexType',
1022
                            'simpleType',
1023
                        ],
1024 49
                        true
1025
                    )
1026
                ) {
1027 49
                    $this->loadTypeWithCallback(
1028 49
                        $element->getSchema(),
1029 49
                        $childNode,
1030 49
                        function (Type $type) use ($element) {
1031 49
                            $element->setType($type);
1032 49
                        }
1033
                    );
1034 49
                    $skip = true;
1035
                }
1036 49
            }
1037
        );
1038 49
        if ($skip) {
1039 49
            return;
1040
        }
1041 49
        $this->fillItemNonLocalType($element, $node);
1042 49
    }
1043
1044 49
    private function fillItemNonLocalType(Item $element, DOMElement $node): void
1045
    {
1046 49
        if ($node->getAttribute('type')) {
1047
            /**
1048
             * @var Type
1049
             */
1050 49
            $type = $this->findSomeType($element, $node, 'type');
1051
        } else {
1052
            /**
1053
             * @var Type
1054
             */
1055 49
            $type = $this->findSomeTypeFromAttribute(
1056 49
                $element,
1057 49
                $node,
1058 49
                ($node->lookupPrefix(self::XSD_NS).':anyType')
1059
            );
1060
        }
1061
1062 49
        $element->setType($type);
1063 49
    }
1064
1065 49
    private function loadImport(
1066
        Schema $schema,
1067
        DOMElement $node
1068
    ): Closure {
1069 49
        $namespace = $node->getAttribute('namespace');
1070 49
        $schemaLocation = $node->getAttribute('schemaLocation');
1071
1072
        // postpone schema loading
1073 49
        if ($namespace && !$schemaLocation && !isset(self::$globalSchemaInfo[$namespace])) {
1074 2
            return function () use ($schema, $namespace) {
1075 2
                if (!empty($this->loadedSchemas[$namespace])) {
1076 2
                    foreach ($this->loadedSchemas[$namespace] as $s) {
1077 2
                        $schema->addSchema($s, $namespace);
0 ignored issues
show
$s is of type object<GoetasWebservices...SDReader\Schema\Schema>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1078
                    }
1079
                }
1080 2
            };
1081 49
        } elseif ($namespace && !$schemaLocation && isset($this->globalSchema[$namespace])) {
1082
            $schema->addSchema($this->globalSchema[$namespace]);
1083
        }
1084
1085 49
        $base = urldecode($node->ownerDocument->documentURI);
1086 49
        $file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute('schemaLocation'));
1087
1088 49
        if (isset($this->loadedFiles[$file])) {
1089 49
            $schema->addSchema($this->loadedFiles[$file]);
0 ignored issues
show
$this->loadedFiles[$file] is of type object<GoetasWebservices...SDReader\Schema\Schema>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1090
1091 49
            return function () {
1092 49
            };
1093
        }
1094
1095 1
        return $this->loadImportFresh($namespace, $schema, $file);
1096
    }
1097
1098 1
    private function createOrUseSchemaForNs(
1099
        Schema $schema,
1100
        string $namespace
1101
    ): Schema {
1102 1
        if (('' !== trim($namespace))) {
1103
            $newSchema = new Schema();
1104
            $newSchema->addSchema($this->getGlobalSchema());
1105
            $schema->addSchema($newSchema);
1106
        } else {
1107 1
            $newSchema = $schema;
1108
        }
1109
1110 1
        return $newSchema;
1111
    }
1112
1113
    private function loadImportFresh(
1114
        string $namespace,
1115
        Schema $schema,
1116
        string $file
1117
    ): Closure {
1118 1
        return function () use ($namespace, $schema, $file) {
1119 1
            $dom = $this->getDOM(
1120 1
            isset($this->knownLocationSchemas[$file])
1121
                ? $this->knownLocationSchemas[$file]
1122 1
                : $file
1123
            );
1124
1125 1
            $schemaNew = $this->createOrUseSchemaForNs($schema, $namespace);
1126
1127 1
            $this->setLoadedFile($file, $schemaNew);
1128
1129 1
            $callbacks = $this->schemaNode($schemaNew, $dom->documentElement, $schema);
1130
1131 1
            foreach ($callbacks as $callback) {
1132 1
                $callback();
1133
            }
1134 1
        };
1135
    }
1136
1137
    /**
1138
     * @var Schema|null
1139
     */
1140
    protected $globalSchema;
1141
1142
    /**
1143
     * @return Schema
1144
     */
1145 49
    public function getGlobalSchema(): Schema
1146
    {
1147 49
        if (!($this->globalSchema instanceof Schema)) {
1148 49
            $callbacks = array();
1149 49
            $globalSchemas = array();
1150
            /**
1151
             * @var string $namespace
1152
             */
1153 49
            foreach (self::$globalSchemaInfo as $namespace => $uri) {
1154 49
                $this->setLoadedFile(
1155 49
                    $uri,
1156 49
                    $globalSchemas[$namespace] = $schema = new Schema()
1157
                );
1158 49
                if ($namespace === self::XSD_NS) {
1159 49
                    $this->globalSchema = $schema;
1160
                }
1161 49
                $xml = $this->getDOM($this->knownLocationSchemas[$uri]);
1162 49
                $callbacks = array_merge($callbacks, $this->schemaNode($schema, $xml->documentElement));
1163
            }
1164
1165 49
            $globalSchemas[(string) static::XSD_NS]->addType(new SimpleType($globalSchemas[(string) static::XSD_NS], 'anySimpleType'));
1166 49
            $globalSchemas[(string) static::XSD_NS]->addType(new SimpleType($globalSchemas[(string) static::XSD_NS], 'anyType'));
1167
1168 49
            $globalSchemas[(string) static::XML_NS]->addSchema(
1169 49
                $globalSchemas[(string) static::XSD_NS],
1170 49
                (string) static::XSD_NS
1171
            );
1172 49
            $globalSchemas[(string) static::XSD_NS]->addSchema(
1173 49
                $globalSchemas[(string) static::XML_NS],
1174 49
                (string) static::XML_NS
1175
            );
1176
1177
            /**
1178
             * @var Closure
1179
             */
1180 49
            foreach ($callbacks as $callback) {
1181 49
                $callback();
1182
            }
1183
        }
1184
1185
        /**
1186
         * @var Schema
1187
         */
1188 49
        $out = $this->globalSchema;
1189
1190 49
        if (!($out instanceof Schema)) {
1191
            throw new TypeException('Globa schema not discoverd');
1192
        }
1193
1194 49
        return $out;
1195
    }
1196
1197 1
    public function readNodes(array $nodes, string $file = null)
1198
    {
1199 1
        $rootSchema = new Schema();
1200 1
        $rootSchema->addSchema($this->getGlobalSchema());
0 ignored issues
show
$this->getGlobalSchema() is of type object<GoetasWebservices...SDReader\Schema\Schema>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1201
1202 1
        if ($file !== null) {
1203
            $this->setLoadedFile($file, $rootSchema);
1204
        }
1205
1206 1
        $all = array();
1207 1
        foreach ($nodes as $k => $node) {
1208 1
            if (($node instanceof \DOMElement) && $node->namespaceURI === self::XSD_NS && $node->localName == 'schema') {
1209 1
                $holderSchema = new Schema();
1210 1
                $holderSchema->addSchema($this->getGlobalSchema());
0 ignored issues
show
$this->getGlobalSchema() is of type object<GoetasWebservices...SDReader\Schema\Schema>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1211
1212 1
                $this->setLoadedSchema($node, $holderSchema);
1213
1214 1
                $rootSchema->addSchema($holderSchema);
0 ignored issues
show
$holderSchema is of type object<GoetasWebservices...SDReader\Schema\Schema>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1215
1216 1
                $callbacks = $this->schemaNode($holderSchema, $node);
1217 1
                $all = array_merge($callbacks, $all);
1218
            }
1219
        }
1220
1221 1
        foreach ($all as $callback) {
1222 1
            call_user_func($callback);
1223
        }
1224
1225 1
        return $rootSchema;
1226
    }
1227
1228 48
    public function readNode(DOMElement $node, string $file = null): Schema
1229
    {
1230 48
        $rootSchema = new Schema();
1231 48
        $rootSchema->addSchema($this->getGlobalSchema());
1232
1233 48
        if ($file !== null) {
1234 47
            $this->setLoadedFile($file, $rootSchema);
1235
        }
1236
1237 48
        $this->setLoadedSchema($node, $rootSchema);
1238
1239 48
        $callbacks = $this->schemaNode($rootSchema, $node);
1240
1241 48
        foreach ($callbacks as $callback) {
1242 42
            call_user_func($callback);
1243
        }
1244
1245 48
        return $rootSchema;
1246
    }
1247
1248
    /**
1249
     * @throws IOException
1250
     */
1251 46
    public function readString(string $content, string $file = 'schema.xsd'): Schema
1252
    {
1253 46
        $xml = new DOMDocument('1.0', 'UTF-8');
1254 46
        if (!$xml->loadXML($content)) {
1255
            throw new IOException("Can't load the schema");
1256
        }
1257 46
        $xml->documentURI = $file;
1258
1259 46
        return $this->readNode($xml->documentElement, $file);
1260
    }
1261
1262 1
    public function readFile(string $file): Schema
1263
    {
1264 1
        $xml = $this->getDOM($file);
1265
1266 1
        return $this->readNode($xml->documentElement, $file);
1267
    }
1268
1269
    /**
1270
     * @throws IOException
1271
     */
1272 49
    private function getDOM(string $file): DOMDocument
1273
    {
1274 49
        $xml = new DOMDocument('1.0', 'UTF-8');
1275 49
        if (!$xml->load($file)) {
1276
            throw new IOException("Can't load the file $file");
1277
        }
1278
1279 49
        return $xml;
1280
    }
1281
1282 49
    private static function againstDOMNodeList(
1283
        DOMElement $node,
1284
        Closure $againstNodeList
1285
    ) {
1286 49
        $limit = $node->childNodes->length;
1287 49
        for ($i = 0; $i < $limit; $i += 1) {
1288
            /**
1289
             * @var DOMNode
1290
             */
1291 49
            $childNode = $node->childNodes->item($i);
1292
1293 49
            if ($childNode instanceof DOMElement) {
1294 49
                $againstNodeList(
1295 49
                    $node,
1296 49
                    $childNode
1297
                );
1298
            }
1299
        }
1300 49
    }
1301
1302 49
    private function loadTypeWithCallback(
1303
        Schema $schema,
1304
        DOMElement $childNode,
1305
        Closure $callback
1306
    ) {
1307
        /**
1308
         * @var Closure|null $func
1309
         */
1310 49
        $func = null;
1311
1312 49
        switch ($childNode->localName) {
1313 49
            case 'complexType':
1314 49
                $func = $this->loadComplexType($schema, $childNode, $callback);
1315 49
                break;
1316 49
            case 'simpleType':
1317 49
                $func = $this->loadSimpleType($schema, $childNode, $callback);
1318 49
                break;
1319
        }
1320
1321 49
        if ($func instanceof Closure) {
1322 49
            call_user_func($func);
1323
        }
1324 49
    }
1325
1326 49
    private function loadElement(
1327
        Schema $schema,
1328
        DOMElement $node
1329
    ): Element {
1330 49
        $element = new Element($schema, $node->getAttribute('name'));
1331 49
        $element->setDoc($this->getDocumentation($node));
1332
1333 49
        $this->fillItem($element, $node);
1334
1335 49
        self::maybeSetMax($element, $node);
1336 49
        self::maybeSetMin($element, $node);
1337
1338 49
        $xp = new \DOMXPath($node->ownerDocument);
1339 49
        $xp->registerNamespace('xs', 'http://www.w3.org/2001/XMLSchema');
1340
1341 49
        if ($xp->query('ancestor::xs:choice', $node)->length) {
1342 49
            $element->setMin(0);
1343
        }
1344
1345 49
        if ($node->hasAttribute('nillable')) {
1346 3
            $element->setNil($node->getAttribute('nillable') == 'true');
1347
        }
1348 49
        if ($node->hasAttribute('form')) {
1349 3
            $element->setQualified($node->getAttribute('form') == 'qualified');
1350
        }
1351
1352 49
        return $element;
1353
    }
1354
1355 49
    private function addAttributeFromAttributeOrRef(
1356
        BaseComplexType $type,
1357
        DOMElement $childNode,
1358
        Schema $schema,
1359
        DOMElement $node
1360
    ): void {
1361 49
        $attribute = $this->getAttributeFromAttributeOrRef(
1362 49
            $childNode,
1363 49
            $schema,
1364 49
            $node
1365
        );
1366
1367 49
        $type->addAttribute($attribute);
1368 49
    }
1369
1370 49
    private function findSomethingLikeAttributeGroup(
1371
        Schema $schema,
1372
        DOMElement $node,
1373
        DOMElement $childNode,
1374
        AttributeContainer $addToThis
1375
    ): void {
1376 49
        $attribute = $this->findAttributeGroup($schema, $node, $childNode->getAttribute('ref'));
1377 49
        $addToThis->addAttribute($attribute);
1378 49
    }
1379
1380 49
    private function setLoadedFile(string $key, Schema $schema): void
1381
    {
1382 49
        $this->loadedFiles[$key] = $schema;
1383 49
    }
1384
1385 49
    private function setLoadedSchema(DOMElement $node, Schema $schema): void
1386
    {
1387 49
        if ($node->hasAttribute('targetNamespace')) {
1388 49
            $this->loadedSchemas[$node->getAttribute('targetNamespace')][] = $schema;
1389
        }
1390 49
    }
1391
1392 49
    private function setSchemaThingsFromNode(
1393
        Schema $schema,
1394
        DOMElement $node,
1395
        Schema $parent = null
1396
    ): void {
1397 49
        $schema->setDoc($this->getDocumentation($node));
1398
1399 49
        if ($node->hasAttribute('targetNamespace')) {
1400 49
            $schema->setTargetNamespace($node->getAttribute('targetNamespace'));
1401
        } elseif ($parent instanceof Schema) {
1402
            $schema->setTargetNamespace($parent->getTargetNamespace());
1403
        }
1404 49
        $schema->setElementsQualification($node->getAttribute('elementFormDefault') == 'qualified');
1405 49
        $schema->setAttributesQualification($node->getAttribute('attributeFormDefault') == 'qualified');
1406 49
        $schema->setDoc($this->getDocumentation($node));
1407 49
    }
1408
}
1409