1# 2# Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). 3# All rights reserved. 4# This file is distributed under the terms of the MIT License. 5# See the file 'LICENSE' in the root directory of the present 6# distribution, or http://opensource.org/licenses/MIT. 7# 8# @author Davide Brunato <brunato@sissa.it> 9# 10from collections.abc import MutableSequence 11from typing import cast, Any, Callable, Iterator, List, Optional, Tuple, Union 12 13from ..exceptions import XMLSchemaValueError 14from ..names import XSD_GROUP, XSD_ATTRIBUTE_GROUP, XSD_SEQUENCE, XSD_OVERRIDE, \ 15 XSD_ALL, XSD_CHOICE, XSD_ANY_ATTRIBUTE, XSD_ATTRIBUTE, XSD_COMPLEX_CONTENT, \ 16 XSD_RESTRICTION, XSD_COMPLEX_TYPE, XSD_EXTENSION, XSD_ANY_TYPE, XSD_ASSERT, \ 17 XSD_UNTYPED_ATOMIC, XSD_SIMPLE_CONTENT, XSD_OPEN_CONTENT, XSD_ANNOTATION 18from ..aliases import ElementType, NamespacesType, SchemaType, ComponentClassType, \ 19 DecodeType, IterDecodeType, IterEncodeType, BaseXsdType, AtomicValueType, \ 20 ExtraValidatorType 21from ..helpers import get_prefixed_qname, get_qname, local_name 22from .. import dataobjects 23 24from .exceptions import XMLSchemaDecodeError 25from .helpers import get_xsd_derivation_attribute 26from .xsdbase import XSD_TYPE_DERIVATIONS, XsdComponent, XsdType, ValidationMixin 27from .attributes import XsdAttributeGroup 28from .assertions import XsdAssert 29from .simple_types import FacetsValueType, XsdSimpleType, XsdUnion 30from .groups import XsdGroup 31from .wildcards import XsdOpenContent, XsdDefaultOpenContent 32 33XSD_MODEL_GROUP_TAGS = {XSD_GROUP, XSD_SEQUENCE, XSD_ALL, XSD_CHOICE} 34 35 36class XsdComplexType(XsdType, ValidationMixin[Union[ElementType, str, bytes], Any]): 37 """ 38 Class for XSD 1.0 *complexType* definitions. 39 40 :var attributes: the attribute group related with the complexType. 41 :var content: the content of the complexType can be a model group or a simple type. 42 :var mixed: if `True` the complex type has mixed content. 43 44 .. <complexType 45 abstract = boolean : false 46 block = (#all | List of (extension | restriction)) 47 final = (#all | List of (extension | restriction)) 48 id = ID 49 mixed = boolean : false 50 name = NCName 51 {any attributes with non-schema namespace . . .}> 52 Content: (annotation?, (simpleContent | complexContent | 53 ((group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?)))) 54 </complexType> 55 """ 56 attributes: XsdAttributeGroup 57 copy: Callable[['XsdComplexType'], 'XsdComplexType'] 58 content: Union[XsdGroup, XsdSimpleType] = None # type: ignore[assignment] 59 60 abstract: bool = False 61 mixed: bool = False 62 assertions: Union[Tuple[()], List[XsdAssert]] = () 63 open_content: Optional[XsdOpenContent] = None 64 _block: Optional[str] = None 65 66 _ADMITTED_TAGS = {XSD_COMPLEX_TYPE, XSD_RESTRICTION} 67 _CONTENT_TAIL_TAGS = {XSD_ATTRIBUTE, XSD_ATTRIBUTE_GROUP, XSD_ANY_ATTRIBUTE} 68 69 @staticmethod 70 def normalize(text: Union[str, bytes]) -> str: 71 return text.decode('utf-8') if isinstance(text, bytes) else text 72 73 def __init__(self, elem: ElementType, 74 schema: SchemaType, 75 parent: Optional[XsdComponent] = None, 76 name: Optional[str] = None, 77 **kwargs: Any) -> None: 78 79 if kwargs: 80 if 'content' in kwargs: 81 self.content = kwargs['content'] 82 if 'attributes' in kwargs: 83 self.attributes = kwargs['attributes'] 84 if 'mixed' in kwargs: 85 self.mixed = kwargs['mixed'] 86 if 'block' in kwargs: 87 self._block = kwargs['block'] 88 if 'final' in kwargs: 89 self._final = kwargs['final'] 90 super(XsdComplexType, self).__init__(elem, schema, parent, name) 91 assert self.content is not None 92 93 def __repr__(self) -> str: 94 if self.name is not None: 95 return '%s(name=%r)' % (self.__class__.__name__, self.prefixed_name) 96 elif not hasattr(self, 'content') or not hasattr(self, 'attributes'): 97 return '%s(id=%r)' % (self.__class__.__name__, id(self)) 98 else: 99 return '%s(content=%r, attributes=%r)' % ( 100 self.__class__.__name__, self.content_type_label, 101 [a if a.name is None else a.prefixed_name for a in self.attributes.values()] 102 ) 103 104 def _parse(self) -> None: 105 if self.elem.tag == XSD_RESTRICTION: 106 return # a local restriction is already parsed by the caller 107 108 if 'abstract' in self.elem.attrib: 109 if self.elem.attrib['abstract'].strip() in {'true', '1'}: 110 self.abstract = True 111 112 if 'block' in self.elem.attrib: 113 try: 114 self._block = get_xsd_derivation_attribute(self.elem, 'block', XSD_TYPE_DERIVATIONS) 115 except ValueError as err: 116 self.parse_error(err) 117 118 if 'final' in self.elem.attrib: 119 try: 120 self._final = get_xsd_derivation_attribute(self.elem, 'final', XSD_TYPE_DERIVATIONS) 121 except ValueError as err: 122 self.parse_error(err) 123 124 if 'mixed' in self.elem.attrib: 125 if self.elem.attrib['mixed'].strip() in {'true', '1'}: 126 self.mixed = True 127 128 try: 129 self.name = get_qname(self.target_namespace, self.elem.attrib['name']) 130 except KeyError: 131 self.name = None 132 if self.parent is None: 133 self.parse_error("missing attribute 'name' in a global complexType") 134 self.name = 'nameless_%s' % str(id(self)) 135 else: 136 if self.parent is not None: 137 self.parse_error("attribute 'name' not allowed for a local complexType") 138 self.name = None 139 140 content_elem = self._parse_child_component(self.elem, strict=False) 141 if content_elem is None or content_elem.tag in self._CONTENT_TAIL_TAGS: 142 self.content = self.schema.create_empty_content_group(self) 143 self._parse_content_tail(self.elem) 144 default_open_content = self.default_open_content 145 if default_open_content is not None and \ 146 (self.mixed or self.content or default_open_content.applies_to_empty): 147 self.open_content = default_open_content 148 149 elif content_elem.tag in {XSD_GROUP, XSD_SEQUENCE, XSD_ALL, XSD_CHOICE}: 150 self.content = self.schema.xsd_group_class(content_elem, self.schema, self) 151 default_open_content = self.default_open_content 152 if default_open_content is not None and \ 153 (self.mixed or self.content or default_open_content.applies_to_empty): 154 self.open_content = default_open_content 155 self._parse_content_tail(self.elem) 156 157 elif content_elem.tag == XSD_SIMPLE_CONTENT: 158 if 'mixed' in content_elem.attrib: 159 self.parse_error("'mixed' attribute not allowed with simpleContent", content_elem) 160 161 derivation_elem = self._parse_derivation_elem(content_elem) 162 if derivation_elem is None: 163 return 164 165 self.base_type = base_type = self._parse_base_type(derivation_elem) 166 if derivation_elem.tag == XSD_RESTRICTION: 167 self._parse_simple_content_restriction(derivation_elem, base_type) 168 else: 169 self._parse_simple_content_extension(derivation_elem, base_type) 170 171 if content_elem is not self.elem[-1]: 172 k = 2 if content_elem is not self.elem[0] else 1 173 self.parse_error( 174 "unexpected tag %r after simpleContent declaration:" % self.elem[k].tag 175 ) 176 177 elif content_elem.tag == XSD_COMPLEX_CONTENT: 178 # 179 # complexType with complexContent restriction/extension 180 if 'mixed' in content_elem.attrib: 181 mixed = content_elem.attrib['mixed'] in ('true', '1') 182 if mixed is not self.mixed: 183 self.mixed = mixed 184 if 'mixed' in self.elem.attrib and self.xsd_version == '1.1': 185 self.parse_error("value of 'mixed' attribute in complexType " 186 "and complexContent must be same") 187 188 derivation_elem = self._parse_derivation_elem(content_elem) 189 if derivation_elem is None: 190 return 191 192 self.base_type = self._parse_base_type(derivation_elem, complex_content=True) 193 if self.base_type is self and self.redefine is not None: 194 self.base_type = self.redefine 195 self.open_content = None 196 197 if derivation_elem.tag == XSD_RESTRICTION: 198 self._parse_complex_content_restriction(derivation_elem, self.base_type) 199 else: 200 self._parse_complex_content_extension(derivation_elem, self.base_type) 201 202 if content_elem is not self.elem[-1]: 203 k = 2 if content_elem is not self.elem[0] else 1 204 self.parse_error( 205 "unexpected tag %r after complexContent declaration:" % self.elem[k].tag 206 ) 207 208 elif content_elem.tag == XSD_OPEN_CONTENT and self.xsd_version > '1.0': 209 self.open_content = XsdOpenContent(content_elem, self.schema, self) 210 211 if content_elem is self.elem[-1]: 212 self.content = self.schema.create_empty_content_group(self) 213 else: 214 for index, child in enumerate(self.elem): 215 if content_elem is not child: 216 continue 217 elif self.elem[index + 1].tag in {XSD_GROUP, XSD_SEQUENCE, XSD_ALL, XSD_CHOICE}: 218 self.content = self.schema.xsd_group_class( 219 self.elem[index + 1], self.schema, self 220 ) 221 else: 222 self.content = self.schema.create_empty_content_group(self) 223 break 224 self._parse_content_tail(self.elem) 225 226 else: 227 if self.schema.validation == 'skip': 228 # Also generated by meta-schema validation for 'lax' and 'strict' modes 229 self.parse_error( 230 "unexpected tag %r for complexType content:" % content_elem.tag 231 ) 232 self.content = self.schema.create_any_content_group(self) 233 self.attributes = self.schema.create_any_attribute_group(self) 234 235 if self.redefine is None: 236 if self.base_type is not None and self.base_type.name == self.name: 237 self.parse_error("wrong definition with self-reference") 238 elif self.base_type is None or self.base_type.name != self.name: 239 self.parse_error("wrong redefinition without self-reference") 240 241 def _parse_content_tail(self, elem: ElementType, **kwargs: Any) -> None: 242 self.attributes = self.schema.xsd_attribute_group_class( 243 elem, self.schema, self, **kwargs 244 ) 245 246 def _parse_derivation_elem(self, elem: ElementType) -> Optional[ElementType]: 247 derivation_elem = self._parse_child_component(elem) 248 if derivation_elem is None or derivation_elem.tag not in {XSD_RESTRICTION, XSD_EXTENSION}: 249 self.parse_error("restriction or extension tag expected", derivation_elem) 250 self.content = self.schema.create_any_content_group(self) 251 self.attributes = self.schema.create_any_attribute_group(self) 252 return None 253 254 if self.derivation is not None and self.redefine is None: 255 raise XMLSchemaValueError("{!r} is expected to have a redefined/" 256 "overridden component".format(self)) 257 self.derivation = local_name(derivation_elem.tag) 258 259 if self.base_type is not None and self.derivation in self.base_type.final: 260 self.parse_error(f"{self.derivation!r} derivation not allowed for {self!r}") 261 return derivation_elem 262 263 def _parse_base_type(self, elem: ElementType, complex_content: bool = False) \ 264 -> Union[XsdSimpleType, 'XsdComplexType']: 265 try: 266 base_qname = self.schema.resolve_qname(elem.attrib['base']) 267 except (KeyError, ValueError, RuntimeError) as err: 268 if 'base' not in elem.attrib: 269 self.parse_error("'base' attribute required", elem) 270 else: 271 self.parse_error(err, elem) 272 return self.any_type 273 274 try: 275 base_type = self.maps.lookup_type(base_qname) 276 except KeyError: 277 self.parse_error("missing base type %r" % base_qname, elem) 278 if complex_content: 279 return self.any_type 280 else: 281 return self.any_simple_type 282 else: 283 if isinstance(base_type, tuple): 284 self.parse_error("circularity definition found between %r " 285 "and %r" % (self, base_qname), elem) 286 return self.any_type 287 elif complex_content and base_type.is_simple(): 288 self.parse_error("a complexType ancestor required: %r" % base_type, elem) 289 return self.any_type 290 291 if base_type.final and elem.tag.rsplit('}', 1)[-1] in base_type.final: 292 msg = "derivation by %r blocked by attribute 'final' in base type" 293 self.parse_error(msg % elem.tag.rsplit('}', 1)[-1]) 294 295 return base_type 296 297 def _parse_simple_content_restriction(self, elem: ElementType, base_type: Any) -> None: 298 # simpleContent restriction: the base type must be a complexType with a simple 299 # content or a complex content with a mixed and emptiable content. 300 if base_type.is_simple(): 301 self.parse_error("a complexType ancestor required: %r" % base_type, elem) 302 self.content = self.schema.create_any_content_group(self) 303 self._parse_content_tail(elem) 304 else: 305 if base_type.is_empty(): 306 self.content = self.schema.xsd_atomic_restriction_class(elem, self.schema, self) 307 if not self.is_empty(): 308 self.parse_error("a not empty simpleContent cannot restrict " 309 "an empty content type", elem) 310 self.content = self.schema.create_any_content_group(self) 311 312 elif base_type.has_simple_content(): 313 self.content = self.schema.xsd_atomic_restriction_class(elem, self.schema, self) 314 if not self.content.is_derived(base_type.content, 'restriction'): 315 self.parse_error("content type is not a restriction of base content", elem) 316 317 elif base_type.mixed and base_type.is_emptiable(): 318 self.content = self.schema.xsd_atomic_restriction_class(elem, self.schema, self) 319 else: 320 self.parse_error("with simpleContent cannot restrict an " 321 "element-only content type", elem) 322 self.content = self.schema.create_any_content_group(self) 323 324 self._parse_content_tail(elem, derivation='restriction', 325 base_attributes=base_type.attributes) 326 327 def _parse_simple_content_extension(self, elem: ElementType, base_type: Any) -> None: 328 # simpleContent extension: the base type must be a simpleType or a complexType 329 # with simple content. 330 child = self._parse_child_component(elem, strict=False) 331 if child is not None and child.tag not in self._CONTENT_TAIL_TAGS: 332 self.parse_error('unexpected tag %r' % child.tag, child) 333 334 if base_type.is_simple(): 335 self.content = base_type 336 self._parse_content_tail(elem) 337 else: 338 if base_type.has_simple_content(): 339 self.content = base_type.content 340 else: 341 self.parse_error("base type %r has not simple content." % base_type, elem) 342 self.content = self.schema.create_any_content_group(self) 343 344 self._parse_content_tail(elem, derivation='extension', 345 base_attributes=base_type.attributes) 346 347 def _parse_complex_content_restriction(self, elem: ElementType, base_type: Any) -> None: 348 if 'restriction' in base_type.final: 349 self.parse_error("the base type is not derivable by restriction") 350 if base_type.is_simple() or base_type.has_simple_content(): 351 self.parse_error("base %r is simple or has a simple content." % base_type, elem) 352 base_type = self.any_type 353 354 # complexContent restriction: the base type must be a complexType with a complex content. 355 for child in elem: 356 if child.tag == XSD_OPEN_CONTENT and self.xsd_version > '1.0': 357 self.open_content = XsdOpenContent(child, self.schema, self) 358 continue 359 elif child.tag in XSD_MODEL_GROUP_TAGS: 360 content = self.schema.xsd_group_class(child, self.schema, self) 361 if not base_type.content.admits_restriction(content.model): 362 self.parse_error( 363 "restriction of an xs:{} with more than one particle with xs:{} is " 364 "forbidden".format(base_type.content.model, content.model) 365 ) 366 break 367 else: 368 content = self.schema.create_empty_content_group( 369 self, base_type.content.model 370 ) 371 372 content.restriction = base_type.content 373 374 if base_type.is_element_only() and content.mixed: 375 self.parse_error( 376 "derived a mixed content from a base type that has element-only content.", elem 377 ) 378 elif base_type.is_empty() and not content.is_empty(): 379 self.parse_error( 380 "derived an empty content from base type that has not empty content.", elem 381 ) 382 383 if self.open_content is None: 384 default_open_content = self.default_open_content 385 if default_open_content is not None and \ 386 (self.mixed or content or default_open_content.applies_to_empty): 387 self.open_content = default_open_content 388 389 if self.open_content and content and \ 390 not self.open_content.is_restriction(base_type.open_content): 391 msg = "{!r} is not a restriction of the base type {!r}" 392 self.parse_error(msg.format(self.open_content, base_type.open_content)) 393 394 self.content = content 395 self._parse_content_tail(elem, derivation='restriction', 396 base_attributes=base_type.attributes) 397 398 def _parse_complex_content_extension(self, elem: ElementType, base_type: Any) -> None: 399 if 'extension' in base_type.final: 400 self.parse_error("the base type is not derivable by extension") 401 402 group_elem: Optional[ElementType] 403 for group_elem in elem: 404 if group_elem.tag != XSD_ANNOTATION and not callable(group_elem.tag): 405 break 406 else: 407 group_elem = None 408 409 if base_type.is_empty(): 410 if not base_type.mixed: 411 # Empty element-only model extension: don't create a nested group. 412 if group_elem is not None and group_elem.tag in XSD_MODEL_GROUP_TAGS: 413 self.content = self.schema.xsd_group_class( 414 group_elem, self.schema, self 415 ) 416 elif base_type.is_simple() or base_type.has_simple_content(): 417 self.content = self.schema.create_empty_content_group(self) 418 else: 419 self.content = self.schema.create_empty_content_group( 420 parent=self, elem=base_type.content.elem 421 ) 422 elif base_type.mixed: 423 # Empty mixed model extension 424 self.content = self.schema.create_empty_content_group(self) 425 self.content.append(self.schema.create_empty_content_group(self.content)) 426 427 if group_elem is not None and group_elem.tag in XSD_MODEL_GROUP_TAGS: 428 group = self.schema.xsd_group_class( 429 group_elem, self.schema, self.content 430 ) 431 if not self.mixed: 432 self.parse_error("base has a different content type (mixed=%r) and the " 433 "extension group is not empty." % base_type.mixed, elem) 434 else: 435 group = self.schema.create_empty_content_group(self) 436 437 self.content.append(group) 438 self.content.elem.append(base_type.content.elem) 439 self.content.elem.append(group.elem) 440 441 elif group_elem is not None and group_elem.tag in XSD_MODEL_GROUP_TAGS: 442 # Derivation from a simple content is forbidden if base type is not empty. 443 if base_type.is_simple() or base_type.has_simple_content(): 444 self.parse_error("base %r is simple or has a simple content." % base_type, elem) 445 base_type = self.any_type 446 447 group = self.schema.xsd_group_class(group_elem, self.schema, self) 448 449 if group.model == 'all': 450 self.parse_error("cannot extend a complex content with xs:all") 451 if base_type.content.model == 'all' and group.model == 'sequence': 452 self.parse_error("xs:sequence cannot extend xs:all") 453 454 content = self.schema.create_empty_content_group(self) 455 content.append(base_type.content) 456 content.append(group) 457 content.elem.append(base_type.content.elem) 458 content.elem.append(group.elem) 459 460 if base_type.content.model == 'all' and base_type.content and group: 461 self.parse_error( 462 "XSD 1.0 does not allow extension of a not empty 'all' model group" 463 ) 464 if base_type.mixed != self.mixed and base_type.name != XSD_ANY_TYPE: 465 self.parse_error("base has a different content type (mixed=%r) and the " 466 "extension group is not empty" % base_type.mixed, elem) 467 self.content = content 468 469 elif base_type.is_simple(): 470 self.content = base_type 471 elif base_type.has_simple_content(): 472 self.content = base_type.content 473 else: 474 self.content = self.schema.create_empty_content_group(self) 475 self.content.append(base_type.content) 476 self.content.elem.append(base_type.content.elem) 477 if base_type.mixed != self.mixed and base_type.name != XSD_ANY_TYPE and self.mixed: 478 self.parse_error( 479 "extended type has a mixed content but the base is element-only", elem 480 ) 481 482 self._parse_content_tail(elem, derivation='extension', base_attributes=base_type.attributes) 483 484 @property 485 def default_open_content(self) -> Optional[XsdDefaultOpenContent]: 486 return None 487 488 @property 489 def block(self) -> str: 490 return self.schema.block_default if self._block is None else self._block 491 492 @property 493 def built(self) -> bool: 494 return self.content.parent is not None or self.content.built 495 496 @property 497 def validation_attempted(self) -> str: 498 return 'full' if self.built else self.content.validation_attempted 499 500 @property 501 def simple_type(self) -> Optional[XsdSimpleType]: 502 return self.content if isinstance(self.content, XsdSimpleType) else None 503 504 @property 505 def model_group(self) -> Optional[XsdGroup]: 506 return self.content if isinstance(self.content, XsdGroup) else None 507 508 @property 509 def content_type(self) -> Union[XsdGroup, XsdSimpleType]: 510 """Property that returns the attribute *content*, for backward compatibility.""" 511 import warnings 512 warnings.warn("'content_type' attribute has been replaced by 'content' " 513 "and will be removed in version 2.0", DeprecationWarning, stacklevel=2) 514 return self.content 515 516 @property 517 def content_type_label(self) -> str: 518 if self.is_empty(): 519 return 'empty' 520 elif isinstance(self.content, XsdSimpleType): 521 return 'simple' 522 elif self.mixed: 523 return 'mixed' 524 else: 525 return 'element-only' 526 527 @property 528 def sequence_type(self) -> str: 529 if self.is_empty(): 530 return 'empty-sequence()' 531 elif not self.has_simple_content(): 532 st = get_prefixed_qname(XSD_UNTYPED_ATOMIC, self.namespaces) 533 else: 534 try: 535 st = self.content.primitive_type.prefixed_name # type: ignore[union-attr] 536 except AttributeError: 537 st = get_prefixed_qname(XSD_UNTYPED_ATOMIC, self.namespaces) 538 else: 539 if st is None: 540 st = 'item()' 541 542 return f"{st}{'*' if self.is_emptiable() else '+'}" 543 544 @staticmethod 545 def is_simple() -> bool: 546 return False 547 548 @staticmethod 549 def is_complex() -> bool: 550 return True 551 552 def is_empty(self) -> bool: 553 if self.open_content and self.open_content.mode != 'none': 554 return False 555 return self.content.is_empty() 556 557 def is_emptiable(self) -> bool: 558 return self.content.is_emptiable() 559 560 def has_simple_content(self) -> bool: 561 if not isinstance(self.content, XsdGroup): 562 return not self.content.is_empty() 563 elif self.content or self.content.mixed or self.base_type is None: 564 return False 565 else: 566 return self.base_type.is_simple() or self.base_type.has_simple_content() 567 568 def has_complex_content(self) -> bool: 569 if not isinstance(self.content, XsdGroup): 570 return False 571 elif self.open_content and self.open_content.mode != 'none': 572 return True 573 return not self.content.is_empty() 574 575 def has_mixed_content(self) -> bool: 576 if not isinstance(self.content, XsdGroup): 577 return False 578 elif self.content.is_empty(): 579 return False 580 else: 581 return self.content.mixed 582 583 def is_element_only(self) -> bool: 584 if not isinstance(self.content, XsdGroup): 585 return False 586 elif self.content.is_empty(): 587 return False 588 else: 589 return not self.content.mixed 590 591 def is_list(self) -> bool: 592 return isinstance(self.content, XsdSimpleType) and self.content.is_list() 593 594 def validate(self, obj: Union[ElementType, str, bytes], 595 use_defaults: bool = True, 596 namespaces: Optional[NamespacesType] = None, 597 max_depth: Optional[int] = None, 598 extra_validator: Optional[ExtraValidatorType] = None) -> None: 599 kwargs: Any = { 600 'use_defaults': use_defaults, 601 'namespaces': namespaces, 602 'max_depth': max_depth, 603 'extra_validator': extra_validator 604 } 605 if not isinstance(obj, (str, bytes)): 606 super(XsdComplexType, self).validate(obj, **kwargs) 607 elif isinstance(self.content, XsdSimpleType): 608 self.content.validate(obj, **kwargs) 609 elif not self.mixed and self.base_type is not None: 610 self.base_type.validate(obj, **kwargs) 611 612 def is_valid(self, obj: Union[ElementType, str, bytes], 613 use_defaults: bool = True, 614 namespaces: Optional[NamespacesType] = None, 615 max_depth: Optional[int] = None, 616 extra_validator: Optional[ExtraValidatorType] = None) -> bool: 617 kwargs: Any = { 618 'use_defaults': use_defaults, 619 'namespaces': namespaces, 620 'max_depth': max_depth, 621 'extra_validator': extra_validator 622 } 623 if not isinstance(obj, (str, bytes)): 624 return super(XsdComplexType, self).is_valid(obj, **kwargs) 625 elif isinstance(self.content, XsdSimpleType): 626 return self.content.is_valid(obj, **kwargs) 627 else: 628 return self.mixed or self.base_type is not None and \ 629 self.base_type.is_valid(obj, **kwargs) 630 631 def is_derived(self, other: Union[BaseXsdType, Tuple[ElementType, SchemaType]], 632 derivation: Optional[str] = None) -> bool: 633 if derivation and derivation == self.derivation: 634 derivation = None # derivation mode checked 635 636 if self is other: 637 return derivation is None 638 elif isinstance(other, tuple): 639 other[1].parse_error(f"global type {other[0].tag!r} is not built") 640 return False 641 elif other.name == XSD_ANY_TYPE: 642 return True 643 elif self.base_type is other: 644 return derivation is None # or self.base_type.derivation == derivation 645 elif isinstance(other, XsdUnion): 646 return any(self.is_derived(m, derivation) for m in other.member_types) 647 elif self.base_type is None: 648 if not self.has_simple_content(): 649 return False 650 return isinstance(self.content, XsdSimpleType) and \ 651 self.content.is_derived(other, derivation) 652 elif self.has_simple_content(): 653 return isinstance(self.content, XsdSimpleType) and \ 654 self.content.is_derived(other, derivation) or \ 655 self.base_type.is_derived(other, derivation) 656 else: 657 return self.base_type.is_derived(other, derivation) 658 659 def iter_components(self, xsd_classes: ComponentClassType = None) \ 660 -> Iterator[XsdComponent]: 661 if xsd_classes is None or isinstance(self, xsd_classes): 662 yield self 663 if self.attributes and self.attributes.parent is not None: 664 yield from self.attributes.iter_components(xsd_classes) 665 if self.content.parent is not None: 666 yield from self.content.iter_components(xsd_classes) 667 if self.base_type is not None and self.base_type.parent is not None: 668 yield from self.base_type.iter_components(xsd_classes) 669 670 for obj in filter(lambda x: x.base_type is self, self.assertions): 671 if xsd_classes is None or isinstance(obj, xsd_classes): 672 yield obj 673 674 def get_facet(self, tag: str) -> Optional[FacetsValueType]: 675 if isinstance(self.content, XsdSimpleType): 676 return self.content.get_facet(tag) 677 return None 678 679 def admit_simple_restriction(self) -> bool: 680 if 'restriction' in self.final: 681 return False 682 else: 683 return self.has_simple_content() or self.mixed and self.is_emptiable() 684 685 def has_restriction(self) -> bool: 686 return self.derivation == 'restriction' 687 688 def has_extension(self) -> bool: 689 return self.derivation == 'extension' 690 691 def text_decode(self, text: str) -> Optional[AtomicValueType]: 692 if isinstance(self.content, XsdSimpleType): 693 return cast(Optional[AtomicValueType], self.content.decode(text, 'skip')) 694 else: 695 return text 696 697 def decode(self, obj: Union[ElementType, str, bytes], *args: Any, **kwargs: Any) \ 698 -> DecodeType[Any]: 699 if not isinstance(obj, (str, bytes)): 700 return super(XsdComplexType, self).decode(obj, *args, **kwargs) 701 elif isinstance(self.content, XsdSimpleType): 702 return self.content.decode(obj, *args, **kwargs) 703 else: 704 raise XMLSchemaDecodeError( 705 self, obj, str, "cannot decode %r data with %r" % (obj, self) 706 ) 707 708 def iter_decode(self, obj: Union[ElementType, str, bytes], 709 validation: str = 'lax', **kwargs: Any) -> IterDecodeType[Any]: 710 """ 711 Decodes an Element instance using a dummy XSD element. Typically used 712 for decoding with xs:anyType when an XSD element is not available. 713 Also decodes strings if the type has a simple content. 714 715 :param obj: the XML data that has to be decoded. 716 :param validation: the validation mode. Can be 'lax', 'strict' or 'skip'. 717 :param kwargs: keyword arguments for the decoding process. 718 :return: yields a decoded object, eventually preceded by a sequence of \ 719 validation or decoding errors. 720 """ 721 if not isinstance(obj, (str, bytes)): 722 xsd_element = self.schema.create_element(obj.tag, parent=self, form='unqualified') 723 xsd_element.type = self 724 yield from xsd_element.iter_decode(obj, validation, **kwargs) 725 elif isinstance(self.content, XsdSimpleType): 726 yield from self.content.iter_decode(obj, validation, **kwargs) 727 else: 728 raise XMLSchemaDecodeError( 729 self, obj, str, "cannot decode %r data with %r" % (obj, self) 730 ) 731 732 def iter_encode(self, obj: Any, validation: str = 'lax', **kwargs: Any) \ 733 -> IterEncodeType[ElementType]: 734 """ 735 Encode XML data. A dummy element is created for the type and it's used for 736 encode data. Typically used for encoding with xs:anyType when an XSD element 737 is not available. 738 739 :param obj: decoded XML data. 740 :param validation: the validation mode: can be 'lax', 'strict' or 'skip'. 741 :param kwargs: keyword arguments for the encoding process. 742 :return: yields an Element, eventually preceded by a sequence of \ 743 validation or encoding errors. 744 """ 745 try: 746 name, value = obj 747 except ValueError: 748 name = obj.name 749 value = obj 750 751 xsd_element = self.schema.create_element(name, parent=self, form='unqualified') 752 xsd_element.type = self 753 754 if isinstance(value, MutableSequence) and not isinstance(value, dataobjects.DataElement): 755 try: 756 results = [x for item in value for x in xsd_element.iter_encode( 757 item, validation, **kwargs 758 )] 759 except XMLSchemaValueError: 760 pass 761 else: 762 yield from results 763 return 764 765 yield from xsd_element.iter_encode(value, validation, **kwargs) 766 767 768class Xsd11ComplexType(XsdComplexType): 769 """ 770 Class for XSD 1.1 *complexType* definitions. 771 772 .. <complexType 773 abstract = boolean : false 774 block = (#all | List of (extension | restriction)) 775 final = (#all | List of (extension | restriction)) 776 id = ID 777 mixed = boolean 778 name = NCName 779 defaultAttributesApply = boolean : true 780 {any attributes with non-schema namespace . . .}> 781 Content: (annotation?, (simpleContent | complexContent | (openContent?, 782 (group | all | choice | sequence)?, 783 ((attribute | attributeGroup)*, anyAttribute?), assert*))) 784 </complexType> 785 """ 786 default_attributes_apply = True 787 788 _CONTENT_TAIL_TAGS = {XSD_ATTRIBUTE_GROUP, XSD_ATTRIBUTE, XSD_ANY_ATTRIBUTE, XSD_ASSERT} 789 790 @property 791 def default_attributes(self) -> Optional[XsdAttributeGroup]: 792 if self.redefine is not None: 793 default_attributes = self.schema.default_attributes 794 else: 795 for child in self.schema.root: 796 if child.tag == XSD_OVERRIDE and self.elem in child: 797 schema = self.schema.includes[child.attrib['schemaLocation']] 798 if schema.override is self.schema: 799 default_attributes = schema.default_attributes 800 break 801 else: 802 default_attributes = self.schema.default_attributes 803 804 if isinstance(default_attributes, str): 805 return None 806 return default_attributes 807 808 @property 809 def default_open_content(self) -> Optional[XsdDefaultOpenContent]: 810 if self.parent is not None: 811 return self.schema.default_open_content 812 813 for child in self.schema.root: 814 if child.tag == XSD_OVERRIDE and self.elem in child: 815 schema = self.schema.includes[child.attrib['schemaLocation']] 816 if schema.override is self.schema: 817 return schema.default_open_content 818 else: 819 return self.schema.default_open_content 820 821 def _parse(self) -> None: 822 super(Xsd11ComplexType, self)._parse() 823 824 if self.base_type and self.base_type.base_type is self.any_simple_type and \ 825 self.base_type.derivation == 'extension' and not self.attributes: 826 # Derivation from xs:anySimpleType with missing variety. 827 # See: http://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition_details 828 msg = "the simple content of {!r} is not a valid simple type in XSD 1.1" 829 self.parse_error(msg.format(self.base_type)) 830 831 # Add open content to a complex content type 832 if isinstance(self.content, XsdGroup): 833 if self.open_content is None: 834 if self.content.interleave is not None or self.content.suffix is not None: 835 self.parse_error("openContent mismatch between type and model group") 836 elif self.open_content.mode == 'interleave': 837 self.content.interleave = self.content.suffix \ 838 = self.open_content.any_element 839 elif self.open_content.mode == 'suffix': 840 self.content.suffix = self.open_content.any_element 841 842 # Add inheritable attributes 843 if isinstance(self.base_type, XsdComplexType): 844 for name, attr in self.base_type.attributes.items(): 845 if attr.inheritable: 846 if name not in self.attributes: 847 self.attributes[name] = attr 848 elif not self.attributes[name].inheritable: 849 self.parse_error("attribute %r must be inheritable") 850 851 if 'defaultAttributesApply' not in self.elem.attrib: 852 self.default_attributes_apply = True 853 elif self.elem.attrib['defaultAttributesApply'].strip() in {'false', '0'}: 854 self.default_attributes_apply = False 855 else: 856 self.default_attributes_apply = True 857 858 # Add default attributes 859 if self.default_attributes_apply and \ 860 isinstance(self.default_attributes, XsdAttributeGroup): 861 if self.redefine is None: 862 for k in self.default_attributes: 863 if k in self.attributes: 864 self.parse_error(f"default attribute {k!r} is already " 865 f"declared in the complex type") 866 867 self.attributes.update((k, v) for k, v in self.default_attributes.items()) 868 869 def _parse_complex_content_extension(self, elem: ElementType, base_type: Any) -> None: 870 # Complex content extension with simple base is forbidden XSD 1.1. 871 # For the detailed rule refer to XSD 1.1 documentation: 872 # https://www.w3.org/TR/2012/REC-xmlschema11-1-20120405/#sec-cos-ct-extends 873 if base_type.is_simple() or base_type.has_simple_content(): 874 self.parse_error("base %r is simple or has a simple content." % base_type, elem) 875 base_type = self.any_type 876 877 if 'extension' in base_type.final: 878 self.parse_error("the base type is not derivable by extension") 879 880 # Parse openContent 881 group_elem: Any 882 for group_elem in elem: 883 if group_elem.tag == XSD_ANNOTATION or callable(group_elem.tag): 884 continue 885 elif group_elem.tag != XSD_OPEN_CONTENT: 886 break 887 self.open_content = XsdOpenContent(group_elem, self.schema, self) 888 try: 889 any_element = base_type.open_content.any_element 890 self.open_content.any_element.union(any_element) 891 except AttributeError: 892 pass 893 else: 894 group_elem = None 895 896 if not base_type.content: 897 if not base_type.mixed: 898 # Empty element-only model extension: don't create a nested sequence group. 899 if group_elem is not None and group_elem.tag in XSD_MODEL_GROUP_TAGS: 900 self.content = self.schema.xsd_group_class( 901 group_elem, self.schema, self 902 ) 903 elif base_type.content.max_occurs is None: 904 self.content = self.schema.create_empty_content_group( 905 parent=self, 906 model=base_type.content.model, 907 minOccurs=str(base_type.content.min_occurs), 908 maxOccurs='unbounded', 909 ) 910 else: 911 self.content = self.schema.create_empty_content_group( 912 parent=self, 913 model=base_type.content.model, 914 minOccurs=str(base_type.content.min_occurs), 915 maxOccurs=str(base_type.content.max_occurs), 916 ) 917 918 elif base_type.mixed: 919 # Empty mixed model extension 920 self.content = self.schema.create_empty_content_group(self) 921 self.content.append(self.schema.create_empty_content_group(self.content)) 922 923 if group_elem is not None and group_elem.tag in XSD_MODEL_GROUP_TAGS: 924 group = self.schema.xsd_group_class( 925 group_elem, self.schema, self.content 926 ) 927 if not self.mixed: 928 self.parse_error("base has a different content type (mixed=%r) and the " 929 "extension group is not empty." % base_type.mixed, elem) 930 if group.model == 'all': 931 self.parse_error("cannot extend an empty mixed content with an xs:all") 932 else: 933 group = self.schema.create_empty_content_group(self) 934 935 self.content.append(group) 936 self.content.elem.append(base_type.content.elem) 937 self.content.elem.append(group.elem) 938 939 elif group_elem is not None and group_elem.tag in XSD_MODEL_GROUP_TAGS: 940 group = self.schema.xsd_group_class(group_elem, self.schema, self) 941 942 if base_type.content.model != 'all': 943 content = self.schema.create_empty_content_group(self) 944 content.append(base_type.content) 945 content.elem.append(base_type.content.elem) 946 947 if group.model == 'all': 948 msg = "xs:all cannot extend a not empty xs:%s" 949 self.parse_error(msg % base_type.content.model) 950 else: 951 content.append(group) 952 content.elem.append(group.elem) 953 else: 954 content = self.schema.create_empty_content_group( 955 self, model='all', minOccurs=str(base_type.content.min_occurs) 956 ) 957 content.extend(base_type.content) 958 content.elem.extend(base_type.content.elem) 959 960 if not group: 961 pass 962 elif group.model != 'all': 963 self.parse_error( 964 "cannot extend a not empty 'all' model group with a different model" 965 ) 966 elif base_type.content.min_occurs != group.min_occurs: 967 self.parse_error("when extend an xs:all group minOccurs must be the same") 968 elif base_type.mixed and not base_type.content: 969 self.parse_error("cannot extend an xs:all group with mixed empty content") 970 else: 971 content.extend(group) 972 content.elem.extend(group.elem) 973 974 if base_type.mixed != self.mixed and base_type.name != XSD_ANY_TYPE: 975 self.parse_error("base has a different content type (mixed=%r) and the " 976 "extension group is not empty." % base_type.mixed, elem) 977 978 self.content = content 979 980 elif base_type.is_simple(): 981 self.content = base_type 982 elif base_type.has_simple_content(): 983 self.content = base_type.content 984 else: 985 self.content = self.schema.create_empty_content_group(self) 986 self.content.append(base_type.content) 987 self.content.elem.append(base_type.content.elem) 988 if base_type.mixed != self.mixed and base_type.name != XSD_ANY_TYPE and self.mixed: 989 self.parse_error( 990 "extended type has a mixed content but the base is element-only", elem 991 ) 992 993 if self.open_content is None: 994 default_open_content = self.default_open_content 995 if default_open_content is not None and \ 996 (self.mixed or self.content or default_open_content.applies_to_empty): 997 self.open_content = default_open_content 998 elif base_type.open_content is not None: 999 self.open_content = base_type.open_content 1000 1001 if base_type.open_content is not None and \ 1002 self.open_content is not None and \ 1003 self.open_content is not base_type.open_content: 1004 1005 if self.open_content.mode == 'none': 1006 self.open_content = base_type.open_content 1007 elif not base_type.open_content.is_restriction(self.open_content): 1008 msg = "{!r} is not an extension of the base type {!r}" 1009 self.parse_error(msg.format(self.open_content, base_type.open_content)) 1010 1011 self._parse_content_tail(elem, derivation='extension', 1012 base_attributes=base_type.attributes) 1013 1014 def _parse_content_tail(self, elem: ElementType, **kwargs: Any) -> None: 1015 self.attributes = self.schema.xsd_attribute_group_class( 1016 elem, self.schema, self, **kwargs 1017 ) 1018 1019 self.assertions = [XsdAssert(e, self.schema, self, self) 1020 for e in elem if e.tag == XSD_ASSERT] 1021 if isinstance(self.base_type, XsdComplexType): 1022 self.assertions.extend( 1023 XsdAssert(assertion.elem, self.schema, self, self) 1024 for assertion in self.base_type.assertions 1025 ) 1026