goetas /
xsd-reader
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | namespace Goetas\XML\XSDReader; |
||
| 3 | |||
| 4 | use DOMDocument; |
||
| 5 | use DOMElement; |
||
| 6 | use Goetas\XML\XSDReader\Utils\UrlUtils; |
||
| 7 | use Goetas\XML\XSDReader\Schema\Schema; |
||
| 8 | use Goetas\XML\XSDReader\Schema\Element\Element; |
||
| 9 | use Goetas\XML\XSDReader\Schema\Attribute\Attribute; |
||
| 10 | use Goetas\XML\XSDReader\Schema\Type\ComplexType; |
||
| 11 | use Goetas\XML\XSDReader\Schema\Type\SimpleType; |
||
| 12 | use Goetas\XML\XSDReader\Schema\Type\Type; |
||
| 13 | use Goetas\XML\XSDReader\Schema\Type\BaseComplexType; |
||
| 14 | use Goetas\XML\XSDReader\Schema\Item; |
||
| 15 | use Goetas\XML\XSDReader\Exception\TypeException; |
||
| 16 | use Goetas\XML\XSDReader\Exception\IOException; |
||
| 17 | use Goetas\XML\XSDReader\Schema\Attribute\Group as AttributeGroup; |
||
| 18 | use Goetas\XML\XSDReader\Schema\Element\Group; |
||
| 19 | use Goetas\XML\XSDReader\Schema\Element\ElementContainer; |
||
| 20 | use Goetas\XML\XSDReader\Schema\Type\ComplexTypeSimpleContent; |
||
| 21 | use Goetas\XML\XSDReader\Schema\Element\ElementDef; |
||
| 22 | use Goetas\XML\XSDReader\Schema\Inheritance\Restriction; |
||
| 23 | use Goetas\XML\XSDReader\Schema\Inheritance\Extension; |
||
| 24 | use Goetas\XML\XSDReader\Schema\Exception\TypeNotFoundException; |
||
| 25 | use Goetas\XML\XSDReader\Schema\Element\ElementRef; |
||
| 26 | use Goetas\XML\XSDReader\Schema\Attribute\AttributeRef; |
||
| 27 | use Goetas\XML\XSDReader\Schema\Element\ElementItem; |
||
| 28 | use Goetas\XML\XSDReader\Schema\Attribute\AttributeDef; |
||
| 29 | use Goetas\XML\XSDReader\Schema\Element\GroupRef; |
||
| 30 | |||
| 31 | class SchemaReader |
||
| 32 | { |
||
| 33 | |||
| 34 | const XSD_NS = "http://www.w3.org/2001/XMLSchema"; |
||
| 35 | |||
| 36 | const XML_NS = "http://www.w3.org/XML/1998/namespace"; |
||
| 37 | |||
| 38 | private $loadedFiles = array(); |
||
| 39 | |||
| 40 | private $knowLocationSchemas = array(); |
||
| 41 | |||
| 42 | private static $globalSchemaInfo = array( |
||
| 43 | self::XML_NS => 'http://www.w3.org/2001/xml.xsd', |
||
| 44 | self::XSD_NS => 'http://www.w3.org/2001/XMLSchema.xsd' |
||
| 45 | ); |
||
| 46 | |||
| 47 | public function __construct() |
||
| 48 | { |
||
| 49 | $this->addKnownSchemaLocation('http://www.w3.org/2001/xml.xsd', __DIR__ . '/Resources/xml.xsd'); |
||
| 50 | $this->addKnownSchemaLocation('http://www.w3.org/2001/XMLSchema.xsd', __DIR__ . '/Resources/XMLSchema.xsd'); |
||
| 51 | } |
||
| 52 | |||
| 53 | public function addKnownSchemaLocation($remote, $local) |
||
| 54 | { |
||
| 55 | $this->knowLocationSchemas[$remote] = $local; |
||
| 56 | } |
||
| 57 | |||
| 58 | private function loadAttributeGroup(Schema $schema, DOMElement $node) |
||
| 59 | { |
||
| 60 | $attGroup = new AttributeGroup($schema, $node->getAttribute("name")); |
||
| 61 | $attGroup->setDoc($this->getDocumentation($node)); |
||
| 62 | $schema->addAttributeGroup($attGroup); |
||
| 63 | |||
| 64 | return function () use($schema, $node, $attGroup) |
||
| 65 | { |
||
| 66 | foreach ($node->childNodes as $childNode) { |
||
| 67 | switch ($childNode->localName) { |
||
| 68 | case 'attribute': |
||
| 69 | if ($childNode->hasAttribute("ref")) { |
||
| 70 | $attribute = $this->findSomething('findAttribute', $schema, $node, $childNode->getAttribute("ref")); |
||
| 71 | } else { |
||
| 72 | $attribute = $this->loadAttribute($schema, $childNode); |
||
| 73 | } |
||
| 74 | $attGroup->addAttribute($attribute); |
||
| 75 | break; |
||
| 76 | case 'attributeGroup': |
||
| 77 | |||
| 78 | $attribute = $this->findSomething('findAttributeGroup', $schema, $node, $childNode->getAttribute("ref")); |
||
| 79 | $attGroup->addAttribute($attribute); |
||
| 80 | break; |
||
| 81 | } |
||
| 82 | } |
||
| 83 | }; |
||
| 84 | } |
||
| 85 | |||
| 86 | private function loadAttribute(Schema $schema, DOMElement $node) |
||
| 87 | { |
||
| 88 | $attribute = new Attribute($schema, $node->getAttribute("name")); |
||
| 89 | $attribute->setDoc($this->getDocumentation($node)); |
||
| 90 | $this->fillItem($attribute, $node); |
||
| 91 | |||
| 92 | if ($node->hasAttribute("nillable")) { |
||
| 93 | $attribute->setNil($node->getAttribute("nillable") == "true"); |
||
| 94 | } |
||
| 95 | if ($node->hasAttribute("form")) { |
||
| 96 | $attribute->setQualified($node->getAttribute("form") == "qualified"); |
||
| 97 | } |
||
| 98 | if ($node->hasAttribute("use")) { |
||
| 99 | $attribute->setUse($node->getAttribute("use")); |
||
| 100 | } |
||
| 101 | return $attribute; |
||
| 102 | } |
||
| 103 | |||
| 104 | |||
| 105 | private function loadAttributeDef(Schema $schema, DOMElement $node) |
||
| 106 | { |
||
| 107 | $attribute = new AttributeDef($schema, $node->getAttribute("name")); |
||
| 108 | |||
| 109 | $schema->addAttribute($attribute); |
||
| 110 | |||
| 111 | return function () use($attribute, $schema, $node) |
||
| 112 | { |
||
| 113 | $this->fillItem($attribute, $node); |
||
| 114 | }; |
||
| 115 | } |
||
| 116 | |||
| 117 | /** |
||
| 118 | * @param DOMElement $node |
||
| 119 | * @return string |
||
| 120 | */ |
||
| 121 | private function getDocumentation(DOMElement $node) |
||
| 122 | { |
||
| 123 | $doc = ''; |
||
| 124 | foreach ($node->childNodes as $childNode) { |
||
| 125 | if ($childNode->localName == "annotation") { |
||
| 126 | foreach ($childNode->childNodes as $subChildNode) { |
||
| 127 | if ($subChildNode->localName == "documentation") { |
||
| 128 | $doc .= ($subChildNode->nodeValue); |
||
| 129 | } |
||
| 130 | } |
||
| 131 | } |
||
| 132 | } |
||
| 133 | $doc = preg_replace('/[\t ]+/', ' ', $doc); |
||
| 134 | return trim($doc); |
||
| 135 | } |
||
| 136 | |||
| 137 | /** |
||
| 138 | * |
||
| 139 | * @param Schema $schema |
||
| 140 | * @param DOMElement $node |
||
| 141 | * @param Schema $parent |
||
| 142 | * @return array |
||
| 143 | */ |
||
| 144 | private function schemaNode(Schema $schema, DOMElement $node, Schema $parent = null) |
||
| 145 | { |
||
| 146 | $schema->setDoc($this->getDocumentation($node)); |
||
| 147 | |||
| 148 | if ($node->hasAttribute("targetNamespace")) { |
||
| 149 | $schema->setTargetNamespace($node->getAttribute("targetNamespace")); |
||
| 150 | } elseif ($parent) { |
||
| 151 | $schema->setTargetNamespace($parent->getTargetNamespace()); |
||
| 152 | } |
||
| 153 | $schema->setElementsQualification(! $node->hasAttribute("elementFormDefault") || $node->getAttribute("elementFormDefault") == "qualified"); |
||
| 154 | $schema->setAttributesQualification(! $node->hasAttribute("attributeFormDefault") || $node->getAttribute("attributeFormDefault") == "qualified"); |
||
| 155 | $schema->setDoc($this->getDocumentation($node)); |
||
| 156 | $functions = array(); |
||
| 157 | |||
| 158 | foreach ($node->childNodes as $childNode) { |
||
| 159 | switch ($childNode->localName) { |
||
| 160 | case 'include': |
||
| 161 | case 'import': |
||
| 162 | $functions[] = $this->loadImport($schema, $childNode); |
||
| 163 | break; |
||
| 164 | case 'element': |
||
| 165 | $functions[] = $this->loadElementDef($schema, $childNode); |
||
| 166 | break; |
||
| 167 | case 'attribute': |
||
| 168 | $functions[] = $this->loadAttributeDef($schema, $childNode); |
||
| 169 | break; |
||
| 170 | case 'attributeGroup': |
||
| 171 | $functions[] = $this->loadAttributeGroup($schema, $childNode); |
||
| 172 | break; |
||
| 173 | case 'group': |
||
| 174 | $functions[] = $this->loadGroup($schema, $childNode); |
||
| 175 | break; |
||
| 176 | case 'complexType': |
||
| 177 | $functions[] = $this->loadComplexType($schema, $childNode); |
||
| 178 | break; |
||
| 179 | case 'simpleType': |
||
| 180 | $functions[] = $this->loadSimpleType($schema, $childNode); |
||
| 181 | break; |
||
| 182 | } |
||
| 183 | } |
||
| 184 | |||
| 185 | return $functions; |
||
| 186 | } |
||
| 187 | |||
| 188 | private function loadElement(Schema $schema, DOMElement $node) |
||
| 189 | { |
||
| 190 | $element = new Element($schema, $node->getAttribute("name")); |
||
| 191 | $element->setDoc($this->getDocumentation($node)); |
||
| 192 | |||
| 193 | $this->fillItem($element, $node); |
||
| 194 | |||
| 195 | if ($node->hasAttribute("maxOccurs")) { |
||
| 196 | $element->setMax($node->getAttribute("maxOccurs") == "unbounded" ? - 1 : (int)$node->getAttribute("maxOccurs")); |
||
| 197 | } |
||
| 198 | if ($node->hasAttribute("minOccurs")) { |
||
| 199 | $element->setMin((int)$node->getAttribute("minOccurs")); |
||
| 200 | } |
||
| 201 | if ($node->hasAttribute("nillable")) { |
||
| 202 | $element->setNil($node->getAttribute("nillable") == "true"); |
||
| 203 | } |
||
| 204 | if ($node->hasAttribute("form")) { |
||
| 205 | $element->setQualified($node->getAttribute("form") == "qualified"); |
||
| 206 | } |
||
| 207 | return $element; |
||
| 208 | } |
||
| 209 | |||
| 210 | private function loadGroupRef(Group $referenced, DOMElement $node) |
||
| 211 | { |
||
| 212 | $ref = new GroupRef($referenced); |
||
| 213 | $ref->setDoc($this->getDocumentation($node)); |
||
| 214 | |||
| 215 | if ($node->hasAttribute("maxOccurs")) { |
||
| 216 | $ref->setMax($node->getAttribute("maxOccurs") == "unbounded" ? - 1 : (int)$node->getAttribute("maxOccurs")); |
||
| 217 | } |
||
| 218 | if ($node->hasAttribute("minOccurs")) { |
||
| 219 | $ref->setMin((int)$node->getAttribute("minOccurs")); |
||
| 220 | } |
||
| 221 | |||
| 222 | return $ref; |
||
| 223 | } |
||
| 224 | |||
| 225 | private function loadElementRef(ElementDef $referenced, DOMElement $node) |
||
| 226 | { |
||
| 227 | $ref = new ElementRef($referenced); |
||
| 228 | $ref->setDoc($this->getDocumentation($node)); |
||
| 229 | |||
| 230 | if ($node->hasAttribute("maxOccurs")) { |
||
| 231 | $ref->setMax($node->getAttribute("maxOccurs") == "unbounded" ? - 1 : (int)$node->getAttribute("maxOccurs")); |
||
| 232 | } |
||
| 233 | if ($node->hasAttribute("minOccurs")) { |
||
| 234 | $ref->setMin((int)$node->getAttribute("minOccurs")); |
||
| 235 | } |
||
| 236 | if ($node->hasAttribute("nillable")) { |
||
| 237 | $ref->setNil($node->getAttribute("nillable") == "true"); |
||
| 238 | } |
||
| 239 | if ($node->hasAttribute("form")) { |
||
| 240 | $ref->setQualified($node->getAttribute("form") == "qualified"); |
||
| 241 | } |
||
| 242 | |||
| 243 | return $ref; |
||
| 244 | } |
||
| 245 | |||
| 246 | |||
| 247 | private function loadAttributeRef(AttributeDef $referencedAttribiute, DOMElement $node) |
||
| 248 | { |
||
| 249 | $attribute = new AttributeRef($referencedAttribiute); |
||
| 250 | $attribute->setDoc($this->getDocumentation($node)); |
||
| 251 | |||
| 252 | if ($node->hasAttribute("nillable")) { |
||
| 253 | $attribute->setNil($node->getAttribute("nillable") == "true"); |
||
| 254 | } |
||
| 255 | if ($node->hasAttribute("form")) { |
||
| 256 | $attribute->setQualified($node->getAttribute("form") == "qualified"); |
||
| 257 | } |
||
| 258 | if ($node->hasAttribute("use")) { |
||
| 259 | $attribute->setUse($node->getAttribute("use")); |
||
| 260 | } |
||
| 261 | return $attribute; |
||
| 262 | } |
||
| 263 | |||
| 264 | private function loadSequence(ElementContainer $elementContainer, DOMElement $node, $max = null) |
||
| 265 | { |
||
| 266 | $max = $max || $node->getAttribute("maxOccurs")=="unbounded" || $node->getAttribute("maxOccurs")>1 ? 2 :null; |
||
| 267 | |||
| 268 | foreach ($node->childNodes as $childNode) { |
||
| 269 | |||
| 270 | switch ($childNode->localName) { |
||
| 271 | case 'choice': |
||
| 272 | case 'sequence': |
||
| 273 | case 'all': |
||
| 274 | $this->loadSequence($elementContainer, $childNode, $max); |
||
| 275 | break; |
||
| 276 | case 'element': |
||
| 277 | if ($childNode->hasAttribute("ref")) { |
||
| 278 | $referencedElement = $this->findSomething('findElement', $elementContainer->getSchema(), $node, $childNode->getAttribute("ref")); |
||
| 279 | $element = $this->loadElementRef($referencedElement, $childNode); |
||
| 280 | } else { |
||
| 281 | $element = $this->loadElement($elementContainer->getSchema(), $childNode); |
||
| 282 | } |
||
| 283 | if ($max) { |
||
| 284 | $element->setMax($max); |
||
| 285 | } |
||
| 286 | $elementContainer->addElement($element); |
||
| 287 | break; |
||
| 288 | case 'group': |
||
| 289 | $referencedGroup = $this->findSomething('findGroup', $elementContainer->getSchema(), $node, $childNode->getAttribute("ref")); |
||
| 290 | |||
| 291 | $group = $this->loadGroupRef($referencedGroup, $childNode); |
||
| 292 | $elementContainer->addElement($group); |
||
| 293 | break; |
||
| 294 | } |
||
| 295 | } |
||
| 296 | } |
||
| 297 | |||
| 298 | private function loadGroup(Schema $schema, DOMElement $node) |
||
| 299 | { |
||
| 300 | $group = new Group($schema, $node->getAttribute("name")); |
||
| 301 | $group->setDoc($this->getDocumentation($node)); |
||
| 302 | |||
| 303 | if ($node->hasAttribute("maxOccurs")) { |
||
| 304 | $group->setMax($node->getAttribute("maxOccurs") == "unbounded" ? - 1 : (int)$node->getAttribute("maxOccurs")); |
||
| 305 | } |
||
| 306 | if ($node->hasAttribute("minOccurs")) { |
||
| 307 | $group->setMin((int)$node->getAttribute("minOccurs")); |
||
| 308 | } |
||
| 309 | |||
| 310 | $schema->addGroup($group); |
||
| 311 | |||
| 312 | return function () use($group, $node) |
||
| 313 | { |
||
| 314 | foreach ($node->childNodes as $childNode) { |
||
| 315 | switch ($childNode->localName) { |
||
| 316 | case 'sequence': |
||
| 317 | case 'choice': |
||
| 318 | case 'all': |
||
| 319 | $this->loadSequence($group, $childNode); |
||
| 320 | break; |
||
| 321 | } |
||
| 322 | } |
||
| 323 | }; |
||
| 324 | } |
||
| 325 | |||
| 326 | private function loadComplexType(Schema $schema, DOMElement $node, $callback = null) |
||
| 327 | { |
||
| 328 | $isSimple = false; |
||
| 329 | |||
| 330 | foreach ($node->childNodes as $childNode) { |
||
| 331 | if ($childNode->localName === "simpleContent") { |
||
| 332 | $isSimple = true; |
||
| 333 | break; |
||
| 334 | } |
||
| 335 | } |
||
| 336 | |||
| 337 | $type = $isSimple ? new ComplexTypeSimpleContent($schema, $node->getAttribute("name")) : new ComplexType($schema, $node->getAttribute("name")); |
||
| 338 | |||
| 339 | $type->setDoc($this->getDocumentation($node)); |
||
| 340 | if ($node->getAttribute("name")) { |
||
| 341 | $schema->addType($type); |
||
| 342 | } |
||
| 343 | |||
| 344 | return function () use($type, $node, $schema, $callback) |
||
| 345 | { |
||
| 346 | |||
| 347 | $this->fillTypeNode($type, $node); |
||
| 348 | |||
| 349 | foreach ($node->childNodes as $childNode) { |
||
| 350 | switch ($childNode->localName) { |
||
| 351 | case 'sequence': |
||
| 352 | case 'choice': |
||
| 353 | case 'all': |
||
| 354 | $this->loadSequence($type, $childNode); |
||
| 355 | break; |
||
| 356 | case 'attribute': |
||
| 357 | if ($childNode->hasAttribute("ref")) { |
||
| 358 | $referencedAttribute = $this->findSomething('findAttribute', $schema, $node, $childNode->getAttribute("ref")); |
||
| 359 | $attribute = $this->loadAttributeRef($referencedAttribute, $childNode); |
||
| 360 | } else { |
||
| 361 | $attribute = $this->loadAttribute($schema, $childNode); |
||
| 362 | } |
||
| 363 | |||
| 364 | $type->addAttribute($attribute); |
||
| 365 | break; |
||
| 366 | case 'attributeGroup': |
||
| 367 | $attribute = $this->findSomething('findAttributeGroup', $schema, $node, $childNode->getAttribute("ref")); |
||
| 368 | $type->addAttribute($attribute); |
||
| 369 | break; |
||
| 370 | } |
||
| 371 | } |
||
| 372 | |||
| 373 | if ($callback) { |
||
| 374 | call_user_func($callback, $type); |
||
| 375 | } |
||
| 376 | }; |
||
| 377 | } |
||
| 378 | |||
| 379 | private function loadSimpleType(Schema $schema, DOMElement $node, $callback = null) |
||
| 380 | { |
||
| 381 | $type = new SimpleType($schema, $node->getAttribute("name")); |
||
| 382 | $type->setDoc($this->getDocumentation($node)); |
||
| 383 | if ($node->getAttribute("name")) { |
||
| 384 | $schema->addType($type); |
||
| 385 | } |
||
| 386 | |||
| 387 | return function () use($type, $node, $callback) |
||
| 388 | { |
||
| 389 | $this->fillTypeNode($type, $node); |
||
| 390 | |||
| 391 | foreach ($node->childNodes as $childNode) { |
||
| 392 | switch ($childNode->localName) { |
||
| 393 | case 'union': |
||
| 394 | $this->loadUnion($type, $childNode); |
||
| 395 | break; |
||
| 396 | case 'list': |
||
| 397 | $this->loadList($type, $childNode); |
||
| 398 | break; |
||
| 399 | } |
||
| 400 | } |
||
| 401 | |||
| 402 | if ($callback) { |
||
| 403 | call_user_func($callback, $type); |
||
| 404 | } |
||
| 405 | }; |
||
| 406 | } |
||
| 407 | |||
| 408 | private function loadList(SimpleType $type, DOMElement $node) |
||
| 409 | { |
||
| 410 | if ($node->hasAttribute("itemType")) { |
||
| 411 | $type->setList($this->findSomething('findType', $type->getSchema(), $node, $node->getAttribute("itemType"))); |
||
| 412 | }else{ |
||
| 413 | $addCallback = function ($list) use($type) |
||
| 414 | { |
||
| 415 | $type->setList($list); |
||
| 416 | }; |
||
| 417 | |||
| 418 | foreach ($node->childNodes as $childNode) { |
||
| 419 | switch ($childNode->localName) { |
||
| 420 | case 'simpleType': |
||
| 421 | call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback)); |
||
| 422 | break; |
||
| 423 | } |
||
| 424 | } |
||
| 425 | } |
||
| 426 | } |
||
| 427 | |||
| 428 | private function loadUnion(SimpleType $type, DOMElement $node) |
||
| 429 | { |
||
| 430 | if ($node->hasAttribute("memberTypes")) { |
||
| 431 | $types = preg_split('/\s+/', $node->getAttribute("memberTypes")); |
||
| 432 | foreach ($types as $typeName) { |
||
| 433 | $type->addUnion($this->findSomething('findType', $type->getSchema(), $node, $typeName)); |
||
| 434 | } |
||
| 435 | } |
||
| 436 | $addCallback = function ($unType) use($type) |
||
| 437 | { |
||
| 438 | $type->addUnion($unType); |
||
| 439 | }; |
||
| 440 | |||
| 441 | foreach ($node->childNodes as $childNode) { |
||
| 442 | switch ($childNode->localName) { |
||
| 443 | case 'simpleType': |
||
| 444 | call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback)); |
||
| 445 | break; |
||
| 446 | } |
||
| 447 | } |
||
| 448 | } |
||
| 449 | |||
| 450 | private function fillTypeNode(Type $type, DOMElement $node, $checkAbstract = true) |
||
| 451 | { |
||
| 452 | |||
| 453 | if($checkAbstract){ |
||
| 454 | $type->setAbstract($node->getAttribute("abstract")==="true" || $node->getAttribute("abstract")==="1"); |
||
| 455 | } |
||
| 456 | |||
| 457 | foreach ($node->childNodes as $childNode) { |
||
| 458 | switch ($childNode->localName) { |
||
| 459 | case 'restriction': |
||
| 460 | $this->loadRestriction($type, $childNode); |
||
| 461 | break; |
||
| 462 | case 'extension': |
||
| 463 | $this->loadExtension($type, $childNode); |
||
| 464 | break; |
||
| 465 | case 'simpleContent': |
||
| 466 | case 'complexContent': |
||
| 467 | $this->fillTypeNode($type, $childNode, false); |
||
| 468 | break; |
||
| 469 | } |
||
| 470 | } |
||
| 471 | } |
||
| 472 | |||
| 473 | private function loadExtension(BaseComplexType $type, DOMElement $node) |
||
| 474 | { |
||
| 475 | $extension = new Extension(); |
||
| 476 | $type->setExtension($extension); |
||
| 477 | |||
| 478 | if ($node->hasAttribute("base")) { |
||
| 479 | $parent = $this->findSomething('findType', $type->getSchema(), $node, $node->getAttribute("base")); |
||
| 480 | $extension->setBase($parent); |
||
| 481 | } |
||
| 482 | |||
| 483 | foreach ($node->childNodes as $childNode) { |
||
| 484 | switch ($childNode->localName) { |
||
| 485 | case 'sequence': |
||
| 486 | case 'choice': |
||
| 487 | case 'all': |
||
| 488 | $this->loadSequence($type, $childNode); |
||
|
0 ignored issues
–
show
|
|||
| 489 | break; |
||
| 490 | case 'attribute': |
||
| 491 | if ($childNode->hasAttribute("ref")) { |
||
| 492 | $attribute = $this->findSomething('findAttribute', $type->getSchema(), $node, $childNode->getAttribute("ref")); |
||
| 493 | } else { |
||
| 494 | $attribute = $this->loadAttribute($type->getSchema(), $childNode); |
||
| 495 | } |
||
| 496 | $type->addAttribute($attribute); |
||
| 497 | break; |
||
| 498 | case 'attributeGroup': |
||
| 499 | $attribute = $this->findSomething('findAttributeGroup', $type->getSchema(), $node, $childNode->getAttribute("ref")); |
||
| 500 | $type->addAttribute($attribute); |
||
| 501 | break; |
||
| 502 | } |
||
| 503 | } |
||
| 504 | } |
||
| 505 | |||
| 506 | private function loadRestriction(Type $type, DOMElement $node) |
||
| 507 | { |
||
| 508 | $restriction = new Restriction(); |
||
| 509 | $type->setRestriction($restriction); |
||
| 510 | if ($node->hasAttribute("base")) { |
||
| 511 | $restrictedType = $this->findSomething('findType', $type->getSchema(), $node, $node->getAttribute("base")); |
||
| 512 | $restriction->setBase($restrictedType); |
||
| 513 | } else { |
||
| 514 | $addCallback = function ($restType) use($restriction) |
||
| 515 | { |
||
| 516 | $restriction->setBase($restType); |
||
| 517 | }; |
||
| 518 | |||
| 519 | foreach ($node->childNodes as $childNode) { |
||
| 520 | switch ($childNode->localName) { |
||
| 521 | case 'simpleType': |
||
| 522 | call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback)); |
||
| 523 | break; |
||
| 524 | } |
||
| 525 | } |
||
| 526 | } |
||
| 527 | foreach ($node->childNodes as $childNode) { |
||
| 528 | if (in_array($childNode->localName, |
||
| 529 | [ |
||
| 530 | 'enumeration', |
||
| 531 | 'pattern', |
||
| 532 | 'length', |
||
| 533 | 'minLength', |
||
| 534 | 'maxLength', |
||
| 535 | 'minInclusive', |
||
| 536 | 'maxInclusive', |
||
| 537 | 'minExclusive', |
||
| 538 | 'maxExclusive' |
||
| 539 | ], true)) { |
||
| 540 | $restriction->addCheck($childNode->localName, |
||
| 541 | [ |
||
| 542 | 'value' => $childNode->getAttribute("value"), |
||
| 543 | 'doc' => $this->getDocumentation($childNode) |
||
| 544 | ]); |
||
| 545 | } |
||
| 546 | } |
||
| 547 | } |
||
| 548 | |||
| 549 | private static function splitParts(DOMElement $node, $typeName) |
||
| 550 | { |
||
| 551 | $namespace = null; |
||
| 552 | $prefix = null; |
||
| 553 | $name = $typeName; |
||
| 554 | if (strpos($typeName, ':') !== false) { |
||
| 555 | list ($prefix, $name) = explode(':', $typeName); |
||
| 556 | } |
||
| 557 | |||
| 558 | $namespace = $node->lookupNamespaceURI($prefix ?: null); |
||
| 559 | return array( |
||
| 560 | $name, |
||
| 561 | $namespace, |
||
| 562 | $prefix |
||
| 563 | ); |
||
| 564 | } |
||
| 565 | |||
| 566 | /** |
||
| 567 | * |
||
| 568 | * @param string $finder |
||
| 569 | * @param Schema $schema |
||
| 570 | * @param DOMElement $node |
||
| 571 | * @param string $typeName |
||
| 572 | * @throws TypeException |
||
| 573 | * @return ElementItem|Group|AttributeItem|AttribiuteGroup|Type |
||
| 574 | */ |
||
| 575 | private function findSomething($finder, Schema $schema, DOMElement $node, $typeName) |
||
| 576 | { |
||
| 577 | list ($name, $namespace) = self::splitParts($node, $typeName); |
||
| 578 | |||
| 579 | $namespace = $namespace ?: $schema->getTargetNamespace(); |
||
| 580 | |||
| 581 | try { |
||
| 582 | return $schema->$finder($name, $namespace); |
||
| 583 | } catch (TypeNotFoundException $e) { |
||
| 584 | throw new TypeException(sprintf("Can't find %s named {%s}#%s, at line %d in %s ", strtolower(substr($finder, 4)), $namespace, $name, $node->getLineNo(), $node->ownerDocument->documentURI), 0, $e); |
||
| 585 | } |
||
| 586 | } |
||
| 587 | |||
| 588 | private function loadElementDef(Schema $schema, DOMElement $node) |
||
| 589 | { |
||
| 590 | $element = new ElementDef($schema, $node->getAttribute("name")); |
||
| 591 | $schema->addElement($element); |
||
| 592 | |||
| 593 | return function () use ($element, $node) { |
||
| 594 | $this->fillItem($element, $node); |
||
| 595 | }; |
||
| 596 | } |
||
| 597 | |||
| 598 | private function fillItem(Item $element, DOMElement $node) |
||
| 599 | { |
||
| 600 | $localType = null; |
||
| 601 | foreach ($node->childNodes as $childNode) { |
||
| 602 | switch ($childNode->localName) { |
||
| 603 | case 'complexType': |
||
| 604 | case 'simpleType': |
||
| 605 | $localType = $childNode; |
||
| 606 | break 2; |
||
| 607 | } |
||
| 608 | } |
||
| 609 | |||
| 610 | if ($localType) { |
||
| 611 | $addCallback = function ($type) use($element) { |
||
| 612 | $element->setType($type); |
||
| 613 | }; |
||
| 614 | switch ($localType->localName) { |
||
| 615 | case 'complexType': |
||
| 616 | call_user_func($this->loadComplexType($element->getSchema(), $localType, $addCallback)); |
||
| 617 | break; |
||
| 618 | case 'simpleType': |
||
| 619 | call_user_func($this->loadSimpleType($element->getSchema(), $localType, $addCallback)); |
||
| 620 | break; |
||
| 621 | } |
||
| 622 | } else { |
||
| 623 | |||
| 624 | if ($node->getAttribute("type")) { |
||
| 625 | $type = $this->findSomething('findType', $element->getSchema(), $node, $node->getAttribute("type")); |
||
| 626 | } else { |
||
| 627 | $type = $this->findSomething('findType', $element->getSchema(), $node, ($node->lookupPrefix(self::XSD_NS).":anyType")); |
||
| 628 | } |
||
| 629 | |||
| 630 | $element->setType($type); |
||
| 631 | } |
||
| 632 | } |
||
| 633 | |||
| 634 | private function loadImport(Schema $schema, DOMElement $node) |
||
| 635 | { |
||
| 636 | $base = urldecode($node->ownerDocument->documentURI); |
||
| 637 | $file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute("schemaLocation")); |
||
| 638 | if ($node->hasAttribute("namespace") |
||
| 639 | && isset(self::$globalSchemaInfo[$node->getAttribute("namespace")]) |
||
| 640 | && isset($this->loadedFiles[self::$globalSchemaInfo[$node->getAttribute("namespace")]]) |
||
| 641 | ){ |
||
| 642 | |||
| 643 | $schema->addSchema($this->loadedFiles[self::$globalSchemaInfo[$node->getAttribute("namespace")]]); |
||
| 644 | |||
| 645 | return function () |
||
| 646 | { |
||
| 647 | }; |
||
| 648 | }elseif (isset($this->loadedFiles[$file])) { |
||
| 649 | $schema->addSchema($this->loadedFiles[$file]); |
||
| 650 | return function () { |
||
| 651 | }; |
||
| 652 | } |
||
| 653 | |||
| 654 | if (!$node->getAttribute("namespace")){ |
||
| 655 | $this->loadedFiles[$file] = $newSchema = $schema; |
||
| 656 | }else{ |
||
| 657 | $this->loadedFiles[$file] = $newSchema = new Schema(); |
||
| 658 | $newSchema->addSchema($this->getGlobalSchema()); |
||
| 659 | } |
||
| 660 | |||
| 661 | $xml = $this->getDOM(isset($this->knowLocationSchemas[$file])?$this->knowLocationSchemas[$file]:$file); |
||
| 662 | |||
| 663 | $callbacks = $this->schemaNode($newSchema, $xml->documentElement, $schema); |
||
| 664 | |||
| 665 | if ($node->getAttribute("namespace")){ |
||
| 666 | $schema->addSchema($newSchema); |
||
| 667 | } |
||
| 668 | |||
| 669 | |||
| 670 | return function () use($callbacks) |
||
| 671 | { |
||
| 672 | foreach ($callbacks as $callback) { |
||
| 673 | call_user_func($callback); |
||
| 674 | } |
||
| 675 | }; |
||
| 676 | } |
||
| 677 | |||
| 678 | private $globalSchema; |
||
| 679 | |||
| 680 | /** |
||
| 681 | * |
||
| 682 | * @return \Goetas\XML\XSDReader\Schema\Schema |
||
| 683 | */ |
||
| 684 | public function getGlobalSchema() |
||
| 685 | { |
||
| 686 | if (! $this->globalSchema) { |
||
| 687 | $callbacks = array(); |
||
| 688 | $globalSchemas = array(); |
||
| 689 | foreach (self::$globalSchemaInfo as $namespace => $uri) { |
||
| 690 | $this->loadedFiles[$uri] = $globalSchemas [$namespace] = $schema = new Schema(); |
||
| 691 | if($namespace === self::XSD_NS){ |
||
| 692 | $this->globalSchema = $schema; |
||
| 693 | } |
||
| 694 | $xml = $this->getDOM($this->knowLocationSchemas[$uri]); |
||
| 695 | $callbacks = array_merge($callbacks, $this->schemaNode($schema, $xml->documentElement)); |
||
| 696 | } |
||
| 697 | |||
| 698 | $globalSchemas[self::XSD_NS]->addType(new SimpleType($globalSchemas[self::XSD_NS], "anySimpleType")); |
||
| 699 | $globalSchemas[self::XSD_NS]->addType(new SimpleType($globalSchemas[self::XSD_NS], "anyType")); |
||
| 700 | |||
| 701 | $globalSchemas[self::XML_NS]->addSchema($globalSchemas[self::XSD_NS], self::XSD_NS); |
||
| 702 | $globalSchemas[self::XSD_NS]->addSchema($globalSchemas[self::XML_NS], self::XML_NS); |
||
| 703 | |||
| 704 | foreach ($callbacks as $callback) { |
||
| 705 | $callback(); |
||
| 706 | } |
||
| 707 | } |
||
| 708 | return $this->globalSchema; |
||
| 709 | } |
||
| 710 | |||
| 711 | /** |
||
| 712 | * @return \Goetas\XML\XSDReader\Schema\Schema |
||
| 713 | */ |
||
| 714 | public function readNode(\DOMNode $node, $file = 'schema.xsd') |
||
| 715 | { |
||
| 716 | $this->loadedFiles[$file] = $rootSchema = new Schema(); |
||
| 717 | |||
| 718 | $rootSchema->addSchema($this->getGlobalSchema()); |
||
| 719 | $callbacks = $this->schemaNode($rootSchema, $node); |
||
| 720 | |||
| 721 | foreach ($callbacks as $callback) { |
||
| 722 | call_user_func($callback); |
||
| 723 | } |
||
| 724 | |||
| 725 | return $rootSchema; |
||
| 726 | } |
||
| 727 | |||
| 728 | |||
| 729 | /** |
||
| 730 | * @return \Goetas\XML\XSDReader\Schema\Schema |
||
| 731 | */ |
||
| 732 | public function readString($content, $file = 'schema.xsd') |
||
| 733 | { |
||
| 734 | $xml = new DOMDocument('1.0', 'UTF-8'); |
||
| 735 | if (! $xml->loadXML($content)) { |
||
| 736 | throw new IOException("Can't load the schema"); |
||
| 737 | } |
||
| 738 | $xml->documentURI = $file; |
||
| 739 | |||
| 740 | return $this->readNode($xml->documentElement, $file); |
||
| 741 | } |
||
| 742 | /** |
||
| 743 | * @return \Goetas\XML\XSDReader\Schema\Schema |
||
| 744 | */ |
||
| 745 | public function readFile($file) |
||
| 746 | { |
||
| 747 | $xml = $this->getDOM($file); |
||
| 748 | return $this->readNode($xml->documentElement, $file); |
||
| 749 | } |
||
| 750 | |||
| 751 | /** |
||
| 752 | * @param string $file |
||
| 753 | * @throws IOException |
||
| 754 | * @return \DOMDocument |
||
| 755 | */ |
||
| 756 | private function getDOM($file) |
||
| 757 | { |
||
| 758 | $xml = new DOMDocument('1.0', 'UTF-8'); |
||
| 759 | if (! $xml->load($file)) { |
||
| 760 | throw new IOException("Can't load the file $file"); |
||
| 761 | } |
||
| 762 | return $xml; |
||
| 763 | } |
||
| 764 | } |
||
| 765 |
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: