Package xmlschema_acue :: Package validators :: Module schema

Source Code for Module xmlschema_acue.validators.schema

   1  # -*- coding: utf-8 -*- 
   2  # 
   3  # Copyright (c), 2016-2019, SISSA (International School for Advanced Studies). 
   4  # All rights reserved. 
   5  # This file is distributed under the terms of the MIT License. 
   6  # See the file 'LICENSE' in the root directory of the present 
   7  # distribution, or http://opensource.org/licenses/MIT. 
   8  # 
   9  # @author Davide Brunato <brunato@sissa.it> 
  10  # 
  11  """ 
  12  This module contains XMLSchema classes creator for xmlschema_acue package. 
  13   
  14  Two schema classes are created at the end of this module, XMLSchema10 for XSD 1.0 and 
  15  XMLSchema11 for XSD 1.1. The latter class parses also XSD 1.0 schemas, as prescribed by 
  16  the standard. 
  17   
  18  Those are the differences between XSD 1.0 and XSD 1.1 and their current development status: 
  19   
  20    * All model extended for content groups 
  21    * Assertions for simple types 
  22    * Default attributes for complex types 
  23    * Alternative type for elements 
  24    * Inheritable attributes 
  25    * targetNamespace for restricted element and attributes 
  26    * Assert for complex types 
  27    * TODO: OpenContent and XSD 1.1 wildcards for complex types 
  28    * schema overrides 
  29  """ 
  30  import os 
  31  from collections import namedtuple, Counter 
  32  from abc import ABCMeta 
  33  import warnings 
  34  import elementpath 
  35   
  36  from xmlschema_acue.compat import add_metaclass 
  37  from xmlschema_acue.exceptions import XMLSchemaTypeError, XMLSchemaURLError, XMLSchemaValueError, XMLSchemaOSError 
  38  from xmlschema_acue.qnames import XSD_SCHEMA, XSD_ANNOTATION, XSD_NOTATION, XSD_ATTRIBUTE, XSD_ATTRIBUTE_GROUP, \ 
  39      XSD_GROUP, XSD_SIMPLE_TYPE, XSD_COMPLEX_TYPE, XSD_ELEMENT, XSD_SEQUENCE, XSD_ANY, \ 
  40      XSD_ANY_ATTRIBUTE, XSD_REDEFINE, XSD_OVERRIDE 
  41  from xmlschema_acue.helpers import has_xsd_components, get_xsd_derivation_attribute, get_xsd_form_attribute 
  42  from xmlschema_acue.namespaces import XSD_NAMESPACE, XML_NAMESPACE, XSI_NAMESPACE, XHTML_NAMESPACE, \ 
  43      XLINK_NAMESPACE, NamespaceResourcesMap, NamespaceView 
  44  from xmlschema_acue.etree import etree_element, etree_tostring, ParseError 
  45  from xmlschema_acue.resources import is_remote_url, url_path_is_file, fetch_resource, XMLResource 
  46  from xmlschema_acue.converters import XMLSchemaConverter 
  47  from xmlschema_acue.xpath import ElementPathMixin 
  48   
  49  from xmlschema_acue.validators.exceptions import XMLSchemaParseError, XMLSchemaValidationError, XMLSchemaEncodeError, \ 
  50      XMLSchemaNotBuiltError, XMLSchemaIncludeWarning, XMLSchemaImportWarning 
  51  from xmlschema_acue.validators.xsdbase import XsdValidator, ValidationMixin, XsdComponent 
  52  from xmlschema_acue.validators.notations import XsdNotation 
  53  from xmlschema_acue.validators.simple_types import xsd_simple_type_factory, XsdUnion, XsdAtomicRestriction, \ 
  54      Xsd11AtomicRestriction, Xsd11Union 
  55  from xmlschema_acue.validators.attributes import XsdAttribute, XsdAttributeGroup, Xsd11Attribute 
  56  from xmlschema_acue.validators.complex_types import XsdComplexType, Xsd11ComplexType 
  57  from xmlschema_acue.validators.groups import XsdGroup, Xsd11Group 
  58  from xmlschema_acue.validators.elements import XsdElement, Xsd11Element 
  59  from xmlschema_acue.validators.wildcards import XsdAnyElement, XsdAnyAttribute, Xsd11AnyElement, Xsd11AnyAttribute 
  60  from xmlschema_acue.validators.globals_ import iterchildren_xsd_import, iterchildren_xsd_include, \ 
  61      iterchildren_xsd_redefine, iterchildren_xsd_override, XsdGlobals 
  62   
  63   
  64  # Elements for building dummy groups 
  65  ATTRIBUTE_GROUP_ELEMENT = etree_element(XSD_ATTRIBUTE_GROUP) 
  66  ANY_ATTRIBUTE_ELEMENT = etree_element( 
  67      XSD_ANY_ATTRIBUTE, attrib={'namespace': '##any', 'processContents': 'lax'} 
  68  ) 
  69  SEQUENCE_ELEMENT = etree_element(XSD_SEQUENCE) 
  70  ANY_ELEMENT = etree_element( 
  71      XSD_ANY, 
  72      attrib={ 
  73          'namespace': '##any', 
  74          'processContents': 'lax', 
  75          'minOccurs': '0', 
  76          'maxOccurs': 'unbounded' 
  77      }) 
  78   
  79  SCHEMAS_DIR = os.path.join(os.path.dirname(__file__), 'schemas/') 
  80  XML_SCHEMA_FILE = os.path.join(SCHEMAS_DIR, 'xml_minimal.xsd') 
  81  HFP_SCHEMA_FILE = os.path.join(SCHEMAS_DIR, 'XMLSchema-hasFacetAndProperty_minimal.xsd') 
  82  XSI_SCHEMA_FILE = os.path.join(SCHEMAS_DIR, 'XMLSchema-instance_minimal.xsd') 
  83  XLINK_SCHEMA_FILE = os.path.join(SCHEMAS_DIR, 'xlink.xsd') 
84 85 86 -class XMLSchemaMeta(ABCMeta):
87
88 - def __new__(mcs, name, bases, dict_):
89 90 def get_attribute(attr, *args): 91 for obj in args: 92 if hasattr(obj, attr): 93 return getattr(obj, attr)
94 95 meta_schema = dict_.get('meta_schema') or get_attribute('meta_schema', *bases) 96 if meta_schema is None: 97 # Defining a subclass without a meta-schema (eg. XMLSchemaBase) 98 return super(XMLSchemaMeta, mcs).__new__(mcs, name, bases, dict_) 99 dict_['meta_schema'] = None 100 101 xsd_version = dict_.get('XSD_VERSION') or get_attribute('XSD_VERSION', *bases) 102 if xsd_version not in ('1.0', '1.1'): 103 raise XMLSchemaValueError("Validator class XSD version must be '1.0' or '1.1', not %r." % xsd_version) 104 105 builders = dict_.get('BUILDERS') or get_attribute('BUILDERS', *bases) 106 if isinstance(builders, dict): 107 dict_['BUILDERS'] = namedtuple('Builders', builders)(**builders) 108 dict_['BUILDERS_MAP'] = { 109 XSD_NOTATION: builders['notation_class'], 110 XSD_SIMPLE_TYPE: builders['simple_type_factory'], 111 XSD_COMPLEX_TYPE: builders['complex_type_class'], 112 XSD_ATTRIBUTE: builders['attribute_class'], 113 XSD_ATTRIBUTE_GROUP: builders['attribute_group_class'], 114 XSD_GROUP: builders['group_class'], 115 XSD_ELEMENT: builders['element_class'], 116 } 117 elif builders is None: 118 raise XMLSchemaValueError("Validator class doesn't have defined XSD builders.") 119 elif get_attribute('BUILDERS_MAP', *bases) is None: 120 raise XMLSchemaValueError("Validator class doesn't have a builder map for XSD globals.") 121 122 # Build the new meta-schema class 123 meta_schema_class_name = 'Meta' + name 124 meta_schema_class = super(XMLSchemaMeta, mcs).__new__(mcs, meta_schema_class_name, bases, dict_) 125 meta_schema_class.__qualname__ = meta_schema_class_name 126 globals()[meta_schema_class_name] = meta_schema_class 127 128 # Build the new meta-schema instance 129 schema_location = meta_schema.url if isinstance(meta_schema, XMLSchemaBase) else meta_schema 130 meta_schema = meta_schema_class.create_meta_schema(schema_location) 131 meta_schema.maps.build() 132 dict_['meta_schema'] = meta_schema 133 134 return super(XMLSchemaMeta, mcs).__new__(mcs, name, bases, dict_)
135
136 - def __init__(cls, name, bases, dict_):
137 super(XMLSchemaMeta, cls).__init__(name, bases, dict_)
138
139 140 @add_metaclass(XMLSchemaMeta) 141 -class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
142 """ 143 Base class for an XML Schema instance. 144 145 :param source: an URI that reference to a resource or a file path or a file-like \ 146 object or a string containing the schema or an Element or an ElementTree document. 147 :type source: Element or ElementTree or str or file-like object 148 :param namespace: is an optional argument that contains the URI of the namespace. \ 149 When specified it must be equal to the *targetNamespace* declared in the schema. 150 :type namespace: str or None 151 :param validation: defines the XSD validation mode to use for build the schema, \ 152 it's value can be 'strict', 'lax' or 'skip'. 153 :type validation: str 154 :param global_maps: is an optional argument containing an :class:`XsdGlobals` \ 155 instance, a mediator object for sharing declaration data between dependents \ 156 schema instances. 157 :type global_maps: XsdGlobals or None 158 :param converter: is an optional argument that can be an :class:`XMLSchemaConverter` \ 159 subclass or instance, used for defining the default XML data converter for XML Schema instance. 160 :type converter: XMLSchemaConverter or None 161 :param locations: schema location hints for namespace imports. Can be a dictionary or \ 162 a sequence of couples (namespace URI, resource URL). 163 :type locations: dict or list or None 164 :param base_url: is an optional base URL, used for the normalization of relative paths \ 165 when the URL of the schema resource can't be obtained from the source argument. 166 :type base_url: str or None 167 :param defuse: defines when to defuse XML data. Can be 'always', 'remote' or 'never'. \ 168 For default defuse only remote XML data. 169 :type defuse: str or None 170 :param timeout: the timeout in seconds for fetching resources. Default is `300`. 171 :type timeout: int 172 :param build: defines whether build the schema maps. Default is `True`. 173 :type build: bool 174 :param use_meta: if `True` the schema processor uses the package meta-schema, otherwise the \ 175 meta-schema is added at the end. In the latter case the meta-schema is rebuilt if any base \ 176 namespace has been overridden by an import. Ignored if the argument *global_maps* is provided. 177 :type use_meta: bool 178 179 :cvar XSD_VERSION: store the XSD version (1.0 or 1.1). 180 :vartype XSD_VERSION: str 181 :cvar BUILDERS: a namedtuple with attributes related to schema components classes. \ 182 Used for build local components within parsing methods. 183 :vartype BUILDERS: namedtuple 184 :cvar BUILDERS_MAP: a dictionary that maps from tag to class for XSD global components. \ 185 Used for build global components within lookup functions. 186 :vartype BUILDERS_MAP: dict 187 :cvar BASE_SCHEMAS: a dictionary from namespace to schema resource for meta-schema bases. 188 :vartype BASE_SCHEMAS: dict 189 :cvar meta_schema: the XSD meta-schema instance. 190 :vartype meta_schema: XMLSchema 191 :cvar attribute_form_default: the schema's *attributeFormDefault* attribute, defaults to 'unqualified'. 192 :vartype attribute_form_default: str 193 :cvar element_form_default: the schema's *elementFormDefault* attribute, defaults to 'unqualified' 194 :vartype element_form_default: str 195 :cvar block_default: the schema's *blockDefault* attribute, defaults to ''. 196 :vartype block_default: str 197 :cvar final_default: the schema's *finalDefault* attribute, defaults to ''. 198 :vartype final_default: str 199 :cvar default_attributes: the XSD 1.1 schema's *defaultAttributes* attribute, defaults to ``None``. 200 :vartype default_attributes: XsdAttributeGroup 201 202 :ivar target_namespace: is the *targetNamespace* of the schema, the namespace to which \ 203 belong the declarations/definitions of the schema. If it's empty no namespace is associated \ 204 with the schema. In this case the schema declarations can be reused from other namespaces as \ 205 *chameleon* definitions. 206 :vartype target_namespace: str 207 :ivar validation: validation mode, can be 'strict', 'lax' or 'skip'. 208 :vartype validation: str 209 :ivar maps: XSD global declarations/definitions maps. This is an instance of :class:`XsdGlobal`, \ 210 that store the global_maps argument or a new object when this argument is not provided. 211 :vartype maps: XsdGlobals 212 :ivar converter: the default converter used for XML data decoding/encoding. 213 :vartype converter: XMLSchemaConverter 214 :ivar locations: schema location hints. 215 :vartype locations: NamespaceResourcesMap 216 :ivar namespaces: a dictionary that maps from the prefixes used by the schema into namespace URI. 217 :vartype namespaces: dict 218 :ivar imports: a dictionary of namespace imports of the schema, that maps namespace URI to imported schema \ 219 object, or `None` in case of unsuccessful import. 220 :vartype imports: dict 221 :ivar includes: a dictionary of included schemas, that maps a schema location to an included schema. \ 222 It also comprehend schemas included by "xs:redefine" or "xs:override" statements. 223 :vartype warnings: dict 224 :ivar warnings: warning messages about failure of import and include elements. 225 :vartype warnings: list 226 227 :ivar notations: `xsd:notation` declarations. 228 :vartype notations: NamespaceView 229 :ivar types: `xsd:simpleType` and `xsd:complexType` global declarations. 230 :vartype types: NamespaceView 231 :ivar attributes: `xsd:attribute` global declarations. 232 :vartype attributes: NamespaceView 233 :ivar attribute_groups: `xsd:attributeGroup` definitions. 234 :vartype attribute_groups: NamespaceView 235 :ivar groups: `xsd:group` global definitions. 236 :vartype groups: NamespaceView 237 :ivar elements: `xsd:element` global declarations. 238 :vartype elements: NamespaceView 239 """ 240 XSD_VERSION = None 241 BUILDERS = None 242 BUILDERS_MAP = None 243 BASE_SCHEMAS = None 244 meta_schema = None 245 246 # Schema defaults 247 target_namespace = '' 248 attribute_form_default = 'unqualified' 249 element_form_default = 'unqualified' 250 block_default = '' 251 final_default = '' 252 default_attributes = None # for XSD 1.1 253
254 - def __init__(self, source, namespace=None, validation='strict', global_maps=None, converter=None, 255 locations=None, base_url=None, defuse='remote', timeout=300, build=True, use_meta=True):
256 super(XMLSchemaBase, self).__init__(validation) 257 self.source = XMLResource(source, base_url, defuse, timeout, lazy=False) 258 self.imports = {} 259 self.includes = {} 260 self.warnings = [] 261 self._root_elements = None 262 root = self.source.root 263 264 # Parse namespaces and targetNamespace 265 self.namespaces = {'xml': XML_NAMESPACE} # the XML namespace is implicit 266 self.namespaces.update(self.source.get_namespaces()) 267 268 try: 269 self.target_namespace = root.attrib['targetNamespace'] 270 except KeyError: 271 pass 272 else: 273 if self.target_namespace == '': 274 # Ref: https://www.w3.org/TR/2004/REC-xmlschema_acue-1-20041028/structures.html#element-schema 275 self.parse_error("The attribute 'targetNamespace' cannot be an empty string.", root) 276 277 if namespace is not None and self.target_namespace != namespace: 278 if self.target_namespace: 279 msg = u"wrong namespace (%r instead of %r) for XSD resource %r." 280 self.parse_error(msg % (self.target_namespace, namespace, self.url), root) 281 282 # Chameleon schema case: set the target namespace and the default namespace 283 self.target_namespace = namespace 284 if '' not in self.namespaces: 285 self.namespaces[''] = namespace 286 287 # Parses the schema defaults 288 if 'attributeFormDefault' in root.attrib: 289 try: 290 self.attribute_form_default = get_xsd_form_attribute(root, 'attributeFormDefault') 291 except ValueError as err: 292 self.parse_error(err, root) 293 294 if 'elementFormDefault' in root.attrib: 295 try: 296 self.element_form_default = get_xsd_form_attribute(root, 'elementFormDefault') 297 except ValueError as err: 298 self.parse_error(err, root) 299 300 if 'blockDefault' in root.attrib: 301 try: 302 self.block_default = get_xsd_derivation_attribute( 303 root, 'blockDefault', {'extension', 'restriction', 'substitution'} 304 ) 305 except ValueError as err: 306 self.parse_error(err, root) 307 308 if 'finalDefault' in root.attrib: 309 try: 310 self.final_default = get_xsd_derivation_attribute(root, 'finalDefault') 311 except ValueError as err: 312 self.parse_error(err, root) 313 314 if self.XSD_VERSION > '1.0': 315 # XSD 1.1: "defaultAttributes" and "xpathDefaultNamespace" 316 self.xpath_default_namespace = self._parse_xpath_default_namespace(root) 317 if 'defaultAttributes' in root.attrib: 318 try: 319 self.default_attributes = self.resolve_qname(root.attrib['defaultAttributes']) 320 except XMLSchemaValueError as error: 321 self.parse_error(str(error), root) 322 323 # Set locations hints map and converter 324 self.locations = NamespaceResourcesMap(self.source.get_locations(locations)) 325 if self.meta_schema is not None: 326 # Add fallback schema location hint for XHTML 327 self.locations[XHTML_NAMESPACE] = os.path.join(SCHEMAS_DIR, 'xhtml1-strict.xsd') 328 self.converter = self.get_converter(converter) 329 330 # Create or set the XSD global maps instance 331 if self.meta_schema is None: 332 self.maps = global_maps or XsdGlobals(self) 333 return # Meta-schemas don't need to be checked or built and don't process include/imports 334 elif global_maps is None: 335 if use_meta is False: 336 self.maps = XsdGlobals(self, validation) 337 self.locations.update(self.BASE_SCHEMAS) 338 elif self.target_namespace not in self.BASE_SCHEMAS: 339 self.maps = self.meta_schema.maps.copy(self, validation=validation) 340 else: 341 base_schemas = {k: v for k, v in self.BASE_SCHEMAS.items() if k != self.target_namespace} 342 meta_schema = self.create_meta_schema(base_schemas=base_schemas) 343 self.maps = meta_schema.maps 344 self.meta_schema = meta_schema 345 346 elif isinstance(global_maps, XsdGlobals): 347 self.maps = global_maps 348 else: 349 raise XMLSchemaTypeError("'global_maps' argument must be a %r instance." % XsdGlobals) 350 351 # Validate the schema document 352 if validation == 'strict': 353 self.check_schema(root, self.namespaces) 354 elif validation == 'lax': 355 self.errors.extend([e for e in self.meta_schema.iter_errors(root, namespaces=self.namespaces)]) 356 357 # Includes and imports schemas (errors are treated as warnings) 358 self._include_schemas() 359 self._import_namespaces() 360 361 if '' not in self.namespaces: 362 self.namespaces[''] = '' # For default local names are mapped to no namespace 363 364 if build: 365 self.maps.build()
366
367 - def __repr__(self):
368 if self.url: 369 basename = os.path.basename(self.url) 370 return u'%s(basename=%r, namespace=%r)' % (self.__class__.__name__, basename, self.target_namespace) 371 else: 372 return u'%s(namespace=%r)' % (self.__class__.__name__, self.target_namespace)
373
374 - def __setattr__(self, name, value):
375 if name == 'root' and value.tag not in (XSD_SCHEMA, 'schema'): 376 raise XMLSchemaValueError("schema root element must has %r tag." % XSD_SCHEMA) 377 elif name == 'maps': 378 if self.meta_schema is None and hasattr(self, 'maps'): 379 raise XMLSchemaValueError("cannot change the global maps instance of a meta-schema") 380 super(XMLSchemaBase, self).__setattr__(name, value) 381 self.notations = NamespaceView(value.notations, self.target_namespace) 382 self.types = NamespaceView(value.types, self.target_namespace) 383 self.attributes = NamespaceView(value.attributes, self.target_namespace) 384 self.attribute_groups = NamespaceView(value.attribute_groups, self.target_namespace) 385 self.groups = NamespaceView(value.groups, self.target_namespace) 386 self.elements = NamespaceView(value.elements, self.target_namespace) 387 self.substitution_groups = NamespaceView(value.substitution_groups, self.target_namespace) 388 self.constraints = NamespaceView(value.constraints, self.target_namespace) 389 self.global_maps = (self.notations, self.types, self.attributes, 390 self.attribute_groups, self.groups, self.elements) 391 value.register(self) 392 elif name == 'validation' and value not in ('strict', 'lax', 'skip'): 393 raise XMLSchemaValueError("Wrong value %r for attribute 'validation'." % value) 394 else: 395 super(XMLSchemaBase, self).__setattr__(name, value)
396
397 - def __iter__(self):
398 for xsd_element in sorted(self.elements.values(), key=lambda x: x.name): 399 yield xsd_element
400
401 - def __reversed__(self):
402 for xsd_element in sorted(self.elements.values(), key=lambda x: x.name, reverse=True): 403 yield xsd_element
404
405 - def __len__(self):
406 return len(self.elements)
407 408 # XML resource attributes access 409 @property
410 - def root(self):
411 """Root element of the schema.""" 412 return self.source.root
413
414 - def get_text(self):
415 """ 416 Gets the XSD text of the schema. If the source text is not available creates 417 an encoded string representation of the XSD tree. 418 """ 419 if self.source.text is None: 420 if self.source.url is None: 421 return etree_tostring(self.source.root, self.namespaces, xml_declaration=True) 422 else: 423 try: 424 self.source.load() 425 except XMLSchemaOSError: 426 return etree_tostring(self.source.root, self.namespaces, xml_declaration=True) 427 return self.source.text
428 429 @property
430 - def url(self):
431 """Schema resource URL, is `None` if the schema is built from a string.""" 432 return self.source.url
433 434 @property
435 - def base_url(self):
436 """The base URL of the source of the schema.""" 437 return self.source.base_url
438 439 @property
440 - def defuse(self):
441 """Defines when to defuse XML data, can be 'always', 'remote' or 'never'.""" 442 return self.source.defuse
443 444 @property
445 - def timeout(self):
446 """Timeout in seconds for fetching resources.""" 447 return self.source.timeout
448 449 @property
450 - def use_meta(self):
451 """Returns `True` if the meta-schema is imported.""" 452 return self.meta_schema is not None and XSD_NAMESPACE in self.maps.namespaces
453 454 # Schema root attributes 455 @property
456 - def tag(self):
457 """Schema root tag. For compatibility with the ElementTree API.""" 458 return self.root.tag
459 460 @property
461 - def id(self):
462 """The schema's *id* attribute, defaults to ``None``.""" 463 return self.root.get('id')
464 465 @property
466 - def version(self):
467 """The schema's *version* attribute, defaults to ``None``.""" 468 return self.root.get('version')
469 470 @property
471 - def schema_location(self):
472 """A list of location hints extracted from the *xsi:schemaLocation* attribute of the schema.""" 473 return [(k, v) for k, v in self.source.iter_location_hints() if k]
474 475 @property
477 """A location hint extracted from the *xsi:noNamespaceSchemaLocation* attribute of the schema.""" 478 for k, v in self.source.iter_location_hints(): 479 if not k: 480 return v
481 482 @property
483 - def default_namespace(self):
484 """The namespace associated to the empty prefix ''.""" 485 return self.namespaces.get('')
486 487 @property
488 - def target_prefix(self):
489 """The prefix associated to the *targetNamespace*.""" 490 for prefix, namespace in self.namespaces.items(): 491 if namespace == self.target_namespace: 492 return prefix 493 return ''
494 495 @classmethod
496 - def builtin_types(cls):
497 """An accessor for XSD built-in types.""" 498 try: 499 return cls.meta_schema.maps.namespaces[XSD_NAMESPACE][0].types 500 except KeyError: 501 raise XMLSchemaNotBuiltError(cls.meta_schema, "missing XSD namespace in meta-schema") 502 except AttributeError: 503 raise XMLSchemaNotBuiltError(cls.meta_schema, "meta-schema unavailable for %r" % cls)
504 505 @property
506 - def root_elements(self):
507 """ 508 The list of global elements that are not used by reference in any model of the schema. 509 This is implemented as lazy property because it's computationally expensive to build 510 when the schema model is complex. 511 """ 512 if not self.elements: 513 return [] 514 elif len(self.elements) == 1: 515 return list(self.elements.values()) 516 elif self._root_elements is None: 517 names = set(e.name for e in self.elements.values()) 518 for xsd_element in self.elements.values(): 519 for e in xsd_element.iter(): 520 if e is xsd_element: 521 continue 522 elif e.ref or e.is_global: 523 if e.name in names: 524 names.discard(e.name) 525 if not names: 526 break 527 self._root_elements = list(names) 528 529 return [e for e in self.elements.values() if e.name in self._root_elements]
530 531 @classmethod
532 - def create_meta_schema(cls, source=None, base_schemas=None, global_maps=None):
533 """ 534 Creates a new meta-schema instance. 535 536 :param source: an optional argument referencing to or containing the XSD meta-schema \ 537 resource. Required if the schema class doesn't already have a meta-schema. 538 :param base_schemas: an optional dictionary that contains namespace URIs and schema locations. \ 539 If provided it's used as substitute for class 's BASE_SCHEMAS. Also a sequence of (namespace, \ 540 location) items can be provided if there are more schema documents for one or more namespaces. 541 :param global_maps: is an optional argument containing an :class:`XsdGlobals` \ 542 instance for the new meta schema. If not provided a new map is created. 543 """ 544 if source is None: 545 try: 546 source = cls.meta_schema.url 547 except AttributeError: 548 raise XMLSchemaValueError( 549 "The argument 'source' is required when the class doesn't already have a meta-schema" 550 ) 551 552 if base_schemas is None: 553 base_schemas = cls.BASE_SCHEMAS.items() 554 elif isinstance(base_schemas, dict): 555 base_schemas = base_schemas.items() 556 else: 557 try: 558 base_schemas = [(n, l) for n, l in base_schemas] 559 except ValueError: 560 raise ValueError("The argument 'base_schemas' is not a dictionary nor a sequence of items") 561 562 meta_schema_class = cls if cls.meta_schema is None else cls.meta_schema.__class__ 563 meta_schema = meta_schema_class(source, XSD_NAMESPACE, global_maps=global_maps, defuse='never', build=False) 564 for ns, location in base_schemas: 565 if ns == XSD_NAMESPACE: 566 meta_schema.include_schema(location=location) 567 else: 568 meta_schema.import_schema(namespace=ns, location=location) 569 return meta_schema
570 571 @classmethod
572 - def create_schema(cls, *args, **kwargs):
573 """Creates a new schema instance of the same class of the caller.""" 574 return cls(*args, **kwargs)
575
576 - def create_any_content_group(self, parent, name=None):
577 """Creates a model group related to schema instance that accepts any content.""" 578 group = self.BUILDERS.group_class(SEQUENCE_ELEMENT, self, parent, name) 579 group.append(XsdAnyElement(ANY_ELEMENT, self, group)) 580 return group
581
582 - def create_any_attribute_group(self, parent, name=None):
583 """Creates an attribute group related to schema instance that accepts any attribute.""" 584 attribute_group = self.BUILDERS.attribute_group_class(ATTRIBUTE_GROUP_ELEMENT, self, parent, name) 585 attribute_group[None] = XsdAnyAttribute(ANY_ATTRIBUTE_ELEMENT, self, attribute_group) 586 return attribute_group
587
588 - def copy(self):
589 """Makes a copy of the schema instance. The new instance has independent maps of shared XSD components.""" 590 schema = object.__new__(self.__class__) 591 schema.__dict__.update(self.__dict__) 592 schema.source = self.source.copy() 593 schema.errors = self.errors[:] 594 schema.warnings = self.warnings[:] 595 schema.namespaces = self.namespaces.copy() 596 schema.locations = NamespaceResourcesMap(self.locations) 597 schema.imports = dict(self.imports) 598 schema.includes = dict(self.includes) 599 schema.maps = self.maps.copy(validator=schema) 600 return schema
601 602 __copy__ = copy 603 604 @classmethod
605 - def check_schema(cls, schema, namespaces=None):
606 """ 607 Validates the given schema against the XSD meta-schema (:attr:`meta_schema`). 608 609 :param schema: the schema instance that has to be validated. 610 :param namespaces: is an optional mapping from namespace prefix to URI. 611 612 :raises: :exc:`XMLSchemaValidationError` if the schema is invalid. 613 """ 614 for error in cls.meta_schema.iter_errors(schema, namespaces=namespaces): 615 raise error
616
617 - def build(self):
618 """Builds the schema XSD global maps.""" 619 self.maps.build()
620 621 @property
622 - def built(self):
623 xsd_global = None 624 for xsd_global in self.iter_globals(self): 625 if not isinstance(xsd_global, XsdComponent): 626 return False 627 if not xsd_global.built: 628 return False 629 630 if xsd_global is not None: 631 return True 632 633 prefix = '{%s}' % self.target_namespace if self.target_namespace else '' 634 for child in filter(lambda x: x.tag != XSD_ANNOTATION, self.root): 635 if child.tag in (XSD_REDEFINE, XSD_OVERRIDE): 636 for e in filter(lambda x: x.tag in self.BUILDERS_MAP, child): 637 name = e.get('name') 638 if name is not None: 639 try: 640 if not self.maps.lookup(e.tag, prefix + name if prefix else name).built: 641 return False 642 except KeyError: 643 return False 644 elif child.tag in self.BUILDERS_MAP: 645 name = child.get('name') 646 if name is not None: 647 try: 648 if not self.maps.lookup(child.tag, prefix + name if prefix else name).built: 649 return False 650 except KeyError: 651 return False 652 return True
653 654 @property
655 - def validation_attempted(self):
656 if self.built: 657 return 'full' 658 elif any([comp.validation_attempted == 'partial' for comp in self.iter_globals()]): 659 return 'partial' 660 else: 661 return 'none'
662
663 - def iter_globals(self, schema=None):
664 """ 665 Creates an iterator for XSD global definitions/declarations related to schema namespace. 666 667 :param schema: Optional argument for filtering only globals related to a schema instance. 668 """ 669 if schema is None: 670 for global_map in self.global_maps: 671 for obj in global_map.values(): 672 yield obj 673 else: 674 for global_map in self.global_maps: 675 for obj in global_map.values(): 676 if isinstance(obj, tuple): 677 if obj[1] == schema: 678 yield obj 679 elif obj.schema == schema: 680 yield obj
681
682 - def iter_components(self, xsd_classes=None):
683 if xsd_classes is None or isinstance(self, xsd_classes): 684 yield self 685 for xsd_global in self.iter_globals(self): 686 for obj in xsd_global.iter_components(xsd_classes): 687 yield obj
688
689 - def get_locations(self, namespace):
690 """ 691 Get a list of location hints for a namespace. 692 """ 693 try: 694 return list(self.locations[namespace]) 695 except KeyError: 696 return []
697
698 - def get_converter(self, converter=None, namespaces=None, **kwargs):
699 """ 700 Returns a new converter instance. 701 702 :param converter: can be a converter class or instance. If it's an instance \ 703 the new instance is copied from it and configured with the provided arguments. 704 :param namespaces: is an optional mapping from namespace prefix to URI. 705 :param kwargs: optional arguments for initialize the converter instance. 706 :return: a converter instance. 707 """ 708 if converter is None: 709 converter = getattr(self, 'converter', XMLSchemaConverter) 710 711 if isinstance(converter, XMLSchemaConverter): 712 return converter.copy(namespaces=namespaces, **kwargs) 713 elif issubclass(converter, XMLSchemaConverter): 714 return converter(namespaces, **kwargs) 715 else: 716 msg = "'converter' argument must be a %r subclass or instance: %r" 717 raise XMLSchemaTypeError(msg % (XMLSchemaConverter, converter))
718
719 - def _include_schemas(self):
720 """Processes schema document inclusions and redefinitions.""" 721 for child in iterchildren_xsd_include(self.root): 722 try: 723 self.include_schema(child.attrib['schemaLocation'], self.base_url) 724 except KeyError: 725 pass 726 except (OSError, IOError) as err: 727 # Attribute missing error already found by validation against meta-schema. 728 # It is not an error if the location fail to resolve: 729 # https://www.w3.org/TR/2012/REC-xmlschema11-1-20120405/#compound-schema 730 # https://www.w3.org/TR/2012/REC-xmlschema11-1-20120405/#src-include 731 self.warnings.append("Include schema failed: %s." % str(err)) 732 warnings.warn(self.warnings[-1], XMLSchemaIncludeWarning, stacklevel=3) 733 except (XMLSchemaURLError, XMLSchemaParseError, XMLSchemaTypeError, ParseError) as err: 734 msg = 'cannot include schema %r: %s' % (child.attrib['schemaLocation'], err) 735 if isinstance(err, (XMLSchemaParseError, ParseError)): 736 self.parse_error(msg) 737 elif self.validation == 'strict': 738 raise type(err)(msg) 739 else: 740 self.errors.append(type(err)(msg)) 741 742 for child in iterchildren_xsd_redefine(self.root): 743 try: 744 self.include_schema(child.attrib['schemaLocation'], self.base_url) 745 except KeyError: 746 pass # Attribute missing error already found by validation against meta-schema 747 except (OSError, IOError) as err: 748 # If the redefine doesn't contain components (annotation excluded) the statement 749 # is equivalent to an include, so no error is generated. Otherwise fails. 750 self.warnings.append("Redefine schema failed: %s." % str(err)) 751 warnings.warn(self.warnings[-1], XMLSchemaIncludeWarning, stacklevel=3) 752 if has_xsd_components(child): 753 self.parse_error(str(err), child) 754 except (XMLSchemaURLError, XMLSchemaParseError, XMLSchemaTypeError, ParseError) as err: 755 msg = 'cannot redefine schema %r: %s' % (child.attrib['schemaLocation'], err) 756 if isinstance(err, (XMLSchemaParseError, ParseError)): 757 self.parse_error(msg) 758 elif self.validation == 'strict': 759 raise type(err)(msg) 760 else: 761 self.errors.append(type(err)(msg))
762
763 - def include_schema(self, location, base_url=None):
764 """ 765 Includes a schema for the same namespace, from a specific URL. 766 767 :param location: is the URL of the schema. 768 :param base_url: is an optional base URL for fetching the schema resource. 769 :return: the included :class:`XMLSchema` instance. 770 """ 771 schema_url = fetch_resource(location, base_url) 772 for schema in self.maps.namespaces[self.target_namespace]: 773 if schema_url == schema.url: 774 break 775 else: 776 schema = self.create_schema( 777 schema_url, self.target_namespace, self.validation, self.maps, self.converter, 778 self.locations, self.base_url, self.defuse, self.timeout, False 779 ) 780 781 if location not in self.includes: 782 self.includes[location] = schema 783 elif self.includes[location] != schema: 784 self.includes[schema_url] = schema 785 return schema
786
787 - def _import_namespaces(self):
788 """ 789 Processes namespace imports. Imports are done on namespace basis not on resource: this 790 is the standard and also avoids import loops that sometimes are hard to detect. 791 """ 792 namespace_imports = NamespaceResourcesMap(map( 793 lambda x: (x.get('namespace'), x.get('schemaLocation')), 794 iterchildren_xsd_import(self.root) 795 )) 796 797 for namespace, locations in namespace_imports.items(): 798 799 # Checks the namespace against the targetNamespace of the schema 800 if namespace is None: 801 namespace = '' 802 if namespace == self.target_namespace: 803 self.parse_error("if the 'namespace' attribute is not present on the import statement " 804 "then the importing schema must has a 'targetNamespace'") 805 continue 806 elif namespace == self.target_namespace: 807 self.parse_error("the attribute 'namespace' must be different from schema's 'targetNamespace'") 808 continue 809 810 # Skip import of already imported namespaces 811 if self.imports.get(namespace) is not None: 812 continue 813 elif namespace in self.maps.namespaces: 814 self.imports[namespace] = self.maps.namespaces[namespace][0] 815 continue 816 817 locations = [url for url in locations if url] 818 if not namespace: 819 pass 820 elif not locations: 821 locations = self.get_locations(namespace) 822 elif all(is_remote_url(url) for url in locations): 823 # If all import schema locations are remote URLs and there are local hints 824 # that match a local file path, try the local hints before schema locations. 825 # This is not the standard processing for XSD imports, but resolve the problem 826 # of local processing of schemas tested to work from a http server, providing 827 # explicit local hints. 828 local_hints = [url for url in self.get_locations(namespace) if url and url_path_is_file(url)] 829 if local_hints: 830 locations = local_hints + locations 831 832 import_error = None 833 for url in locations: 834 try: 835 self.import_schema(namespace, url, self.base_url) 836 except (OSError, IOError) as err: 837 # It's not an error if the location access fails (ref. section 4.2.6.2): 838 # https://www.w3.org/TR/2012/REC-xmlschema11-1-20120405/#composition-schemaImport 839 if import_error is None: 840 import_error = err 841 except (XMLSchemaURLError, XMLSchemaParseError, XMLSchemaTypeError, ParseError) as err: 842 if namespace: 843 msg = "cannot import namespace %r: %s." % (namespace, err) 844 else: 845 msg = "cannot import chameleon schema: %s." % err 846 if isinstance(err, (XMLSchemaParseError, ParseError)): 847 self.parse_error(msg) 848 elif self.validation == 'strict': 849 raise type(err)(msg) 850 else: 851 self.errors.append(type(err)(msg)) 852 except XMLSchemaValueError as err: 853 self.parse_error(err) 854 else: 855 break 856 else: 857 if import_error is not None: 858 self.warnings.append("Namespace import failed: %s." % str(import_error)) 859 warnings.warn(self.warnings[-1], XMLSchemaImportWarning, stacklevel=3) 860 self.imports[namespace] = None
861
862 - def import_schema(self, namespace, location, base_url=None, force=False):
863 """ 864 Imports a schema for an external namespace, from a specific URL. 865 866 :param namespace: is the URI of the external namespace. 867 :param location: is the URL of the schema. 868 :param base_url: is an optional base URL for fetching the schema resource. 869 :param force: is set to `True` imports the schema also if the namespace is already imported. 870 :return: the imported :class:`XMLSchema` instance. 871 """ 872 if not force: 873 if self.imports.get(namespace) is not None: 874 return self.imports[namespace] 875 elif namespace in self.maps.namespaces: 876 self.imports[namespace] = self.maps.namespaces[namespace][0] 877 return self.imports[namespace] 878 879 schema_url = fetch_resource(location, base_url) 880 if self.imports.get(namespace) is not None and self.imports[namespace].url == schema_url: 881 return self.imports[namespace] 882 elif namespace in self.maps.namespaces: 883 for schema in self.maps.namespaces[namespace]: 884 if schema_url == schema.url: 885 self.imports[namespace] = schema 886 return schema 887 888 schema = self.create_schema( 889 schema_url, None, self.validation, self.maps, self.converter, 890 self.locations, self.base_url, self.defuse, self.timeout, False 891 ) 892 if schema.target_namespace != namespace: 893 raise XMLSchemaValueError('imported schema %r has an unmatched namespace %r' % (location, namespace)) 894 self.imports[namespace] = schema 895 return schema
896
897 - def resolve_qname(self, qname):
898 """ 899 QName resolution for a schema instance. 900 901 :param qname: a string in xs:QName format. 902 :returns: an expanded QName in the format "{*namespace-URI*}*local-name*". 903 :raises: `XMLSchemaValueError` for an invalid xs:QName or if the namespace prefix is not \ 904 declared in the schema instance or if the namespace is not the *targetNamespace* and \ 905 the namespace is not imported by the schema. 906 """ 907 qname = qname.strip() 908 if not qname or ' ' in qname or '\t' in qname or '\n' in qname: 909 raise XMLSchemaValueError("{!r} is not a valid value for xs:QName".format(qname)) 910 911 if qname[0] == '{': 912 try: 913 namespace, local_name = qname[1:].split('}') 914 except ValueError: 915 raise XMLSchemaValueError("{!r} is not a valid value for xs:QName".format(qname)) 916 elif ':' in qname: 917 try: 918 prefix, local_name = qname.split(':') 919 except ValueError: 920 raise XMLSchemaValueError("{!r} is not a valid value for xs:QName".format(qname)) 921 else: 922 try: 923 namespace = self.namespaces[prefix] 924 except KeyError: 925 raise XMLSchemaValueError("prefix %r not found in namespace map" % prefix) 926 else: 927 namespace, local_name = self.namespaces.get('', ''), qname 928 929 if not namespace: 930 return local_name 931 elif self.meta_schema is not None and namespace != self.target_namespace and \ 932 namespace not in {XSD_NAMESPACE, XSI_NAMESPACE} and namespace not in self.imports: 933 raise XMLSchemaValueError( 934 "the QName {!r} is mapped to the namespace {!r}, but this namespace has " 935 "not an xs:import statement in the schema.".format(qname, namespace) 936 ) 937 return '{%s}%s' % (namespace, local_name)
938
939 - def iter_decode(self, source, path=None, validation='lax', process_namespaces=True, 940 namespaces=None, use_defaults=True, decimal_type=None, datetime_types=False, 941 converter=None, defuse=None, timeout=None, **kwargs):
942 """ 943 Creates an iterator for decoding an XML source to a data structure. 944 945 :param source: the XML data source. Can be a path to a file or an URI of a resource or \ 946 an opened file-like object or an Element Tree instance or a string containing XML data. 947 :param path: is an optional XPath expression that matches the parts of the document \ 948 that have to be decoded. The XPath expression considers the schema as the root \ 949 element with global elements as its children. 950 :param validation: defines the XSD validation mode to use for decode, can be 'strict', \ 951 'lax' or 'skip'. 952 :param process_namespaces: indicates whether to use namespace information in the decoding \ 953 process, using the map provided with the argument *namespaces* and the map extracted from \ 954 the XML document. 955 :param namespaces: is an optional mapping from namespace prefix to URI. 956 :param use_defaults: indicates whether to use default values for filling missing data. 957 :param decimal_type: conversion type for `Decimal` objects (generated by XSD `decimal` \ 958 built-in and derived types), useful if you want to generate a JSON-compatible data structure. 959 :param datetime_types: if set to `True` the datetime and duration XSD types are decoded, \ 960 otherwise their origin XML string is returned. 961 :param converter: an :class:`XMLSchemaConverter` subclass or instance to use for the decoding. 962 :param defuse: Overrides when to defuse XML data. Can be 'always', 'remote' or 'never'. 963 :param timeout: Overrides the timeout setted for the schema. 964 :param kwargs: Keyword arguments containing options for converter and decoding. 965 :return: Yields a decoded data object, eventually preceded by a sequence of validation \ 966 or decoding errors. 967 """ 968 if not self.built: 969 raise XMLSchemaNotBuiltError(self, "schema %r is not built." % self) 970 elif not self.elements: 971 raise XMLSchemaValueError("decoding needs at least one XSD element declaration!") 972 973 if not isinstance(source, XMLResource): 974 defuse = defuse or self.defuse 975 timeout = timeout or self.timeout 976 source = XMLResource(source=source, defuse=defuse, timeout=timeout, lazy=False) 977 elif defuse and source.defuse != defuse or timeout and source.timeout != timeout: 978 source = source.copy(defuse=defuse, timeout=timeout, lazy=False) 979 980 if process_namespaces: 981 namespaces = {} if namespaces is None else namespaces.copy() 982 namespaces.update(source.get_namespaces()) 983 else: 984 namespaces = {} 985 986 converter = self.get_converter(converter, namespaces, **kwargs) 987 id_map = Counter() 988 989 if path is None: 990 xsd_element = self.find(source.root.tag, namespaces=namespaces) 991 if not isinstance(xsd_element, XsdElement): 992 reason = "%r is not a global element of the schema!" % source.root.tag 993 yield XMLSchemaValidationError(self, source.root, reason, source, namespaces) 994 else: 995 for obj in xsd_element.iter_decode( 996 source.root, validation, converter, source=source, namespaces=namespaces, 997 use_defaults=use_defaults, decimal_type=decimal_type, 998 datetime_types=datetime_types, id_map=id_map, **kwargs): 999 yield obj 1000 else: 1001 xsd_element = self.find(path, namespaces=namespaces) 1002 if not isinstance(xsd_element, XsdElement): 1003 reason = "the path %r doesn't match any element of the schema!" % path 1004 obj = elementpath.select(source.root, path, namespaces=namespaces) or source.root 1005 yield XMLSchemaValidationError(self, obj, reason, source, namespaces) 1006 else: 1007 for elem in elementpath.select(source.root, path, namespaces=namespaces): 1008 for obj in xsd_element.iter_decode( 1009 elem, validation, converter, source=source, namespaces=namespaces, 1010 use_defaults=use_defaults, decimal_type=decimal_type, 1011 datetime_types=datetime_types, id_map=id_map, **kwargs): 1012 yield obj 1013 1014 for k, v in id_map.items(): 1015 if v != 1: 1016 self.parse_error("Duplicated xsd:ID value {!r}".format(k), self.root)
1017
1018 - def iter_encode(self, obj, path=None, validation='lax', namespaces=None, converter=None, **kwargs):
1019 """ 1020 Creates an iterator for encoding a data structure to an ElementTree's Element. 1021 1022 :param obj: the data that has to be encoded. 1023 :param path: is an optional XPath expression for selecting the element of the schema \ 1024 that matches the data that has to be encoded. For default the first global element of \ 1025 the schema is used. 1026 :param validation: the XSD validation mode. Can be 'strict', 'lax' or 'skip'. 1027 :param namespaces: is an optional mapping from namespace prefix to URI. 1028 :param converter: an :class:`XMLSchemaConverter` subclass or instance to use for the encoding. 1029 :param kwargs: Keyword arguments containing options for converter and encoding. 1030 :return: Yields an Element instance, eventually preceded by a sequence of validation \ 1031 or encoding errors. 1032 """ 1033 if not self.built: 1034 raise XMLSchemaNotBuiltError(self, "schema %r is not built." % self) 1035 elif not self.elements: 1036 yield XMLSchemaValueError("encoding needs at least one XSD element declaration!") 1037 1038 namespaces = {} if namespaces is None else namespaces.copy() 1039 converter = self.get_converter(converter, namespaces, **kwargs) 1040 1041 if path is not None: 1042 xsd_element = self.find(path, namespaces=namespaces) 1043 elif isinstance(obj, dict) and len(obj) == 1: 1044 xsd_element = self.elements.get(list(obj.keys())[0]) 1045 elif len(self.elements) == 1: 1046 xsd_element = list(self.elements.values())[0] 1047 else: 1048 root_elements = self.root_elements 1049 xsd_element = root_elements[0] if len(root_elements) == 1 else None 1050 1051 if not isinstance(xsd_element, XsdElement): 1052 if path is not None: 1053 msg = "the path %r doesn't match any element of the schema!" % path 1054 else: 1055 msg = "unable to select an element for decoding data, provide a valid 'path' argument." 1056 yield XMLSchemaEncodeError(self, obj, self.elements, reason=msg) 1057 else: 1058 for result in xsd_element.iter_encode(obj, validation, converter, **kwargs): 1059 yield result
1060
1061 1062 -class XMLSchema10(XMLSchemaBase):
1063 """ 1064 XSD 1.0 schema class. 1065 1066 <schema 1067 attributeFormDefault = (qualified | unqualified) : unqualified 1068 blockDefault = (#all | List of (extension | restriction | substitution)) : '' 1069 elementFormDefault = (qualified | unqualified) : unqualified 1070 finalDefault = (#all | List of (extension | restriction | list | union)) : '' 1071 id = ID 1072 targetNamespace = anyURI 1073 version = token 1074 xml:lang = language 1075 {any attributes with non-schema namespace . . .}> 1076 Content: ((include | import | redefine | annotation)*, (((simpleType | complexType | group | 1077 attributeGroup) | element | attribute | notation), annotation*)*) 1078 </schema> 1079 """ 1080 XSD_VERSION = '1.0' 1081 BUILDERS = { 1082 'notation_class': XsdNotation, 1083 'complex_type_class': XsdComplexType, 1084 'attribute_class': XsdAttribute, 1085 'any_attribute_class': XsdAnyAttribute, 1086 'attribute_group_class': XsdAttributeGroup, 1087 'group_class': XsdGroup, 1088 'element_class': XsdElement, 1089 'any_element_class': XsdAnyElement, 1090 'restriction_class': XsdAtomicRestriction, 1091 'union_class': XsdUnion, 1092 'simple_type_factory': xsd_simple_type_factory 1093 } 1094 meta_schema = os.path.join(SCHEMAS_DIR, 'XSD_1.0/XMLSchema.xsd') 1095 BASE_SCHEMAS = { 1096 XML_NAMESPACE: XML_SCHEMA_FILE, 1097 # HFP_NAMESPACE: HFP_SCHEMA_FILE, 1098 XSI_NAMESPACE: XSI_SCHEMA_FILE, 1099 XLINK_NAMESPACE: XLINK_SCHEMA_FILE, 1100 }
1101
1102 1103 # ++++ UNDER DEVELOPMENT, DO NOT USE!!! ++++ 1104 -class XMLSchema11(XMLSchemaBase):
1105 """ 1106 XSD 1.1 schema class. 1107 1108 <schema 1109 attributeFormDefault = (qualified | unqualified) : unqualified 1110 blockDefault = (#all | List of (extension | restriction | substitution)) : '' 1111 defaultAttributes = QName 1112 xpathDefaultNamespace = (anyURI | (##defaultNamespace | ##targetNamespace | ##local)) : ##local 1113 elementFormDefault = (qualified | unqualified) : unqualified 1114 finalDefault = (#all | List of (extension | restriction | list | union)) : '' 1115 id = ID 1116 targetNamespace = anyURI 1117 version = token 1118 xml:lang = language 1119 {any attributes with non-schema namespace . . .}> 1120 Content: ((include | import | redefine | override | annotation)*, (defaultOpenContent, annotation*)?, 1121 ((simpleType | complexType | group | attributeGroup | element | attribute | notation), annotation*)*) 1122 </schema> 1123 1124 <schema 1125 attributeFormDefault = (qualified | unqualified) : unqualified 1126 blockDefault = (#all | List of (extension | restriction | substitution)) : '' 1127 elementFormDefault = (qualified | unqualified) : unqualified 1128 finalDefault = (#all | List of (extension | restriction | list | union)) : '' 1129 id = ID 1130 targetNamespace = anyURI 1131 version = token 1132 xml:lang = language 1133 {any attributes with non-schema namespace . . .}> 1134 Content: ((include | import | redefine | annotation)*, (((simpleType | complexType | group | 1135 attributeGroup) | element | attribute | notation), annotation*)*) 1136 </schema> 1137 """ 1138 XSD_VERSION = '1.1' 1139 BUILDERS = { 1140 'notation_class': XsdNotation, 1141 'complex_type_class': Xsd11ComplexType, 1142 'attribute_class': Xsd11Attribute, 1143 'any_attribute_class': Xsd11AnyAttribute, 1144 'attribute_group_class': XsdAttributeGroup, 1145 'group_class': Xsd11Group, 1146 'element_class': Xsd11Element, 1147 'any_element_class': Xsd11AnyElement, 1148 'restriction_class': Xsd11AtomicRestriction, 1149 'union_class': Xsd11Union, 1150 'simple_type_factory': xsd_simple_type_factory 1151 } 1152 meta_schema = os.path.join(SCHEMAS_DIR, 'XSD_1.1/XMLSchema.xsd') 1153 BASE_SCHEMAS = { 1154 XSD_NAMESPACE: os.path.join(SCHEMAS_DIR, 'XSD_1.1/list_builtins.xsd'), 1155 XML_NAMESPACE: XML_SCHEMA_FILE, 1156 # HFP_NAMESPACE: HFP_SCHEMA_FILE, 1157 XSI_NAMESPACE: XSI_SCHEMA_FILE, 1158 XLINK_NAMESPACE: XLINK_SCHEMA_FILE, 1159 } 1160
1161 - def _include_schemas(self):
1162 super(XMLSchema11, self)._include_schemas() 1163 for child in iterchildren_xsd_override(self.root): 1164 try: 1165 self.include_schema(child.attrib['schemaLocation'], self.base_url) 1166 except KeyError: 1167 pass # Attribute missing error already found by validation against meta-schema 1168 except (OSError, IOError) as err: 1169 # If the override doesn't contain components (annotation excluded) the statement 1170 # is equivalent to an include, so no error is generated. Otherwise fails. 1171 self.warnings.append("Override schema failed: %s." % str(err)) 1172 warnings.warn(self.warnings[-1], XMLSchemaIncludeWarning, stacklevel=3) 1173 if has_xsd_components(child): 1174 self.parse_error(str(err), child)
1175 1176 1177 XMLSchema = XMLSchema10 1178 """The default class for schema instances.""" 1179