1# -*- coding: utf-8 -*- 2# Copyright 2009-2013, Peter A. Bigot 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); you may 5# not use this file except in compliance with the License. You may obtain a 6# copy of the License at: 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13# License for the specific language governing permissions and limitations 14# under the License. 15 16"""Classes corresponding to W3C XML Schema components. 17 18Class names and behavior should conform to the schema components described in 19U{XML Schema Part 1: Structures<http://www.w3.org/TR/xmlschema-1/>}. 20References to sections in the documentation of this module generally refers to 21that document. 22 23Each class has a C{CreateFromDOM} class method that creates an instance and 24initializes it from a DOM node. Only the L{Wildcard}, L{Particle}, and 25L{ModelGroup} components are created from non-DOM sources. However, the 26requirements on DOM interface are restricted to attributes, child nodes, and 27basic fields, though all these must support namespaces. 28 29@group Mixins: *_mixin 30@group Ur Type Specializations: *UrType* 31@group Utilities: _ImportElementInformationItem 32 33""" 34 35import re 36import logging 37from xml.dom import Node 38import copy 39from pyxb.utils.six.moves.urllib import parse as urlparse 40import os.path 41 42import pyxb 43import pyxb.xmlschema 44import pyxb.namespace.archive 45import pyxb.namespace.resolution 46 47from pyxb.binding import basis, datatypes, facets 48from pyxb.utils import domutils, six 49import pyxb.utils.utility 50 51_log = logging.getLogger(__name__) 52 53# Flag indicating that the built in types have been registered 54_PastAddBuiltInTypes = False 55 56# Make it easier to check node names in the XMLSchema namespace 57from pyxb.namespace import XMLSchema as xsd 58 59class _SchemaComponent_mixin (pyxb.namespace._ComponentDependency_mixin, 60 pyxb.namespace.archive._ArchivableObject_mixin, 61 pyxb.utils.utility.PrivateTransient_mixin, 62 pyxb.utils.utility.Locatable_mixin): 63 """A mix-in that marks the class as representing a schema component. 64 65 This exists so that we can determine the owning schema for any 66 component we encounter. This is normally done at construction 67 time by passing a C{schema=val} parameter to the constructor. 68 """ 69 70 # This class suppports transient instance variables. These variables are 71 # added to the set of transients at the point of declaration in the class. 72 __PrivateTransient = set() 73 74 def _namespaceContext (self): 75 """The namespace context for this schema. 76 77 This defines where it looks things up, where it puts things it 78 creates, the in-scope namespace declarations, etc. Must be defined 79 for anything that does any sort of QName interpretation. The value is 80 generally a reference to a namespace context associated with the DOM 81 element node corresponding to this component.""" 82 if self.__namespaceContext is None: 83 raise pyxb.LogicError('Attempt to access missing namespace context for %s' % (self,)) 84 return self.__namespaceContext 85 def _clearNamespaceContext (self): 86 # Calculate the binding sort key for any archive before we discard the 87 # namespace context, which we might need. 88 self.schemaOrderSortKey() 89 self.__namespaceContext = None 90 return self 91 __namespaceContext = None 92 __PrivateTransient.add('namespaceContext') 93 94 # The name by which this component is known within the binding module. 95 # This is in component rather than _NamedComponent_mixin because some 96 # unnamed components (like ModelGroup and Wildcard) have Python objects to 97 # represent them, so need a binding-level name. 98 __nameInBinding = None 99 100 # The public unique name by which this component is referenced within the 101 # binding class (as opposed to the binding module). 102 __uniqueNameInBinding = None 103 104 # The schema component that owns this. If C{None}, the component is owned 105 # directly by the schema. 106 __owner = None 107 __PrivateTransient.add('owner') 108 109 # The schema components owned by this component. 110 __ownedComponents = None 111 __PrivateTransient.add('ownedComponent') 112 113 def _scope (self): 114 """The context into which declarations in or subordinate to this node are placed.""" 115 return self.__scope 116 __scope = None 117 118 def _scopeIsIndeterminate (self): 119 """Return True iff nobody has defined a scope for this node.""" 120 return _ScopedDeclaration_mixin.ScopeIsIndeterminate(self._scope()) 121 122 def _scopeIsGlobal (self): 123 """Return True iff this component has global scope.""" 124 return _ScopedDeclaration_mixin.ScopeIsGlobal(self._scope()) 125 126 def _setScope (self, ctd): 127 """Set the scope of this instance after construction. 128 129 This should only be invoked on cloned declarations being incorporated 130 into a complex type definition. Note that the source of the clone may 131 be any scope: indeterminate if from a model (attribute) group 132 definition; global if a reference to a global component; or ctd if 133 inherited from a complex base type.""" 134 assert self.__cloneSource is not None 135 assert isinstance(self, _ScopedDeclaration_mixin) 136 assert isinstance(ctd, ComplexTypeDefinition) 137 self.__scope = ctd 138 return self 139 140 def __init__ (self, *args, **kw): 141 """Initialize portions of a component. 142 143 @keyword scope: The scope in which the component is defined 144 145 @keyword namespace_context: The NamespaceContext to use within this component 146 147 @keyword node: If no C{namespace_context} is provided, a DOM node must 148 be provided from which a namespace context can be identified. 149 150 @keyword owner: Reference to the component that owns this one (the 151 immediately enclosing component). Is C{None} in the case of top-level 152 components. 153 154 @keyword schema: Reference to the L{Schema} component to which the 155 component belongs. Required for every component except L{Schema}, 156 L{Annotation}, and L{Wildcard}. 157 """ 158 159 self.__ownedComponents = set() 160 self.__scope = kw.get('scope') 161 self.__namespaceContext = kw.get('namespace_context') 162 node = kw.get('node') 163 owner = kw.get('owner') 164 if self.__namespaceContext is None: 165 if node is None: 166 raise pyxb.LogicError('Schema component constructor must be given namespace_context or node') 167 self.__namespaceContext = pyxb.namespace.NamespaceContext.GetNodeContext(node) 168 if self.__namespaceContext is None: 169 raise pyxb.LogicError('No namespace_context for schema component') 170 171 super(_SchemaComponent_mixin, self).__init__(*args, **kw) 172 173 self._namespaceContext().targetNamespace()._associateComponent(self) 174 175 self._setOwner(owner) 176 if isinstance(node, pyxb.utils.utility.Locatable_mixin): 177 self._setLocation(node._location()) 178 elif isinstance(owner, pyxb.utils.utility.Locatable_mixin): 179 self._setLocation(owner._location()) 180 181 schema = kw.get('schema') 182 if schema is not None: 183 self._setObjectOrigin(schema.originRecord()) 184 else: 185 assert isinstance(self, (Schema, Annotation, Wildcard)), 'No origin available for type %s' % (type(self),) 186 187 if isinstance(self, ComplexTypeDefinition): 188 assert 1 < len(self.__namespaceContext.inScopeNamespaces()) 189 190 def _dissociateFromNamespace (self): 191 """Dissociate this component from its owning namespace. 192 193 This should only be done whwen there are no other references to the 194 component, and you want to ensure it does not appear in the model.""" 195 self._namespaceContext().targetNamespace()._replaceComponent(self, None) 196 return self 197 198 def _setOwner (self, owner): 199 """Set the owner of this component. 200 201 If C{owner} is C{None}, this has no effect. Otherwise, the 202 component's current owner must be either C{None} or the same as the 203 input C{owner}.""" 204 205 if owner is not None: 206 assert (self.__owner is None) or (self.__owner == owner), 'Owner was %s set to %s' % (self.__owner, owner) 207 self.__owner = owner 208 owner.__ownedComponents.add(self) 209 return self 210 211 def owner (self): 212 return self.__owner 213 214 # A reference to the instance from which this instance was cloned. 215 __cloneSource = None 216 __PrivateTransient.add('cloneSource') 217 218 def _cloneSource (self): 219 """The source component from which this is a clone. 220 221 Returns C{None} if this is not a clone.""" 222 return self.__cloneSource 223 224 # A set of references to all instances that are clones of this one. 225 __clones = None 226 __PrivateTransient.add('clones') 227 228 def _clones (self): 229 """The set of instances cloned from this component. 230 231 Returns None if no instances have been cloned from this.""" 232 return self.__clones 233 234 def _resetClone_csc (self, **kw): 235 """Virtual method to clear whatever attributes should be reset in a 236 cloned component. 237 238 This instance should be an instance created by copy.copy(). 239 240 The implementation in this class clears the owner and dependency 241 relations. 242 243 Returns C{self}. 244 """ 245 assert self.__cloneSource is not None 246 owner = kw['owner'] 247 self.__nameInBinding = None 248 self.__uniqueNameInBinding = None 249 self.__owner = owner 250 assert not (isinstance(self, ComplexTypeDefinition) and isinstance(owner, Schema)) 251 self.__ownedComponents = set() 252 self.__clones = None 253 owner._namespaceContext().targetNamespace()._associateComponent(self) 254 if self.__namespaceContext is None: 255 # When cloning imported components, loan them the owner's 256 # namespace context, only so that their cloned children can be 257 # associated with the same namespace. 258 self.__namespaceContext = owner._namespaceContext() 259 self_fn = lambda *_args, **_kw: self 260 return getattr(super(_SchemaComponent_mixin, self), '_resetClone_csc', self_fn)(**kw) 261 262 def _clone (self, owner, origin): 263 """Create a copy of this instance suitable for adoption by some other 264 component. 265 266 This is used for creating a locally-scoped declaration from a 267 declaration in a named model or attribute group.""" 268 269 # We only care about cloning declarations, and they should 270 # have an unassigned scope. However, we do clone 271 # non-declarations that contain cloned declarations. 272 #assert (not isinstance(self, _ScopedDeclaration_mixin)) or self._scopeIsIndeterminate() 273 if isinstance(self, pyxb.namespace.resolution._Resolvable_mixin): 274 assert self.isResolved() 275 276 assert owner is not None 277 that = copy.copy(self) 278 that.__cloneSource = self 279 if self.__clones is None: 280 self.__clones = set() 281 self.__clones.add(that) 282 that._resetClone_csc(owner=owner, origin=origin) 283 if isinstance(that, pyxb.namespace.resolution._Resolvable_mixin): 284 assert that.isResolved() 285 return that 286 287 def isTypeDefinition (self): 288 """Return True iff this component is a simple or complex type 289 definition.""" 290 return isinstance(self, (SimpleTypeDefinition, ComplexTypeDefinition)) 291 292 def isUrTypeDefinition (self): 293 """Return True iff this component is a simple or complex type 294 definition.""" 295 return isinstance(self, (_SimpleUrTypeDefinition, _UrTypeDefinition)) 296 297 def bestNCName (self): 298 """Return the name of this component, as best it can be determined. 299 300 For example, ModelGroup instances will be named by their 301 ModelGroupDefinition, if available. Returns None if no name can be 302 inferred.""" 303 if isinstance(self, _NamedComponent_mixin): 304 return self.name() 305 if isinstance(self, ModelGroup): 306 agd = self.modelGroupDefinition() 307 if agd is not None: 308 return agd.name() 309 return None 310 311 def nameInBinding (self): 312 """Return the name by which this component is known in the binding module. 313 314 @note: To support builtin datatypes, type definitions with an 315 associated L{pythonSupport<SimpleTypeDefinition.pythonSupport>} class 316 initialize their binding name from the class name when the support 317 association is created. As long as no built-in datatype conflicts 318 with a language keyword, this should be fine.""" 319 return self.__nameInBinding 320 321 def uniqueNameInBinding (self): 322 """Return the name by which this component is known in the binding class.""" 323 return self.__uniqueNameInBinding 324 325 def hasBinding (self): 326 """Return C{True} iff this is a component which has a user-visible 327 Python construct which serves as its binding. 328 329 Type definitions have classes as their bindings. Global element 330 declarations have instances of L{pyxb.binding.basis.element} as their 331 bindings.""" 332 return self.isTypeDefinition() or (isinstance(self, ElementDeclaration) and self._scopeIsGlobal()) 333 334 def setNameInBinding (self, name_in_binding): 335 """Set the name by which this component shall be known in the binding module.""" 336 self.__nameInBinding = name_in_binding 337 return self 338 339 def setUniqueNameInBinding (self, unique_name): 340 """Set the name by which this component shall be known in the binding class.""" 341 self.__uniqueNameInBinding = unique_name 342 return self 343 344 def _updateFromOther_csc (self, other): 345 """Override fields in this instance with those from the other. 346 347 Post-extended; description in leaf implementation in 348 ComplexTypeDefinition and SimpleTypeDefinition.""" 349 assert self != other 350 self_fn = lambda *_args, **_kw: self 351 getattr(super(_SchemaComponent_mixin, self), '_updateFromOther_csc', self_fn)(other) 352 # The only thing we update is the binding name, and that only if it's new. 353 if self.__nameInBinding is None: 354 self.__nameInBinding = other.__nameInBinding 355 return self 356 357 def schemaOrderSortKey (self): 358 """A key to be used when sorting components for binding generation. 359 360 This is a tuple comprising the namespace URI, schema location, and 361 line and column of the component definition within the schema. The 362 purpose is to ensure consistent order of binding components in 363 generated code, to simplify maintenance involving the generated 364 sources. 365 366 To support Python 3 values that are C{None} are replaced with the 367 default value for whatever type belongs in the corresponding 368 position: (uri:str, locbase:str, locline:int, loccol:int) """ 369 if self.__schemaOrderSortKey is None: 370 ns = None 371 if isinstance(self, _NamedComponent_mixin): 372 ns = self.bindingNamespace() 373 if ns is None: 374 ns = self._namespaceContext().targetNamespace() 375 elif isinstance(self, _ParticleTree_mixin): 376 ns = self._namespaceContext().targetNamespace() 377 ns_uri = '' 378 if (ns is not None) and (ns.uri() is not None): 379 ns_uri = ns.uri() 380 key_elts = [ns_uri] 381 loc = self._location() 382 v = '' 383 if (loc is not None) and (loc.locationBase is not None): 384 v = loc.locationBase 385 key_elts.append(v) 386 v = 0 387 if (loc is not None) and (loc.lineNumber is not None): 388 v = loc.lineNumber 389 key_elts.append(v) 390 v = 0 391 if (loc is not None) and (loc.columnNumber is not None): 392 v = loc.columnNumber 393 key_elts.append(v) 394 self.__schemaOrderSortKey = tuple(key_elts) 395 return self.__schemaOrderSortKey 396 __schemaOrderSortKey = None 397 398 def facStateSortKey (self): 399 """A sort key matching preferred content order. 400 401 This is an ordinal (integer) used to control which candidate 402 transitions are attempted first when testing symbols against the 403 content automaton state. 404 405 @note: The value associated with a node (especially a L{ModelGroup} or 406 L{Particle} will be different for different complex types, and is 407 valid only during generation of the automata code for a given type.""" 408 assert self.__facStateSortKey is not None 409 return self.__facStateSortKey 410 411 def _setFacStateSortKey (self, key): 412 """Set the automata state sort key. 413 414 @param key: the ordinal used for sorting.""" 415 self.__facStateSortKey = key 416 __facStateSortKey = None 417 __PrivateTransient.add('facStateSortKey') 418 419class _ParticleTree_mixin (pyxb.cscRoot): 420 def _walkParticleTree (self, visit, arg): 421 """Mix-in supporting walks of L{Particle} trees. 422 423 This invokes a provided function on each node in a tree defining the 424 content model of a particle, both on the way down the tree and on the 425 way back up. A standard implementation would be:: 426 427 def _walkParticleTree (self, visit, arg): 428 visit(self, True, arg) 429 self.__term.walkParticleTree(visit, arg) 430 visit(self, False, arg) 431 432 @param visit: A callable with parameters C{node, entering, arg} where 433 C{node} is an instance of a class inheriting L{_ParticleTree_mixin}, 434 C{entering} indicates tree transition status, and C{arg} is a 435 caller-provided state parameter. C{entering} is C{True} if C{node} 436 has particle children and the call is before they are visited; 437 C{None} if the C{node} has no particle children; and C{False} if 438 C{node} has particle children and they have been visited. 439 440 @param arg: The caller-provided state parameter to be passed along 441 with the node and entry/exit status in the invocation of C{visit}. 442 """ 443 raise NotImplementedError('%s._walkParticleTree' % (self.__class__.__name__,)) 444 445class _Singleton_mixin (pyxb.cscRoot): 446 """This class is a mix-in which guarantees that only one instance 447 of the class will be created. It is used to ensure that the 448 ur-type instances are pointer-equivalent even when unpickling. 449 See ComplexTypeDefinition.UrTypeDefinition().""" 450 def __new__ (cls, *args, **kw): 451 singleton_property = '_%s__singleton' % (cls.__name__,) 452 if not (singleton_property in cls.__dict__): 453 setattr(cls, singleton_property, super(_Singleton_mixin, cls).__new__(cls, *args, **kw)) 454 return cls.__dict__[singleton_property] 455 456class _Annotated_mixin (pyxb.cscRoot): 457 """Mix-in that supports an optional single annotation that describes the component. 458 459 Most schema components have annotations. The ones that don't are 460 L{AttributeUse}, L{Particle}, and L{Annotation}. L{ComplexTypeDefinition} 461 and L{Schema} support multiple annotations, so do not mix-in this 462 class.""" 463 464 # Optional Annotation instance 465 __annotation = None 466 467 def __init__ (self, *args, **kw): 468 super(_Annotated_mixin, self).__init__(*args, **kw) 469 self.__annotation = kw.get('annotation') 470 471 def _annotationFromDOM (self, node): 472 cn = domutils.LocateUniqueChild(node, 'annotation') 473 if cn is not None: 474 kw = { } 475 if isinstance(self, _SchemaComponent_mixin): 476 kw['owner'] = self 477 self.__annotation = Annotation.CreateFromDOM(cn, **kw) 478 479 def _updateFromOther_csc (self, other): 480 """Override fields in this instance with those from the other. 481 482 Post-extended; description in leaf implementation in 483 ComplexTypeDefinition and SimpleTypeDefinition.""" 484 assert self != other 485 self_fn = lambda *_args, **_kw: self 486 getattr(super(_Annotated_mixin, self), '_updateFromOther_csc', self_fn)(other) 487 # @todo: make this a copy? 488 self.__annotation = other.__annotation 489 return self 490 491 def annotation (self): 492 return self.__annotation 493 494class _PickledAnonymousReference (object): 495 """A helper that encapsulates a reference to an anonymous type in a different namespace. 496 497 Normally references to components in other namespaces can be made using 498 the component's name. This is not the case when a namespace derives from 499 a base type in another namespace and needs to reference the attribute or 500 element declarations held in that type. If these declarations are local 501 to the base complex type, they cannot be identified by name. This class 502 provides a pickleable representation for them that behaves rather like an 503 L{pyxb.namespace.ExpandedName} instance in that it can be used to 504 dereference various component types.""" 505 506 __AnonymousCategory = pyxb.namespace.archive.NamespaceArchive._AnonymousCategory() 507 508 __namespace = None 509 __anonymousName = None 510 def __init__ (self, namespace, anonymous_name): 511 """Create a new anonymous reference. 512 513 @param namespace: The namespace in which the component is declared. 514 @type namespace: L{pyxb.namespace.Namespace} 515 @param anonymous_name: A generated name guaranteed to be unique within 516 the namespace. See L{_NamedComponent_mixin._anonymousName}. 517 @type anonymous_name: C{basestring}. 518 """ 519 self.__namespace = namespace 520 self.__anonymousName = anonymous_name 521 assert self.__anonymousName is not None 522 523 @classmethod 524 def FromPickled (cls, object_reference): 525 """Return the component referred to by the provided reference, 526 regardless of whether it is a normal or anonymous reference.""" 527 if not isinstance(object_reference, _PickledAnonymousReference): 528 assert isinstance(object_reference, tuple) 529 object_reference = pyxb.namespace.ExpandedName(object_reference) 530 return object_reference 531 532 def namespace (self): 533 return self.__namespace 534 535 def anonymousName (self): 536 return self.__anonymousName 537 538 def validateComponentModel (self): 539 """Forward to the associated namespace.""" 540 return self.__namespace.validateComponentModel() 541 542 def __lookupObject (self): 543 return self.__namespace.categoryMap(self.__AnonymousCategory).get(self.__anonymousName) 544 545 typeDefinition = __lookupObject 546 attributeGroupDefinition = __lookupObject 547 modelGroupDefinition = __lookupObject 548 attributeDeclaration = __lookupObject 549 elementDeclaration = __lookupObject 550 identityConstraintDefinition = __lookupObject 551 notationDeclaration = __lookupObject 552 553 def __str__ (self): 554 """Represent the anonymous reference in a form recognizable by a developer.""" 555 return 'ANONYMOUS:%s' % (pyxb.namespace.ExpandedName(self.__namespace, self.__anonymousName),) 556 557class _NamedComponent_mixin (pyxb.utils.utility.PrivateTransient_mixin, pyxb.cscRoot): 558 """Mix-in to hold the name and targetNamespace of a component. 559 560 The name may be None, indicating an anonymous component. The 561 targetNamespace is never None, though it could be an empty namespace. The 562 name and targetNamespace values are immutable after creation. 563 564 This class overrides the pickling behavior: when pickling a Namespace, 565 objects that do not belong to that namespace are pickled as references, 566 not as values. This ensures the uniqueness of objects when multiple 567 namespace definitions are pre-loaded. 568 569 This class must follow L{_SchemaComponent_mixin} in the MRO. 570 """ 571 572 __PrivateTransient = set() 573 574 def name (self): 575 """Name of the component within its scope or namespace. 576 577 This is an NCName. The value isNone if the component is 578 anonymous. The attribute is immutable after the component is 579 created creation.""" 580 return self.__name 581 __name = None 582 583 def isAnonymous (self): 584 """Return true iff this instance is locally scoped (has no name).""" 585 return self.__name is None 586 587 def _setAnonymousName (self, namespace, unique_id=None, anon_name=None): 588 # If this already has a name, keep using it. 589 if self.__anonymousName is not None: 590 return 591 assert self.__needAnonymousSupport() 592 assert namespace is not None 593 if self.bindingNamespace() is not None: 594 assert self.bindingNamespace() == namespace 595 if self.targetNamespace() is not None: 596 assert self.targetNamespace() == namespace 597 if anon_name is None: 598 anon_name = self.nameInBinding() 599 if anon_name is None: 600 anon_name = self.name() 601 if anon_name is None: 602 anon_name = 'ANON_IN_GROUP' 603 if unique_id is not None: 604 anon_name = '%s_%s' % (anon_name, unique_id) 605 anon_name = pyxb.utils.utility.MakeUnique(anon_name, set(six.iterkeys(namespace.categoryMap(self.__AnonymousCategory)))) 606 self.__anonymousName = anon_name 607 namespace.addCategoryObject(self.__AnonymousCategory, anon_name, self) 608 def _anonymousName (self, namespace=None): 609 assert self.__anonymousName is not None, '%x %s %s in %s missing anonymous name' % (id(self), type(self), self.name(), self.targetNamespace()) 610 return self.__anonymousName 611 __anonymousName = None 612 613 def targetNamespace (self): 614 """The targetNamespace of a component. 615 616 This is None, or a reference to a Namespace in which the 617 component is declared (either as a global or local to one of 618 the namespace's complex type definitions). This is immutable 619 after creation. 620 """ 621 return self.__targetNamespace 622 __targetNamespace = None 623 624 def bindingNamespace (self): 625 """The namespace in which this component's binding is placed.""" 626 return self.__bindingNamespace 627 def _setBindingNamespace (self, namespace): 628 self.__bindingNamespace = namespace 629 __bindingNamespace = None 630 631 def _templateMap (self): 632 """A map from template keys to component-specific values. 633 634 This is used in code generation to maintain unique names for accessor 635 methods, identifiers, keys, and other characteristics associated with 636 the code generated in support of the binding for this component.""" 637 return self.__templateMap 638 __templateMap = None 639 640 __AnonymousCategory = pyxb.namespace.archive.NamespaceArchive._AnonymousCategory() 641 642 def __needAnonymousSupport (self): 643 # If this component doesn't have a name, or if it's in some scope in 644 # which it cannot be located in a category map, we'll need a unique 645 # name for it. 646 return self.isAnonymous() or (self._scopeIsIndeterminate() and not isinstance(self, (AttributeGroupDefinition, ModelGroupDefinition))) 647 648 def _schema (self): 649 """Return the schema component from which this component was defined. 650 651 Needed so we can distinguish components that came from different 652 locations, since that imposes an external order dependency on them and 653 on cross-namespace inclusions. 654 655 @note: This characteristic is removed when the component is stored in 656 a namespace archive.""" 657 return self.__schema 658 __schema = None 659 __PrivateTransient.add('schema') 660 661 def _prepareForArchive_csc (self, module_record): 662 if self.__needAnonymousSupport(): 663 self._setAnonymousName(module_record.namespace(), unique_id=module_record.generationUID()) 664 self_fn = lambda *_args, **_kw: self 665 return getattr(super(_NamedComponent_mixin, self), '_prepareForArchive_csc', self_fn)(module_record) 666 667 def _picklesInArchive (self, archive): 668 """Return C{True} if this component should be pickled by value in the 669 given namespace. 670 671 When pickling, a declaration component is considered to belong to the 672 namespace if it has a local scope which belongs to the namespace. In 673 that case, the declaration is a clone of something that does not 674 belong to the namespace; but the clone does. 675 676 @see: L{_bindsInNamespace} 677 678 @return: C{False} if the component should be pickled by reference. 679 """ 680 if isinstance(self._scope(), ComplexTypeDefinition): 681 return self._scope()._picklesInArchive(archive) 682 assert not (self.targetNamespace() is None), '%s has no tns, scope %s, location %s, schema %s' % (self, self._scope(), self._location(), self._schema().targetNamespace()) 683 assert not (self._objectOrigin() is None) 684 new_flag = (self._objectOrigin().generationUID() == archive.generationUID()) 685 return new_flag 686 687 def _bindsInNamespace (self, ns): 688 """Return C{True} if the binding for this component should be 689 generated in the given namespace. 690 691 This is the case when the component is in the given namespace. It's 692 also the case when the component has no associated namespace (but not 693 an absent namespace). Be aware that cross-namespace inheritance means 694 you will get references to elements in another namespace when 695 generating code for a subclass; that's fine, and those references 696 should not be generated locally. 697 """ 698 return self.targetNamespace() in (ns, None) 699 700 def expandedName (self): 701 """Return the L{pyxb.namespace.ExpandedName} of this object.""" 702 if self.name() is None: 703 return None 704 return pyxb.namespace.ExpandedName(self.targetNamespace(), self.name()) 705 706 def __new__ (cls, *args, **kw): 707 """Pickling support. 708 709 Normally, we just create a new instance of this class. 710 However, if we're unpickling a reference in a loadable schema, 711 we need to return the existing component instance by looking 712 up the name in the component map of the desired namespace. We 713 can tell the difference because no normal constructors that 714 inherit from this have positional arguments; only invocations 715 by unpickling with a value returned in __getnewargs__ do. 716 717 This does require that the dependent namespace already have 718 been validated (or that it be validated here). That shouldn't 719 be a problem, except for the dependency loop resulting from 720 use of xml:lang in the XMLSchema namespace. For that issue, 721 see pyxb.namespace._XMLSchema. 722 """ 723 724 if 0 == len(args): 725 rv = super(_NamedComponent_mixin, cls).__new__(cls) 726 return rv 727 ( object_reference, scope, icls ) = args 728 729 object_reference = _PickledAnonymousReference.FromPickled(object_reference) 730 731 # Explicitly validate here: the lookup operations won't do so, 732 # but will abort if the namespace hasn't been validated yet. 733 object_reference.validateComponentModel() 734 rv = None 735 if isinstance(scope, (tuple, _PickledAnonymousReference)): 736 # Scope is the expanded name of the complex type in which the 737 # named value can be located. 738 scope_ref = _PickledAnonymousReference.FromPickled(scope) 739 if object_reference.namespace() != scope_ref.namespace(): 740 scope_ref.validateComponentModel() 741 assert 'typeDefinition' in scope_ref.namespace().categories() 742 scope_ctd = scope_ref.typeDefinition() 743 if scope_ctd is None: 744 raise pyxb.SchemaValidationError('Unable to resolve local scope %s' % (scope_ref,)) 745 if issubclass(icls, AttributeDeclaration): 746 rv = scope_ctd.lookupScopedAttributeDeclaration(object_reference) 747 elif issubclass(icls, ElementDeclaration): 748 rv = scope_ctd.lookupScopedElementDeclaration(object_reference) 749 if rv is None: 750 raise pyxb.SchemaValidationError('Unable to resolve %s as %s in scope %s' % (object_reference, icls, scope_ref)) 751 elif _ScopedDeclaration_mixin.ScopeIsGlobal(scope) or _ScopedDeclaration_mixin.ScopeIsIndeterminate(scope): 752 if (issubclass(icls, SimpleTypeDefinition) or issubclass(icls, ComplexTypeDefinition)): 753 rv = object_reference.typeDefinition() 754 elif issubclass(icls, AttributeGroupDefinition): 755 rv = object_reference.attributeGroupDefinition() 756 elif issubclass(icls, ModelGroupDefinition): 757 rv = object_reference.modelGroupDefinition() 758 elif issubclass(icls, AttributeDeclaration): 759 rv = object_reference.attributeDeclaration() 760 elif issubclass(icls, ElementDeclaration): 761 rv = object_reference.elementDeclaration() 762 elif issubclass(icls, IdentityConstraintDefinition): 763 rv = object_reference.identityConstraintDefinition() 764 if rv is None: 765 raise pyxb.SchemaValidationError('Unable to resolve %s as %s' % (object_reference, icls)) 766 if rv is None: 767 raise pyxb.SchemaValidationError('Unable to resolve reference %s, scope %s ns %s type %s, class %s' % (object_reference, scope, (scope is None and "<unknown>" or scope.targetNamespace()), type(scope), icls)) 768 return rv 769 770 def __init__ (self, *args, **kw): 771 assert 0 == len(args) 772 name = kw.get('name') 773 # Must be None or a valid NCName 774 assert (name is None) or (0 > name.find(':')), 'name %s' % (name,) 775 self.__name = name 776 777 # Target namespace is taken from the context, unless somebody 778 # overrides it (as is done for local declarations if the form is 779 # unqualified). 780 self.__targetNamespace = kw.get('target_namespace', self._namespaceContext().targetNamespace()) 781 self.__bindingNamespace = kw.get('binding_namespace') 782 783 self.__templateMap = {} 784 785 self.__schema = kw.get('schema') 786 assert self._schema() is not None 787 788 # Do parent invocations after we've set the name: they might need it. 789 super(_NamedComponent_mixin, self).__init__(*args, **kw) 790 791 def isNameEquivalent (self, other): 792 """Return true iff this and the other component share the same name and target namespace. 793 794 Anonymous components are inherently name inequivalent, except to 795 themselves. This relies on equivalence as defined for 796 pyxb.namespace.ExpandedName, for which None is not equivalent to any 797 non-anonymous name.""" 798 # Note that unpickled objects 799 return (self == other) or ((not self.isAnonymous()) and (self.expandedName() == other.expandedName())) 800 801 def isTypeEquivalent (self, other): 802 """Return True iff this and the other component have matching types. 803 804 It appears that name equivalence is used; two complex type definitions 805 with identical structures are not considered equivalent (at least, per 806 XMLSpy). 807 """ 808 return (type(self) == type(other)) and self.isNameEquivalent(other) 809 810 def isDerivationConsistent (self, other): 811 """Return True iff this type can serve as a restriction of the other 812 type for the purposes of U{element consistency<http://www.w3.org/TR/xmlschema-1/#cos-element-consistent>}. 813 814 It appears that name equivalence is normally used; two complex type 815 definitions with identical structures are not considered equivalent 816 (at least, per XMLSpy). However, some OpenGIS standards demonstrate 817 that derivation by restriction from the other type is also acceptable. 818 That opens a whole can of worms; see 819 L{ElementDeclaration.isAdaptable}. 820 """ 821 this = self 822 # can this succeed if component types are not equivalent? 823 while this is not None: 824 if this.isTypeEquivalent(other): 825 return True 826 # Assumption from ElementDeclaration.isAdaptable 827 assert this.isResolved() and other.isResolved() 828 if isinstance(self, ComplexTypeDefinition): 829 if self.DM_restriction != this.derivationMethod(): 830 return False 831 else: 832 assert isinstance(self, SimpleTypeDefinition) 833 if self._DA_restriction != this._derivationAlternative(): 834 return False 835 if not this.baseTypeDefinition().isDerivationConsistent(other): 836 return False 837 this = this.baseTypeDefinition() 838 return False 839 840 def _picklingReference (self): 841 if self.__needAnonymousSupport(): 842 assert self._anonymousName() is not None 843 return _PickledAnonymousReference(self.targetNamespace(), self._anonymousName()) 844 return self.expandedName().uriTuple() 845 846 def __pickleAsReference (self): 847 if self.targetNamespace() is None: 848 return False 849 # Get the namespace we're pickling. If the namespace is None, 850 # we're not pickling; we're probably cloning, and in that case 851 # we don't want to use the reference state encoding. 852 pickling_archive = pyxb.namespace.archive.NamespaceArchive.PicklingArchive() 853 if pickling_archive is None: 854 return False 855 # If this thing is scoped in a complex type that belongs to the 856 # namespace being pickled, then it gets pickled as an object even if 857 # its target namespace isn't this one. 858 assert self._objectOrigin() is not None 859 if self._picklesInArchive(pickling_archive): 860 return False 861 # Note that anonymous objects must use their fallback 862 return True 863 864 def __getstate__ (self): 865 if self.__pickleAsReference(): 866 # NB: This instance may be a scoped declaration, but in 867 # this case (unlike getnewargs) we don't care about trying 868 # to look up a previous instance, so we don't need to 869 # encode the scope in the reference tuple. 870 return self._picklingReference() 871 if self.targetNamespace() is None: 872 # The only internal named objects that should exist are 873 # ones that have a non-global scope (including those with 874 # absent scope). 875 # @todo: this is wrong for schema that are not bound to a 876 # namespace, unless we use an unbound Namespace instance 877 #assert isinstance(self, _ScopedDeclaration_mixin) 878 #assert self.SCOPE_global != self.scope() 879 # NOTE: The name of the scope may be None. This is not a 880 # problem unless somebody tries to extend or restrict the 881 # scope type, which at the moment I'm thinking is 882 # impossible for anonymous types. If it isn't, we're 883 # gonna need some other sort of ID, like a UUID associated 884 # with the anonymous class at the time it's written to the 885 # preprocessed schema file. 886 pass 887 return super(_NamedComponent_mixin, self).__getstate__() 888 889 def __getnewargs__ (self): 890 """Pickling support. 891 892 If this instance is being pickled as a reference, provide the 893 arguments that are necessary so that the unpickler can locate 894 the appropriate component rather than create a duplicate 895 instance.""" 896 897 if self.__pickleAsReference(): 898 scope = self._scope() 899 if isinstance(self, _ScopedDeclaration_mixin): 900 # If scope is global, we can look it up in the namespace. 901 # If scope is indeterminate, this must be within a group in 902 # another namespace. Why are we serializing it? 903 # If scope is local, provide the namespace and name of 904 # the type that holds it 905 if self.SCOPE_global == self.scope(): 906 pass 907 elif isinstance(self.scope(), ComplexTypeDefinition): 908 scope = self.scope()._picklingReference() 909 assert isinstance(scope, (tuple, _PickledAnonymousReference)), self 910 else: 911 assert self._scopeIsIndeterminate() 912 # This is actually OK: we made sure both the scope and 913 # this instance can be looked up by a unique identifier. 914 else: 915 assert isinstance(self, _NamedComponent_mixin), 'Pickling unnamed component %s in indeterminate scope by reference' % (self,) 916 assert not isinstance(scope, ComplexTypeDefinition), '%s %s %s %s' % (self, self.name(), scope, self._objectOrigin()) 917 918 rv = ( self._picklingReference(), scope, self.__class__ ) 919 return rv 920 return () 921 922 def __setstate__ (self, state): 923 if isinstance(state, tuple): 924 # We don't actually have to set any state here; we just 925 # make sure that we resolved to an already-configured 926 # instance. 927 assert self.targetNamespace() is not None 928 assert self.targetNamespace().uri() == state[0] 929 assert self.name() == state[1] 930 return 931 if isinstance(state, _PickledAnonymousReference): 932 assert self.targetNamespace() is not None 933 assert self.targetNamespace() == state.namespace() 934 assert self.__needAnonymousSupport() 935 assert self._anonymousName() == state.anonymousName() 936 return 937 self.__dict__.update(state) 938 939 def _resetClone_csc (self, **kw): 940 self.__schema = None 941 self_fn = lambda *_args, **_kw: self 942 rv = getattr(super(_NamedComponent_mixin, self), '_resetClone_csc', self_fn)(**kw) 943 self.__templateMap = { } 944 origin = kw.get('origin') 945 self.__anonymousName = None 946 self._setObjectOrigin(origin, override=True) 947 return rv 948 949class _ValueConstraint_mixin (pyxb.cscRoot): 950 """Mix-in indicating that the component contains a simple-type 951 value that may be constrained.""" 952 953 VC_na = 0 #<<< No value constraint applies 954 VC_default = 1 #<<< Provided value constraint is default value 955 VC_fixed = 2 #<<< Provided value constraint is fixed value 956 957 # None, or a tuple containing a string followed by one of the VC_* 958 # values above. 959 __valueConstraint = None 960 def valueConstraint (self): 961 """A constraint on the value of the attribute or element. 962 963 Either None, or a pair consisting of a string in the lexical 964 space of the typeDefinition and one of VC_default and 965 VC_fixed.""" 966 return self.__valueConstraint 967 968 def default (self): 969 """If this instance constraints a default value, return that 970 value; otherwise return None.""" 971 if not isinstance(self.__valueConstraint, tuple): 972 return None 973 if self.VC_default != self.__valueConstraint[1]: 974 return None 975 return self.__valueConstraint[0] 976 977 def fixed (self): 978 """If this instance constraints a fixed value, return that 979 value; otherwise return None.""" 980 if not isinstance(self.__valueConstraint, tuple): 981 return None 982 if self.VC_fixed != self.__valueConstraint[1]: 983 return None 984 return self.__valueConstraint[0] 985 986 def _valueConstraintFromDOM (self, node): 987 adefault = domutils.NodeAttribute(node, 'default') 988 afixed = domutils.NodeAttribute(node, 'fixed') 989 ause = domutils.NodeAttribute(node, 'use') 990 if (adefault is not None) and (afixed is not None): 991 raise pyxb.SchemaValidationError('Attributes default and fixed may not both appear (3.2.3r1)') 992 if adefault is not None: 993 if (ause is not None) and ('optional' != ause): 994 raise pyxb.SchemaValidationError('Attribute use must be optional when default present (3.2.3r2)') 995 self.__valueConstraint = (adefault, self.VC_default) 996 return self 997 if afixed is not None: 998 self.__valueConstraint = (afixed, self.VC_fixed) 999 return self 1000 self.__valueConstraint = None 1001 return self 1002 1003class _ScopedDeclaration_mixin (pyxb.cscRoot): 1004 """Mix-in class for named components that have a scope. 1005 1006 Scope is important when doing cross-namespace inheritance, 1007 e.g. extending or restricting a complex type definition that is 1008 from a different namespace. In this case, we will need to retain 1009 a reference to the external component when the schema is 1010 serialized. 1011 1012 This is done in the pickling process by including the scope when 1013 pickling a component as a reference. The scope is the 1014 SCOPE_global if global; otherwise, it is a tuple containing the 1015 external namespace URI and the NCName of the complex type 1016 definition in that namespace. We assume that the complex type 1017 definition has global scope; otherwise, it should not have been 1018 possible to extend or restrict it. (Should this be untrue, there 1019 are comments in the code about a possible solution.) 1020 1021 @warning: This mix-in must follow L{_NamedComponent_mixin} in the C{mro}. 1022 """ 1023 1024 SCOPE_global = 'global' #<<< Marker to indicate global scope 1025 XSCOPE_indeterminate = 'indeterminate' #<<< Marker to indicate scope has not been assigned 1026 1027 @classmethod 1028 def IsValidScope (cls, value): 1029 return (cls.SCOPE_global == value) or isinstance(value, ComplexTypeDefinition) 1030 1031 @classmethod 1032 def ScopeIsIndeterminate (cls, value): 1033 return (cls.XSCOPE_indeterminate == value) 1034 1035 @classmethod 1036 def ScopeIsGlobal (cls, value): 1037 return (cls.SCOPE_global == value) 1038 1039 def _scopeIsCompatible (self, scope): 1040 """Return True if this scope currently assigned to this instance is compatible with the given scope. 1041 1042 If either scope is indeterminate, presume they will ultimately be 1043 compatible. Scopes that are equal are compatible, as is a local scope 1044 if this already has a global scope.""" 1045 if self.ScopeIsIndeterminate(scope) or self.ScopeIsIndeterminate(self.scope()): 1046 return True 1047 if self.scope() == scope: 1048 return True 1049 return (self.SCOPE_global == self.scope()) and isinstance(scope, ComplexTypeDefinition) 1050 1051 # The scope for the element. Valid values are SCOPE_global or a 1052 # complex type definition. None is an invalid value, but may 1053 # appear if scope is determined by an ancestor component. 1054 def scope (self): 1055 """The scope for the declaration. 1056 1057 Valid values are SCOPE_global, or a complex type definition. 1058 A value of None means a non-global declaration that is not 1059 owned by a complex type definition. These can only appear in 1060 attribute group definitions, model group definitions, and element 1061 declarations. 1062 1063 @todo: For declarations in named model groups (viz., local 1064 elements that aren't references), the scope needs to be set by 1065 the owning complex type. 1066 """ 1067 return self._scope() 1068 1069 # The base declaration is the original _ScopedDeclaration_mixin which 1070 # introduced the element into its scope. This is used to retain a 1071 # particular defining declaration when each extension type gets its own 1072 # clone adapted for its scope. 1073 __baseDeclaration = None 1074 def baseDeclaration (self): 1075 return self.__baseDeclaration or self 1076 def _baseDeclaration (self, referenced_declaration): 1077 self.__baseDeclaration = referenced_declaration.baseDeclaration() 1078 return self.__baseDeclaration 1079 1080 # Indicates that declaration replaces a (compatible) declaration with the 1081 # same name within its scope. Also provide access to the declaration it 1082 # replaces. 1083 __overridesParentScope = False 1084 def overridesParentScope (self): 1085 return self.__overridesParentScope 1086 def _overrideParentScope (self, value): 1087 self.__overriddenDeclaration = value; 1088 self.__overridesParentScope = True 1089 def overriddenDeclaration (self): 1090 return self.__overriddenDeclaration 1091 1092class _AttributeWildcard_mixin (pyxb.cscRoot): 1093 """Support for components that accept attribute wildcards. 1094 1095 That is L{AttributeGroupDefinition} and L{ComplexTypeDefinition}. The 1096 calculations of the appropriate wildcard are sufficiently complex that 1097 they need to be abstracted out to a mix-in class.""" 1098 1099 # Optional wildcard that constrains attributes 1100 __attributeWildcard = None 1101 1102 def attributeWildcard (self): 1103 """Return the L{Wildcard} component associated with attributes of this 1104 instance, or C{None} if attribute wildcards are not present in the 1105 instance.""" 1106 return self.__attributeWildcard 1107 1108 def _setAttributeWildcard (self, attribute_wildcard): 1109 """Set the attribute wildcard property for this instance.""" 1110 assert (attribute_wildcard is None) or isinstance(attribute_wildcard, Wildcard) 1111 self.__attributeWildcard = attribute_wildcard 1112 return self 1113 1114 def _attributeRelevantChildren (self, node_list): 1115 """Return the nodes that are relevant for attribute processing. 1116 1117 @param node_list: A sequence of nodes found in a definition content 1118 information item. 1119 1120 @return: A tuple C{( attributes, attributeGroups, attributeWildcard)} 1121 where C{attributes} is the subsequence of C{node_list} that are 1122 XMLSchema C{attribute} nodes; C{attributeGroups} is analogous; and 1123 C{attributeWildcard} is a single DOM node with XMLSchema name 1124 C{anyAttribute} (or C{None}, if no such node is present in the list). 1125 1126 @raise pyxb.SchemaValidationError: An C{attributeGroup} node is 1127 present but does not have the required C{ref} attribute. 1128 @raise pyxb.SchemaValidationError: Multiple C{anyAttribute} nodes are 1129 identified. 1130 """ 1131 1132 attributes = [] 1133 attribute_groups = [] 1134 any_attribute = None 1135 # Handle clauses 1 and 2 (common between simple and complex types) 1136 for node in node_list: 1137 if Node.ELEMENT_NODE != node.nodeType: 1138 continue 1139 if xsd.nodeIsNamed(node, 'attribute'): 1140 # Note: This attribute use instance may have use=prohibited 1141 attributes.append(node) 1142 elif xsd.nodeIsNamed(node, 'attributeGroup'): 1143 # This must be an attributeGroupRef 1144 agd_en = domutils.NodeAttributeQName(node, 'ref') 1145 if agd_en is None: 1146 raise pyxb.SchemaValidationError('Require ref attribute on internal attributeGroup elements') 1147 attribute_groups.append(agd_en) 1148 elif xsd.nodeIsNamed(node, 'anyAttribute'): 1149 if any_attribute is not None: 1150 raise pyxb.SchemaValidationError('Multiple anyAttribute children are not allowed') 1151 any_attribute = node 1152 1153 return (attributes, attribute_groups, any_attribute) 1154 1155 @classmethod 1156 def CompleteWildcard (cls, namespace_context, attribute_groups, local_wildcard): 1157 """Implement the algorithm as described the 1158 U{specification<http://www.w3.org/TR/xmlschema-1/#declare-type>}. 1159 1160 @param namespace_context: The L{pyxb.namespace.NamespaceContext} to be 1161 associated with any created L{Wildcard} instance 1162 @param attribute_groups: A list of L{AttributeGroupDefinition} instances 1163 @param local_wildcard: A L{Wildcard} instance computed from a relevant 1164 XMLSchema C{anyAttribute} element, or C{None} if no attribute wildcard 1165 is relevant 1166 """ 1167 1168 # Non-absent wildcard properties of attribute groups 1169 agd_wildcards = [] 1170 for agd in attribute_groups: 1171 assert isinstance(agd, AttributeGroupDefinition) 1172 if agd.attributeWildcard() is not None: 1173 agd_wildcards.append(agd.attributeWildcard()) 1174 agd_constraints = [ _agd.namespaceConstraint() for _agd in agd_wildcards ] 1175 1176 # Clause 2.1 1177 if 0 == len(agd_wildcards): 1178 return local_wildcard 1179 1180 if local_wildcard is not None: 1181 # Clause 2.2.1 1182 return Wildcard(process_contents=local_wildcard.processContents(), 1183 namespace_constraint=Wildcard.IntensionalIntersection(agd_constraints + [local_wildcard.namespaecConstraint()]), 1184 annotation=local_wildcard.annotation(), 1185 namespace_context=namespace_context) 1186 # Clause 2.2.2 1187 return Wildcard(process_contents=agd_wildcards[0].processContents(), 1188 namespace_constraint=Wildcard.IntensionalIntersection(agd_constraints), 1189 namespace_context=namespace_context) 1190 1191class AttributeDeclaration (_SchemaComponent_mixin, _NamedComponent_mixin, pyxb.namespace.resolution._Resolvable_mixin, _Annotated_mixin, _ValueConstraint_mixin, _ScopedDeclaration_mixin): 1192 """An XMLSchema U{Attribute Declaration<http://www.w3.org/TR/xmlschema-1/#cAttribute_Declarations>} component. 1193 """ 1194 1195 # The STD to which attribute values must conform 1196 __typeDefinition = None 1197 def typeDefinition (self): 1198 """The simple type definition to which an attribute value must 1199 conform.""" 1200 return self.__typeDefinition 1201 1202 # The expanded name content of the XSD type attribute 1203 __typeExpandedName = None 1204 1205 def __init__ (self, *args, **kw): 1206 super(AttributeDeclaration, self).__init__(*args, **kw) 1207 assert 'scope' in kw 1208 1209 def __str__ (self): 1210 if self.typeDefinition(): 1211 return 'AD[%s:%s]' % (self.name(), self.typeDefinition().expandedName()) 1212 return 'AD[%s:?]' % (self.expandedName(),) 1213 1214 @classmethod 1215 def CreateBaseInstance (cls, name, schema, std=None): 1216 """Create an attribute declaration component for a specified namespace.""" 1217 kw = { 'name' : name, 1218 'schema' : schema, 1219 'namespace_context' : schema.targetNamespace().initialNamespaceContext(), 1220 'scope' : _ScopedDeclaration_mixin.SCOPE_global } 1221 assert schema is not None 1222 bi = cls(**kw) 1223 if std is not None: 1224 bi.__typeDefinition = std 1225 bi.__typeExpandedName = None 1226 return bi 1227 1228 # CFD:AD CFD:AttributeDeclaration 1229 @classmethod 1230 def CreateFromDOM (cls, node, **kw): 1231 """Create an attribute declaration from the given DOM node. 1232 1233 wxs is a Schema instance within which the attribute is being 1234 declared. 1235 1236 node is a DOM element. The name must be one of ( 'all', 1237 'choice', 'sequence' ), and the node must be in the XMLSchema 1238 namespace. 1239 1240 scope is the _ScopeDeclaration_mxin context into which the 1241 attribute declaration is placed. It can be SCOPE_global, a 1242 complex type definition, or XSCOPE_indeterminate if this is an 1243 anonymous declaration within an attribute group. It is a 1244 required parameter for this function. 1245 """ 1246 1247 scope = kw['scope'] 1248 assert _ScopedDeclaration_mixin.ScopeIsIndeterminate(scope) or _ScopedDeclaration_mixin.IsValidScope(scope) 1249 1250 # Node should be an XMLSchema attribute node 1251 assert xsd.nodeIsNamed(node, 'attribute') 1252 1253 name = domutils.NodeAttribute(node, 'name') 1254 1255 # Implement per section 3.2.2 1256 if xsd.nodeIsNamed(node.parentNode, 'schema'): 1257 assert cls.SCOPE_global == scope 1258 elif domutils.NodeAttribute(node, 'ref') is None: 1259 # This is an anonymous declaration within an attribute use 1260 assert _ScopedDeclaration_mixin.ScopeIsIndeterminate(scope) or isinstance(scope, ComplexTypeDefinition) 1261 else: 1262 raise pyxb.SchemaValidationError('Internal attribute declaration by reference') 1263 1264 rv = cls(name=name, node=node, **kw) 1265 rv._annotationFromDOM(node) 1266 rv._valueConstraintFromDOM(node) 1267 1268 rv.__typeExpandedName = domutils.NodeAttributeQName(node, 'type') 1269 1270 kw.pop('node', None) 1271 kw['owner'] = rv 1272 1273 st_node = domutils.LocateUniqueChild(node, 'simpleType') 1274 if st_node is not None: 1275 rv.__typeDefinition = SimpleTypeDefinition.CreateFromDOM(st_node, **kw) 1276 elif rv.__typeExpandedName is None: 1277 rv.__typeDefinition = SimpleTypeDefinition.SimpleUrTypeDefinition() 1278 1279 if rv.__typeDefinition is None: 1280 rv._queueForResolution('creation') 1281 return rv 1282 1283 def isResolved (self): 1284 return self.__typeDefinition is not None 1285 1286 # res:AD res:AttributeDeclaration 1287 def _resolve (self): 1288 if self.isResolved(): 1289 return self 1290 1291 # Although the type definition may not be resolved, *this* component 1292 # is resolved, since we don't look into the type definition for anything. 1293 assert self.__typeExpandedName is not None, 'AD %s is unresolved but had no type attribute field' % (self.expandedName(),) 1294 self.__typeDefinition = self.__typeExpandedName.typeDefinition() 1295 if self.__typeDefinition is None: 1296 raise pyxb.SchemaValidationError('Type reference %s cannot be found' % (self.__typeExpandedName,)) 1297 if not isinstance(self.__typeDefinition, SimpleTypeDefinition): 1298 raise pyxb.SchemaValidationError('Need %s to be a simple type' % (self.__typeExpandedName,)) 1299 1300 return self 1301 1302 def _updateFromOther_csc (self, other): 1303 """Override fields in this instance with those from the other. 1304 1305 This method is invoked only by Schema._addNamedComponent, and 1306 then only when a built-in type collides with a schema-defined 1307 type. Material like facets is not (currently) held in the 1308 built-in copy, so the DOM information is copied over to the 1309 built-in STD, which is subsequently re-resolved. 1310 1311 Returns self. 1312 """ 1313 assert self != other 1314 assert self.name() is not None 1315 assert self.isNameEquivalent(other) 1316 super(AttributeDeclaration, self)._updateFromOther_csc(other) 1317 1318 # The other STD should be an unresolved schema-defined type. 1319 # Mark this instance as unresolved so it is re-examined 1320 if not other.isResolved(): 1321 if pyxb.namespace.BuiltInObjectUID == self._objectOrigin().generationUID(): 1322 #assert self.isResolved(), 'Built-in %s is not resolved' % (self.expandedName(),) 1323 _log.warning('Not destroying builtin %s: %s', self.expandedName(), self.__typeDefinition) 1324 else: 1325 self.__typeDefinition = None 1326 return self 1327 1328 # bR:AD 1329 def _bindingRequires_vx (self, include_lax): 1330 """Attribute declarations require their type.""" 1331 return frozenset([ self.__typeDefinition ]) 1332 1333class AttributeUse (_SchemaComponent_mixin, pyxb.namespace.resolution._Resolvable_mixin, _ValueConstraint_mixin): 1334 """An XMLSchema U{Attribute Use<http://www.w3.org/TR/xmlschema-1/#cAttribute_Use>} component.""" 1335 1336 # How this attribute can be used. The component property 1337 # "required" is true iff the value is USE_required. 1338 __use = None 1339 1340 USE_required = 0x01 #<<< The attribute is required 1341 USE_optional = 0x02 #<<< The attribute may or may not appear 1342 USE_prohibited = 0x04 #<<< The attribute must not appear 1343 1344 def required (self): 1345 return self.USE_required == self.__use 1346 1347 def prohibited (self): 1348 return self.USE_prohibited == self.__use 1349 1350 # The expanded name value of the XSD ref attribute 1351 __refExpandedName = None 1352 1353 __restrictionOf = None 1354 def restrictionOf (self): 1355 return self.__restrictionOf 1356 def _setRestrictionOf (self, au): 1357 assert isinstance(au, AttributeUse) 1358 # Might re-assign if had to suspend resolution 1359 assert (self.__restrictionOf is None) or (self.__restrictionOf == au) 1360 self.__restrictionOf = au 1361 1362 # A reference to an AttributeDeclaration 1363 def attributeDeclaration (self): 1364 """The attribute declaration for this use. 1365 1366 When the use scope is assigned, the declaration is cloned (if 1367 necessary) so that each declaration corresponds to only one use. We 1368 rely on this in code generation, because the template map for the use 1369 is stored in its declaration.""" 1370 return self.__attributeDeclaration 1371 __attributeDeclaration = None 1372 1373 # Define so superclasses can take keywords 1374 def __init__ (self, **kw): 1375 super(AttributeUse, self).__init__(**kw) 1376 1377 def matchingQNameMembers (self, au_set): 1378 """Return the subset of au_set for which the use names match this use.""" 1379 1380 if not self.isResolved(): 1381 return None 1382 this_ad = self.attributeDeclaration() 1383 rv = set() 1384 for au in au_set: 1385 if not au.isResolved(): 1386 return None 1387 that_ad = au.attributeDeclaration() 1388 if this_ad.isNameEquivalent(that_ad): 1389 rv.add(au) 1390 return rv 1391 1392 @classmethod 1393 def CreateBaseInstance (cls, schema, attribute_declaration, use=USE_optional): 1394 kw = { 'schema' : schema, 1395 'namespace_context' : schema.targetNamespace().initialNamespaceContext() } 1396 bi = cls(**kw) 1397 assert isinstance(attribute_declaration, AttributeDeclaration) 1398 bi.__attributeDeclaration = attribute_declaration 1399 bi.__use = use 1400 return bi 1401 1402 # CFD:AU CFD:AttributeUse 1403 @classmethod 1404 def CreateFromDOM (cls, node, **kw): 1405 """Create an Attribute Use from the given DOM node. 1406 1407 wxs is a Schema instance within which the attribute use is 1408 being defined. 1409 1410 node is a DOM element. The name must be 'attribute', and the 1411 node must be in the XMLSchema namespace. 1412 1413 scope is the _ScopeDeclaration_mixin context into which any 1414 required anonymous attribute declaration is put. This must be 1415 a complex type definition, or None if this use is in an 1416 attribute group. 1417 """ 1418 1419 scope = kw['scope'] 1420 assert _ScopedDeclaration_mixin.ScopeIsIndeterminate(scope) or isinstance(scope, ComplexTypeDefinition) 1421 assert xsd.nodeIsNamed(node, 'attribute') 1422 schema = kw['schema'] 1423 rv = cls(node=node, **kw) 1424 1425 rv.__use = cls.USE_optional 1426 use = domutils.NodeAttribute(node, 'use') 1427 if use is not None: 1428 if 'required' == use: 1429 rv.__use = cls.USE_required 1430 elif 'optional' == use: 1431 rv.__use = cls.USE_optional 1432 elif 'prohibited' == use: 1433 rv.__use = cls.USE_prohibited 1434 else: 1435 raise pyxb.SchemaValidationError('Unexpected value %s for attribute use attribute' % (use,)) 1436 1437 rv._valueConstraintFromDOM(node) 1438 1439 rv.__refExpandedName = domutils.NodeAttributeQName(node, 'ref') 1440 if rv.__refExpandedName is None: 1441 # Create an anonymous declaration 1442 kw.pop('node', None) 1443 kw['owner'] = rv 1444 kw['target_namespace'] = schema.targetNamespaceForNode(node, AttributeDeclaration) 1445 rv.__attributeDeclaration = AttributeDeclaration.CreateFromDOM(node, **kw) 1446 1447 if not rv.isResolved(): 1448 rv._queueForResolution('creation') 1449 1450 return rv 1451 1452 def isResolved (self): 1453 return self.__attributeDeclaration is not None 1454 1455 # res:AU res:AttributeUse 1456 def _resolve (self): 1457 if self.isResolved(): 1458 return self 1459 self.__attributeDeclaration = self.__refExpandedName.attributeDeclaration() 1460 if self.__attributeDeclaration is None: 1461 raise pyxb.SchemaValidationError('Attribute declaration %s cannot be found' % (self.__refExpandedName,)) 1462 1463 assert isinstance(self.__attributeDeclaration, AttributeDeclaration) 1464 1465 return self 1466 1467 # bR:AU 1468 def _bindingRequires_vx (self, include_lax): 1469 """Attribute uses require their declarations, but only if lax.""" 1470 if not include_lax: 1471 return frozenset() 1472 return frozenset([ self.attributeDeclaration() ]) 1473 1474 # aFS:AU 1475 def _adaptForScope (self, ctd): 1476 """Adapt this instance for the given complex type. 1477 1478 If the attribute declaration for this use is not associated with a 1479 complex type definition, then associate a clone of it with this CTD, 1480 and clone a new attribute use that uses the associated declaration. 1481 This attribute use is then inherited by extensions and restrictions, 1482 while retaining its original scope.""" 1483 rv = self 1484 assert self.isResolved() 1485 ad = self.__attributeDeclaration 1486 assert ad.scope() is not None 1487 assert isinstance(ctd, ComplexTypeDefinition) 1488 if not isinstance(ad.scope(), ComplexTypeDefinition): 1489 rv = self._clone(ctd, ctd._objectOrigin()) 1490 rv.__attributeDeclaration = ad._clone(rv, ctd._objectOrigin()) 1491 rv.__attributeDeclaration._setScope(ctd) 1492 ctd._recordLocalDeclaration(rv.__attributeDeclaration) 1493 return rv 1494 1495 def __str__ (self): 1496 return 'AU[%s]' % (self.attributeDeclaration(),) 1497 1498 1499class ElementDeclaration (_ParticleTree_mixin, _SchemaComponent_mixin, _NamedComponent_mixin, pyxb.namespace.resolution._Resolvable_mixin, _Annotated_mixin, _ValueConstraint_mixin, _ScopedDeclaration_mixin): 1500 """An XMLSchema U{Element Declaration<http://www.w3.org/TR/xmlschema-1/#cElement_Declarations>} component.""" 1501 1502 # Simple or complex type definition 1503 __typeDefinition = None 1504 def typeDefinition (self): 1505 """The simple or complex type to which the element value conforms.""" 1506 return self.__typeDefinition 1507 def _typeDefinition (self, type_definition): 1508 self.__typeDefinition = type_definition 1509 if (type_definition is not None) and (self.valueConstraint() is not None): 1510 failed = True 1511 if isinstance(self.__typeDefinition, SimpleTypeDefinition): 1512 failed = False 1513 elif isinstance(self.__typeDefinition, ComplexTypeDefinition): 1514 # The corresponding type may not be resolved so we can't check 1515 # its contentType, but we should know whether it could be 1516 # complex. 1517 ct = type_definition.contentType() 1518 if ct is None: 1519 # Either it's not complex, or we can't tell yet; neither 1520 # are failures, but in the latter case delay assigning the 1521 # type until we know. 1522 failed = False 1523 if False != self.__typeDefinition._isComplexContent(): 1524 self.__typeDefinition = None 1525 self._queueForResolution('unresolved base type'); 1526 else: 1527 failed = not (isinstance(ct, tuple) and (ComplexTypeDefinition.CT_SIMPLE == ct[0])) 1528 if failed: 1529 if self.__typeExpandedName is None: 1530 raise pyxb.SchemaValidationError('Value constraint on element %s with non-simple content' % (self.expandedName(),)) 1531 raise pyxb.SchemaValidationError('Value constraint on element %s with non-simple type %s' % (self.expandedName(), self.__typeExpandedName)) 1532 return self 1533 1534 __substitutionGroupExpandedName = None 1535 1536 __typeExpandedName = None 1537 1538 __nillable = False 1539 def nillable (self): 1540 return self.__nillable 1541 1542 __identityConstraintDefinitions = None 1543 def identityConstraintDefinitions (self): 1544 """A list of IdentityConstraintDefinition instances.""" 1545 return self.__identityConstraintDefinitions 1546 1547 __substitutionGroupAffiliation = None 1548 def substitutionGroupAffiliation (self): 1549 """None, or a reference to an ElementDeclaration.""" 1550 return self.__substitutionGroupAffiliation 1551 1552 SGE_none = 0 #<<< No substitution group exclusion specified 1553 SGE_extension = 0x01 #<<< Substitution by an extension of the base type 1554 SGE_restriction = 0x02 #<<< Substitution by a restriction of the base type 1555 SGE_substitution = 0x04 #<<< Substitution by replacement (?) 1556 1557 _SGE_Map = { 'extension' : SGE_extension 1558 , 'restriction' : SGE_restriction } 1559 _DS_Map = _SGE_Map.copy() 1560 _DS_Map.update( { 'substitution' : SGE_substitution } ) 1561 1562 # Subset of SGE marks formed by bitmask. SGE_substitution is disallowed. 1563 __substitutionGroupExclusions = SGE_none 1564 1565 # Subset of SGE marks formed by bitmask 1566 __disallowedSubstitutions = SGE_none 1567 1568 __abstract = False 1569 def abstract (self): 1570 return self.__abstract 1571 1572 def hasWildcardElement (self): 1573 """Return False, since element declarations are not wildcards.""" 1574 return False 1575 1576 # bR:ED 1577 def _bindingRequires_vx (self, include_lax): 1578 """Element declarations depend on the type definition of their 1579 content.""" 1580 return frozenset([self.__typeDefinition]) 1581 1582 def __init__ (self, *args, **kw): 1583 super(ElementDeclaration, self).__init__(*args, **kw) 1584 1585 # CFD:ED CFD:ElementDeclaration 1586 @classmethod 1587 def CreateFromDOM (cls, node, **kw): 1588 """Create an element declaration from the given DOM node. 1589 1590 wxs is a Schema instance within which the element is being 1591 declared. 1592 1593 scope is the _ScopeDeclaration_mixin context into which the 1594 element declaration is recorded. It can be SCOPE_global, a 1595 complex type definition, or None in the case of elements 1596 declared in a named model group. 1597 1598 node is a DOM element. The name must be 'element', and the 1599 node must be in the XMLSchema namespace.""" 1600 1601 scope = kw['scope'] 1602 assert _ScopedDeclaration_mixin.ScopeIsIndeterminate(scope) or _ScopedDeclaration_mixin.IsValidScope(scope) 1603 1604 # Node should be an XMLSchema element node 1605 assert xsd.nodeIsNamed(node, 'element') 1606 1607 # Might be top-level, might be local 1608 name = domutils.NodeAttribute(node, 'name') 1609 if xsd.nodeIsNamed(node.parentNode, 'schema'): 1610 assert _ScopedDeclaration_mixin.SCOPE_global == scope 1611 elif domutils.NodeAttribute(node, 'ref') is None: 1612 # Scope may be None or a CTD. 1613 assert _ScopedDeclaration_mixin.ScopeIsIndeterminate(scope) or isinstance(scope, ComplexTypeDefinition) 1614 else: 1615 raise pyxb.SchemaValidationError('Created reference as element declaration') 1616 1617 rv = cls(name=name, node=node, **kw) 1618 rv._annotationFromDOM(node) 1619 rv._valueConstraintFromDOM(node) 1620 1621 rv.__substitutionGroupExpandedName = domutils.NodeAttributeQName(node, 'substitutionGroup') 1622 1623 kw.pop('node', None) 1624 kw['owner'] = rv 1625 1626 # Global EDs should be given indeterminate scope to ensure subordinate 1627 # declarations are not inappropriately associated with the element's 1628 # namespace. If the ED is within a non-global scope that scope should 1629 # be retained. 1630 if rv._scopeIsGlobal(): 1631 kw['scope'] = _ScopedDeclaration_mixin.XSCOPE_indeterminate 1632 1633 identity_constraints = [] 1634 for cn in node.childNodes: 1635 if (Node.ELEMENT_NODE == cn.nodeType) and xsd.nodeIsNamed(cn, 'key', 'unique', 'keyref'): 1636 identity_constraints.append(IdentityConstraintDefinition.CreateFromDOM(cn, **kw)) 1637 rv.__identityConstraintDefinitions = identity_constraints 1638 1639 rv.__typeDefinition = None 1640 rv.__typeExpandedName = domutils.NodeAttributeQName(node, 'type') 1641 simpleType_node = domutils.LocateUniqueChild(node, 'simpleType') 1642 complexType_node = domutils.LocateUniqueChild(node, 'complexType') 1643 if rv.__typeExpandedName is not None: 1644 if (simpleType_node is not None) and (complexType_node is not None): 1645 raise pyxb.SchemaValidationError('Cannot combine type attribute with simpleType or complexType child') 1646 if (rv.__typeDefinition is None) and (simpleType_node is not None): 1647 rv._typeDefinition(SimpleTypeDefinition.CreateFromDOM(simpleType_node, **kw)) 1648 if (rv.__typeDefinition is None) and (complexType_node is not None): 1649 rv._typeDefinition(ComplexTypeDefinition.CreateFromDOM(complexType_node, **kw)) 1650 if rv.__typeDefinition is None: 1651 if rv.__typeExpandedName is None: 1652 # Scan for particle types which were supposed to be enclosed in a complexType 1653 for cn in node.childNodes: 1654 if Particle.IsParticleNode(cn): 1655 raise pyxb.SchemaValidationError('Node %s in element must be wrapped by complexType.' % (cn.localName,)) 1656 rv._typeDefinition(ComplexTypeDefinition.UrTypeDefinition()) 1657 rv.__isResolved = (rv.__typeDefinition is not None) and (rv.__substitutionGroupExpandedName is None) 1658 if not rv.__isResolved: 1659 rv._queueForResolution('creation') 1660 1661 attr_val = domutils.NodeAttribute(node, 'nillable') 1662 if attr_val is not None: 1663 rv.__nillable = datatypes.boolean(attr_val) 1664 1665 attr_val = domutils.NodeAttribute(node, 'abstract') 1666 if attr_val is not None: 1667 rv.__abstract = datatypes.boolean(attr_val) 1668 1669 schema = kw['schema'] 1670 rv.__disallowedSubstitutions = schema.blockForNode(node, cls._DS_Map) 1671 rv.__substitutionGroupExclusions = schema.finalForNode(node, cls._SGE_Map) 1672 1673 return rv 1674 1675 def isAdaptable (self, ctd): 1676 """Determine whether this element declaration is adaptable. 1677 1678 OK, this gets ugly. First, if this declaration isn't resolved, it's 1679 clearly not adaptable. 1680 1681 Now: For it to be adaptable, we must know enough about its type to 1682 verify that it is derivation-consistent with any other uses of the 1683 same name in the same complex type. If the element's type is 1684 resolved, that's good enough. 1685 1686 If the element's type isn't resolved, we're golden as long as 1687 type-equivalent types were used. But it's also allowed for the 1688 derived ctd to use the element name constraining it to a derivation of 1689 the element base type. (Go see namespace 1690 http://www.opengis.net/ows/1.1 types PositionType, PositionType2D, 1691 BoundingBox, and WGS84BoundingBox for an example). So, we really do 1692 have to have the element's type resolved. 1693 1694 Except that if a CTD's content incorporates an element with the same 1695 type as the CTD (i.e., nested), this will never happen, because the 1696 CTD can't get resolved until after it has been resolved. 1697 (Go see {http://www.opengis.net/ows/1.1}ContentsBaseType and 1698 {http://www.opengis.net/ows/1.1}DatasetDescriptionSummaryBaseType for 1699 an example). 1700 1701 So, we give the world a break and assume that if the type we're trying 1702 to resolve is the same as the type of an element in that type, then 1703 the element type will be resolved by the point it's needed. In point 1704 of fact, it won't, but we'll only notice that if a CTD contains an 1705 element whose type is a restriction of the CTD. In that case, 1706 isDerivationConsistent will blow chunks and somebody'll have to come 1707 back and finish up this mess. 1708 """ 1709 1710 if not self.isResolved(): 1711 return False 1712 if self.typeDefinition().isResolved(): 1713 return True 1714 # Aw, dammit. See if we're gonna need the type resolved before we can 1715 # adapt this thing. 1716 existing_decl = ctd.lookupScopedElementDeclaration(self.expandedName()) 1717 if existing_decl is None: 1718 # Nobody else has this name, so we don't have to check for 1719 # consistency. 1720 return True 1721 # OK, we've got a name clash. Are the two types trivially equivalent? 1722 if self.typeDefinition().isTypeEquivalent(existing_decl.typeDefinition()): 1723 # Yes! Go for it. 1724 return True 1725 # No. Can't proceed until the type definition is resolved. Hope it 1726 # can be.... 1727 _log.warning('Require %s to be resolved; might be a loop.', self.typeDefinition()) 1728 return False 1729 1730 # aFS:ED 1731 def _adaptForScope (self, owner, ctd): 1732 rv = self 1733 assert isinstance(ctd, ComplexTypeDefinition), '%s is not a CTD' % (ctd,) 1734 if not isinstance(self.scope(), ComplexTypeDefinition): 1735 assert owner is not None 1736 rv = self._clone(owner, ctd._objectOrigin()) 1737 rv._setScope(ctd) 1738 ctd._recordLocalDeclaration(rv) 1739 return rv 1740 1741 __isResolved = False 1742 def isResolved (self): 1743 return self.__isResolved 1744 1745 # res:ED res:ElementDeclaration 1746 def _resolve (self): 1747 if self.isResolved(): 1748 return self 1749 1750 #if self._scopeIsIndeterminate(): 1751 # _log.debug('WARNING: Resolving ED %s with indeterminate scope (is this a problem?)', self.expandedName()) 1752 if self.__substitutionGroupExpandedName is not None: 1753 sga = self.__substitutionGroupExpandedName.elementDeclaration() 1754 if sga is None: 1755 raise pyxb.SchemaValidationError('Element declaration refers to unrecognized substitution group %s' % (self.__substitutionGroupExpandedName,)) 1756 self.__substitutionGroupAffiliation = sga 1757 1758 resolved = True 1759 if self.__typeDefinition is None: 1760 assert self.__typeExpandedName is not None 1761 td = self.__typeExpandedName.typeDefinition() 1762 if td is None: 1763 raise pyxb.SchemaValidationError('Type declaration %s cannot be found' % (self.__typeExpandedName,)) 1764 # Type definition may be delayed for default value validation; if 1765 # so, we're not really resolved. 1766 self._typeDefinition(td) 1767 resolved = self.typeDefinition() is not None 1768 1769 self.__isResolved = resolved 1770 1771 return self 1772 1773 def _walkParticleTree (self, visit, arg): 1774 visit(self, None, arg) 1775 1776 def __str__ (self): 1777 if self.typeDefinition() is not None: 1778 return 'ED[%s:%s]' % (self.name(), self.typeDefinition().name()) 1779 return 'ED[%s:?]' % (self.name(),) 1780 1781 1782class ComplexTypeDefinition (_SchemaComponent_mixin, _NamedComponent_mixin, pyxb.namespace.resolution._Resolvable_mixin, _Annotated_mixin, _AttributeWildcard_mixin): 1783 __PrivateTransient = set() 1784 1785 # The type resolved from the base attribute. 1786 __baseTypeDefinition = None 1787 def baseTypeDefinition (self): 1788 """The type resolved from the base attribute.""" 1789 return self.__baseTypeDefinition 1790 1791 DM_empty = 0 #<<< No derivation method specified 1792 DM_extension = 0x01 #<<< Derivation by extension 1793 DM_restriction = 0x02 #<<< Derivation by restriction 1794 1795 _DM_Map = { 'extension' : DM_extension 1796 , 'restriction' : DM_restriction } 1797 1798 # How the type was derived (a DM_* value) 1799 # (This field is used to identify unresolved definitions.) 1800 __derivationMethod = None 1801 def derivationMethod (self): 1802 """How the type was derived.""" 1803 return self.__derivationMethod 1804 1805 # Derived from the final and finalDefault attributes 1806 __final = DM_empty 1807 1808 # Derived from the abstract attribute 1809 __abstract = False 1810 def abstract (self): 1811 return self.__abstract 1812 1813 # A frozenset() of AttributeUse instances. 1814 __attributeUses = None 1815 def attributeUses (self): 1816 """A frozenset() of AttributeUse instances.""" 1817 return self.__attributeUses 1818 1819 # A map from NCNames to AttributeDeclaration instances that are 1820 # local to this type. 1821 __scopedAttributeDeclarations = None 1822 def lookupScopedAttributeDeclaration (self, expanded_name): 1823 """Find an attribute declaration with the given name that is local to this type. 1824 1825 Returns None if there is no such local attribute declaration.""" 1826 if self.__scopedAttributeDeclarations is None: 1827 return None 1828 return self.__scopedAttributeDeclarations.get(expanded_name) 1829 1830 # A map from NCNames to ElementDeclaration instances that are 1831 # local to this type. 1832 __scopedElementDeclarations = None 1833 def lookupScopedElementDeclaration (self, expanded_name): 1834 """Find an element declaration with the given name that is local to this type. 1835 1836 Returns None if there is no such local element declaration.""" 1837 if self.__scopedElementDeclarations is None: 1838 return None 1839 return self.__scopedElementDeclarations.get(expanded_name) 1840 1841 __localScopedDeclarations = None 1842 def localScopedDeclarations (self, reset=False): 1843 """Return a list of element and attribute declarations that were 1844 introduced in this definition (i.e., their scope is this CTD). 1845 1846 @note: This specifically returns a list, with element declarations 1847 first, because name binding should privilege the elements over the 1848 attributes. Within elements and attributes, the components are sorted 1849 by expanded name, to ensure consistency across a series of binding 1850 generations. 1851 1852 @keyword reset: If C{False} (default), a cached previous value (if it 1853 exists) will be returned. 1854 """ 1855 if reset or (self.__localScopedDeclarations is None): 1856 rve = [ _ed for _ed in six.itervalues(self.__scopedElementDeclarations) if (self == _ed.scope()) ] 1857 rve.sort(key=lambda _x: _x.expandedName()) 1858 rva = [ _ad for _ad in six.itervalues(self.__scopedAttributeDeclarations) if (self == _ad.scope()) ] 1859 rva.sort(key=lambda _x: _x.expandedName()) 1860 self.__localScopedDeclarations = rve 1861 self.__localScopedDeclarations.extend(rva) 1862 return self.__localScopedDeclarations 1863 1864 def _recordLocalDeclaration (self, decl): 1865 """Record the given declaration as being locally scoped in 1866 this type.""" 1867 assert isinstance(decl, _ScopedDeclaration_mixin) 1868 if isinstance(decl, ElementDeclaration): 1869 scope_map = self.__scopedElementDeclarations 1870 elif isinstance(decl, AttributeDeclaration): 1871 scope_map = self.__scopedAttributeDeclarations 1872 else: 1873 raise pyxb.LogicError('Unexpected instance of %s recording as local declaration' % (type(decl),)) 1874 decl_en = decl.expandedName() 1875 existing_decl = scope_map.setdefault(decl_en, decl) 1876 if decl != existing_decl: 1877 if isinstance(decl, ElementDeclaration): 1878 # Test cos-element-consistent 1879 existing_type = existing_decl.typeDefinition() 1880 pending_type = decl.typeDefinition() 1881 if not pending_type.isDerivationConsistent(existing_type): 1882 raise pyxb.SchemaValidationError('Conflicting element declarations for %s: existing %s versus new %s' % (decl.expandedName(), existing_type, pending_type)) 1883 # If we're deriving by restriction and the declaration has a 1884 # different type than the one in the parent scope, discard the 1885 # parent scope declaration and replace it with this one rather 1886 # than treating the parent as a base. 1887 if (existing_type != pending_type) and (self.DM_restriction == self.derivationMethod()): 1888 decl._overrideParentScope(existing_decl); 1889 scope_map[decl_en] = decl; 1890 existing_decl = decl 1891 elif isinstance(decl, AttributeDeclaration): 1892 raise pyxb.SchemaValidationError('Multiple attribute declarations for %s' % (decl.expandedName(),)) 1893 else: 1894 assert False, 'Unrecognized type %s' % (type(decl),) 1895 decl._baseDeclaration(existing_decl) 1896 return self 1897 1898 def _isHierarchyRoot (self): 1899 """Return C{True} iff this is the root of a complex type definition hierarchy. 1900 """ 1901 base = self.__baseTypeDefinition 1902 return isinstance(base, SimpleTypeDefinition) or base.isUrTypeDefinition() 1903 1904 CT_EMPTY = 'EMPTY' #<<< No content 1905 CT_SIMPLE = 'SIMPLE' #<<< Simple (character) content 1906 CT_MIXED = 'MIXED' #<<< Children may be elements or other (e.g., character) content 1907 CT_ELEMENT_ONLY = 'ELEMENT_ONLY' #<<< Expect only element content. 1908 1909 def _contentTypeTag (self): 1910 """Return the value of the content type identifier, i.e. one of the 1911 CT_ constants. Return value is None if no content type has been 1912 defined.""" 1913 if isinstance(self.__contentType, tuple): 1914 return self.__contentType[0] 1915 return self.__contentType 1916 1917 def _contentTypeComponent (self): 1918 if isinstance(self.__contentType, tuple): 1919 return self.__contentType[1] 1920 return None 1921 1922 # Identify the sort of content in this type. 1923 __contentType = None 1924 def contentType (self): 1925 """Identify the sort of content in this type. 1926 1927 Valid values are: 1928 - C{CT_EMPTY} 1929 - ( C{CT_SIMPLE}, a L{SimpleTypeDefinition} instance ) 1930 - ( C{CT_MIXED}, a L{Particle} instance ) 1931 - ( C{CT_ELEMENT_ONLY}, a L{Particle} instance ) 1932 """ 1933 return self.__contentType 1934 1935 def contentTypeAsString (self): 1936 if self.CT_EMPTY == self.contentType(): 1937 return 'EMPTY' 1938 ( tag, particle ) = self.contentType() 1939 if self.CT_SIMPLE == tag: 1940 return 'Simple [%s]' % (particle,) 1941 if self.CT_MIXED == tag: 1942 return 'Mixed [%s]' % (particle,) 1943 if self.CT_ELEMENT_ONLY == tag: 1944 return 'Element [%s]' % (particle,) 1945 raise pyxb.LogicError('Unhandled content type') 1946 1947 # Derived from the block and blockDefault attributes 1948 __prohibitedSubstitutions = DM_empty 1949 1950 # @todo: Extracted from children of various types 1951 __annotations = None 1952 1953 def __init__ (self, *args, **kw): 1954 super(ComplexTypeDefinition, self).__init__(*args, **kw) 1955 self.__derivationMethod = kw.get('derivation_method') 1956 self.__scopedElementDeclarations = { } 1957 self.__scopedAttributeDeclarations = { } 1958 1959 def hasWildcardElement (self): 1960 """Return True iff this type includes a wildcard element in 1961 its content model.""" 1962 if self.CT_EMPTY == self.contentType(): 1963 return False 1964 ( tag, particle ) = self.contentType() 1965 if self.CT_SIMPLE == tag: 1966 return False 1967 return particle.hasWildcardElement() 1968 1969 def _updateFromOther_csc (self, other): 1970 """Override fields in this instance with those from the other. 1971 1972 This method is invoked only by Schema._addNamedComponent, and 1973 then only when a built-in type collides with a schema-defined 1974 type. Material like facets is not (currently) held in the 1975 built-in copy, so the DOM information is copied over to the 1976 built-in STD, which is subsequently re-resolved. 1977 1978 Returns self. 1979 """ 1980 assert self != other 1981 assert self.isNameEquivalent(other) 1982 super(ComplexTypeDefinition, self)._updateFromOther_csc(other) 1983 1984 if not other.isResolved(): 1985 if pyxb.namespace.BuiltInObjectUID != self._objectOrigin().generationUID(): 1986 self.__isResolved = False 1987 1988 return self 1989 1990 __UrTypeDefinition = None 1991 @classmethod 1992 def UrTypeDefinition (cls, schema=None, in_builtin_definition=False): 1993 """Create the ComplexTypeDefinition instance that approximates 1994 the ur-type. 1995 1996 See section 3.4.7. 1997 """ 1998 1999 # The first time, and only the first time, this is called, a 2000 # namespace should be provided which is the XMLSchema 2001 # namespace for this run of the system. Please, do not try to 2002 # allow this by clearing the type definition. 2003 #if in_builtin_definition and (cls.__UrTypeDefinition is not None): 2004 # raise pyxb.LogicError('Multiple definitions of UrType') 2005 if cls.__UrTypeDefinition is None: 2006 # NOTE: We use a singleton subclass of this class 2007 assert schema is not None 2008 2009 ns_ctx = schema.targetNamespace().initialNamespaceContext() 2010 2011 kw = { 'name' : 'anyType', 2012 'schema' : schema, 2013 'namespace_context' : ns_ctx, 2014 'binding_namespace' : schema.targetNamespace(), 2015 'derivation_method' : cls.DM_restriction, 2016 'scope' : _ScopedDeclaration_mixin.SCOPE_global } 2017 bi = _UrTypeDefinition(**kw) 2018 2019 # The ur-type is its own baseTypeDefinition 2020 bi.__baseTypeDefinition = bi 2021 2022 # No constraints on attributes 2023 bi._setAttributeWildcard(Wildcard(namespace_constraint=Wildcard.NC_any, process_contents=Wildcard.PC_lax, **kw)) 2024 2025 # There isn't anything to look up, but context is still global. 2026 # No declarations will be created, so use indeterminate scope to 2027 # be consistent with validity checks in Particle constructor. 2028 # Content is mixed, with elements completely unconstrained. @todo: 2029 # not associated with a schema (it should be) 2030 kw = { 'namespace_context' : ns_ctx 2031 , 'schema' : schema 2032 , 'scope': _ScopedDeclaration_mixin.XSCOPE_indeterminate } 2033 w = Wildcard(namespace_constraint=Wildcard.NC_any, process_contents=Wildcard.PC_lax, **kw) 2034 p = Particle(w, min_occurs=0, max_occurs=None, **kw) 2035 m = ModelGroup(compositor=ModelGroup.C_SEQUENCE, particles=[ p ], **kw) 2036 bi.__contentType = ( cls.CT_MIXED, Particle(m, **kw) ) 2037 2038 # No attribute uses 2039 bi.__attributeUses = set() 2040 2041 # No constraints on extension or substitution 2042 bi.__final = cls.DM_empty 2043 bi.__prohibitedSubstitutions = cls.DM_empty 2044 2045 bi.__abstract = False 2046 2047 # Refer to it by name 2048 bi.setNameInBinding(bi.name()) 2049 2050 # The ur-type is always resolved 2051 bi.__isResolved = True 2052 2053 cls.__UrTypeDefinition = bi 2054 return cls.__UrTypeDefinition 2055 2056 def isBuiltin (self): 2057 """Indicate whether this simple type is a built-in type.""" 2058 return (self.UrTypeDefinition() == self) 2059 2060 # bR:CTD 2061 def _bindingRequires_vx (self, include_lax): 2062 """Complex type definitions depend on their base type definition, the 2063 type definitions of any local attribute declarations, and if strict 2064 the type definitions of any local element declarations.""" 2065 rv = set() 2066 assert self.__baseTypeDefinition is not None 2067 rv.add(self.__baseTypeDefinition) 2068 for decl in self.localScopedDeclarations(): 2069 if include_lax or isinstance(decl, AttributeDeclaration): 2070 rv.add(decl.typeDefinition()) 2071 if include_lax: 2072 ct = self._contentTypeComponent() 2073 if ct is not None: 2074 rv.add(ct) 2075 return frozenset(rv) 2076 2077 # CFD:CTD CFD:ComplexTypeDefinition 2078 @classmethod 2079 def CreateFromDOM (cls, node, **kw): 2080 # Node should be an XMLSchema complexType node 2081 assert xsd.nodeIsNamed(node, 'complexType') 2082 2083 name = domutils.NodeAttribute(node, 'name') 2084 2085 rv = cls(name=name, node=node, derivation_method=None, **kw) 2086 2087 # Most of the time, the scope will be global. It can be something 2088 # else only if this is an anonymous CTD (created within an element 2089 # declaration which itself may be global, in a containing CTD, or in a 2090 # model group). 2091 if rv._scopeIsGlobal(): 2092 assert isinstance(rv.owner(), Schema) 2093 if rv.isAnonymous(): 2094 raise pyxb.SchemaValidationError("Anonymous complex type at schema top level") 2095 else: 2096 assert not isinstance(rv.owner(), Schema) 2097 if not rv.isAnonymous(): 2098 raise pyxb.SchemaValidationError('Name attribute invalid on non-global complex types: %s' % (rv.expandedName(),)) 2099 2100 kw.pop('node', None) 2101 kw['owner'] = rv 2102 kw['scope'] = rv 2103 2104 return rv.__setContentFromDOM(node, **kw) 2105 2106 __baseExpandedName = None 2107 2108 __ckw = None 2109 __anyAttribute = None 2110 __attributeGroupNames = None 2111 __usesC1 = None 2112 __usesC1C2 = None 2113 __attributeGroups = None 2114 __PrivateTransient.update(['ckw', 'anyAttribute', 'attributeGroupNames', 'usesC1', 'usesC1C2', 'attributeGroups' ]) 2115 2116 # Handle attributeUses, attributeWildcard, contentType 2117 def __completeProcessing (self, method, content_style): 2118 2119 if self.__usesC1C2 is None: 2120 # Handle clauses 1 and 2 (common between simple and complex types) 2121 uses_c1 = self.__usesC1 # attribute children 2122 uses_c2 = set() # attribute group children 2123 self.__attributeGroups = [] 2124 for ag_en in self.__attributeGroupNames: 2125 agd = ag_en.attributeGroupDefinition() 2126 if agd is None: 2127 raise pyxb.SchemaValidationError('Attribute group %s cannot be found' % (ag_en,)) 2128 if not agd.isResolved(): 2129 self._queueForResolution('unresolved attribute group', depends_on=agd) 2130 return self 2131 self.__attributeGroups.append(agd) 2132 uses_c2.update(agd.attributeUses()) 2133 2134 uses_c1c2 = uses_c1.union(uses_c2) 2135 for au in uses_c1c2: 2136 if not au.isResolved(): 2137 self._queueForResolution('attribute use not resolved') 2138 return self 2139 ad = au.attributeDeclaration() 2140 if not ad.isResolved(): 2141 ad_en = ad.expandedName() 2142 self._queueForResolution('unresolved attribute declaration %s from base type' % (ad_en,), depends_on=ad) 2143 return self 2144 2145 self.__usesC1C2 = frozenset([ _u._adaptForScope(self) for _u in uses_c1c2 ]) 2146 2147 # Handle clause 3. Note the slight difference in description between 2148 # simple and complex content is just that the complex content doesn't 2149 # bother to check that the base type definition is a complex type 2150 # definition. So the same code should work for both, and we don't 2151 # bother to check content_style. 2152 uses_c3 = set() # base attributes 2153 if isinstance(self.__baseTypeDefinition, ComplexTypeDefinition): 2154 # NB: The base type definition should be resolved, which means 2155 # that all its attribute uses have been adapted for scope already 2156 uses_c3 = set(self.__baseTypeDefinition.__attributeUses) 2157 assert self.__baseTypeDefinition.isResolved() 2158 for au in uses_c3: 2159 if not au.isResolved(): 2160 self._queueForResolution('unresolved attribute use from base type', depends_on=au) 2161 return self 2162 ad = au.attributeDeclaration() 2163 if not ad.isResolved(): 2164 ad_en = ad.expandedName() 2165 self._queueForResolution('unresolved attribute declaration %s from base type' % (ad_en,), depends_on=ad) 2166 return self 2167 assert not au.attributeDeclaration()._scopeIsIndeterminate() 2168 2169 if self.DM_restriction == method: 2170 # Exclude attributes per clause 3. Note that this process 2171 # handles both 3.1 and 3.2, since we have not yet filtered 2172 # uses_c1 for prohibited attributes. 2173 for au in self.__usesC1C2: 2174 matching_uses = au.matchingQNameMembers(uses_c3) 2175 assert matching_uses is not None 2176 assert 1 >= len(matching_uses), 'Multiple inherited attribute uses with name %s' 2177 for au2 in matching_uses: 2178 assert au2.isResolved() 2179 uses_c3.remove(au2) 2180 au._setRestrictionOf(au2) 2181 else: 2182 # In theory, the same attribute name can't appear in the base 2183 # and sub types because that would violate the local 2184 # declaration constraint. 2185 assert self.DM_extension == method 2186 2187 use_map = { } 2188 for au in self.__usesC1C2.union(uses_c3): 2189 assert au.isResolved() 2190 ad_en = au.attributeDeclaration().expandedName() 2191 if ad_en in use_map: 2192 raise pyxb.SchemaValidationError('Multiple definitions for %s in CTD %s' % (ad_en, self.expandedName())) 2193 use_map[ad_en] = au 2194 2195 # Past the last point where we might not resolve this instance. Store 2196 # the attribute uses, also recording local attribute declarations. 2197 self.__attributeUses = frozenset(six.itervalues(use_map)) 2198 if not self._scopeIsIndeterminate(): 2199 for au in self.__attributeUses: 2200 assert not au.attributeDeclaration()._scopeIsIndeterminate(), 'indeterminate scope for %s' % (au,) 2201 2202 # @todo: Handle attributeWildcard 2203 # Clause 1 2204 local_wildcard = None 2205 if self.__anyAttribute is not None: 2206 local_wildcard = Wildcard.CreateFromDOM(self.__anyAttribute) 2207 2208 # Clause 2 2209 complete_wildcard = _AttributeWildcard_mixin.CompleteWildcard(self._namespaceContext(), self.__attributeGroups, local_wildcard) 2210 2211 # Clause 3 2212 if self.DM_restriction == method: 2213 # Clause 3.1 2214 self._setAttributeWildcard(complete_wildcard) 2215 else: 2216 assert (self.DM_extension == method) 2217 assert self.baseTypeDefinition().isResolved() 2218 # 3.2.1 2219 base_wildcard = None 2220 if isinstance(self.baseTypeDefinition(), ComplexTypeDefinition): 2221 base_wildcard = self.baseTypeDefinition().attributeWildcard() 2222 # 3.2.2 2223 if base_wildcard is not None: 2224 if complete_wildcard is None: 2225 # 3.2.2.1.1 2226 self._setAttributeWildcard(base_wildcard) 2227 else: 2228 # 3.2.2.1.2 2229 self._setAttributeWildcard(Wildcard (process_contents=complete_wildcard.processContents(), 2230 namespace_constraint = Wildcard.IntensionalUnion([complete_wildcard.namespaceConstraint(), 2231 base_wildcard.namespaceConstraint()]), 2232 annotation=complete_wildcard.annotation(), 2233 namespace_context=self._namespaceContext())) 2234 else: 2235 # 3.2.2.2 2236 self._setAttributeWildcard(complete_wildcard) 2237 2238 # @todo: Make sure we didn't miss any child nodes 2239 2240 # Remove local attributes we will never use again 2241 del self.__usesC1 2242 del self.__usesC1C2 2243 del self.__attributeGroups 2244 self.__ckw = None 2245 2246 # Mark the type resolved 2247 self.__isResolved = True 2248 return self 2249 2250 def __simpleContent (self, method, **kw): 2251 # Do content type 2252 if isinstance(self.__baseTypeDefinition, ComplexTypeDefinition): 2253 # Clauses 1, 2, and 3 might apply 2254 parent_content_type = self.__baseTypeDefinition.__contentType 2255 if ((type(parent_content_type) == tuple) \ 2256 and (self.CT_SIMPLE == parent_content_type[0]) \ 2257 and (self.DM_restriction == method)): 2258 # Clause 1 2259 assert self.__ctscRestrictionNode is not None 2260 std = self.__ctscClause2STD 2261 if std is None: 2262 std = parent_content_type[1] 2263 assert isinstance(std, SimpleTypeDefinition) 2264 if not std.isResolved(): 2265 return None 2266 restriction_node = self.__ctscRestrictionNode 2267 self.__ctscClause2STD = None 2268 self.__ctscRestrictionNode = None 2269 return ( self.CT_SIMPLE, std._createRestriction(self, restriction_node) ) 2270 if ((type(parent_content_type) == tuple) \ 2271 and (self.CT_MIXED == parent_content_type[0]) \ 2272 and parent_content_type[1].isEmptiable()): 2273 # Clause 2 2274 assert isinstance(self.__ctscClause2STD, SimpleTypeDefinition) 2275 return ( self.CT_SIMPLE, self.__ctscClause2STD ) 2276 # Clause 3 2277 return parent_content_type 2278 # Clause 4 2279 return ( self.CT_SIMPLE, self.__baseTypeDefinition ) 2280 2281 __ctscClause2STD = None 2282 __ctscRestrictionNode = None 2283 __PrivateTransient.update(['ctscRestrictionNode' ]) 2284 __effectiveMixed = None 2285 __effectiveContent = None 2286 __isComplexContent = None 2287 def _isComplexContent (self): 2288 return self.__isComplexContent 2289 __ctscRestrictionMode = None 2290 __contentStyle = None 2291 2292 def __setComplexContentFromDOM (self, type_node, content_node, definition_node_list, method, **kw): 2293 # Do content type. Cache the keywords that need to be used 2294 # for newly created schema components. 2295 ckw = kw.copy() 2296 ckw['namespace_context'] = pyxb.namespace.NamespaceContext.GetNodeContext(type_node) 2297 2298 # Definition 1: effective mixed 2299 mixed_attr = None 2300 if content_node is not None: 2301 mixed_attr = domutils.NodeAttribute(content_node, 'mixed') 2302 if mixed_attr is None: 2303 mixed_attr = domutils.NodeAttribute(type_node, 'mixed') 2304 if mixed_attr is not None: 2305 effective_mixed = datatypes.boolean(mixed_attr) 2306 else: 2307 effective_mixed = False 2308 2309 # Definition 2: effective content 2310 test_2_1_1 = True 2311 test_2_1_2 = False 2312 test_2_1_3 = False 2313 typedef_node = None 2314 for cn in definition_node_list: 2315 if Node.ELEMENT_NODE != cn.nodeType: 2316 continue 2317 if xsd.nodeIsNamed(cn, 'simpleContent', 'complexContent'): 2318 # Should have found the content node earlier. 2319 raise pyxb.LogicError('Missed explicit wrapper in complexType content') 2320 if Particle.IsTypedefNode(cn): 2321 typedef_node = cn 2322 test_2_1_1 = False 2323 if xsd.nodeIsNamed(cn, 'all', 'sequence') \ 2324 and (not domutils.HasNonAnnotationChild(cn)): 2325 test_2_1_2 = True 2326 if xsd.nodeIsNamed(cn, 'choice') \ 2327 and (not domutils.HasNonAnnotationChild(cn)): 2328 mo_attr = domutils.NodeAttribute(cn, 'minOccurs') 2329 if ((mo_attr is not None) \ 2330 and (0 == datatypes.integer(mo_attr))): 2331 test_2_1_3 = True 2332 satisfied_predicates = 0 2333 if test_2_1_1: 2334 satisfied_predicates += 1 2335 if test_2_1_2: 2336 satisfied_predicates += 1 2337 if test_2_1_3: 2338 satisfied_predicates += 1 2339 if 1 == satisfied_predicates: 2340 if effective_mixed: 2341 # Clause 2.1.4 2342 assert (typedef_node is None) or test_2_1_2 2343 m = ModelGroup(compositor=ModelGroup.C_SEQUENCE, particles=[], **ckw) 2344 effective_content = Particle(m, **ckw) 2345 else: 2346 # Clause 2.1.5 2347 effective_content = self.CT_EMPTY 2348 else: 2349 # Clause 2.2 2350 assert typedef_node is not None 2351 effective_content = Particle.CreateFromDOM(typedef_node, **kw) 2352 2353 # For issues related to soapenc:Array and the fact that PyXB 2354 # determines the content of types derived from it is empty, see 2355 # http://tech.groups.yahoo.com/group/soapbuilders/message/5879 and 2356 # lament the fact that the WSDL spec is not compatible with XSD. It 2357 # is *not* an error in PyXB. 2358 2359 self.__effectiveMixed = effective_mixed 2360 self.__effectiveContent = effective_content 2361 self.__ckw = ckw 2362 2363 def __complexContent (self, method): 2364 ckw = self.__ckw 2365 2366 # Shared from clause 3.1.2 2367 if self.__effectiveMixed: 2368 ct = self.CT_MIXED 2369 else: 2370 ct = self.CT_ELEMENT_ONLY 2371 # Clause 3 2372 if self.DM_restriction == method: 2373 # Clause 3.1 2374 if self.CT_EMPTY == self.__effectiveContent: 2375 # Clause 3.1.1 2376 content_type = self.CT_EMPTY # ASSIGN CT_EMPTY 2377 else: 2378 # Clause 3.1.2(.2) 2379 content_type = ( ct, self.__effectiveContent ) # ASSIGN RESTRICTION 2380 assert 0 == len(self.__scopedElementDeclarations) 2381 # Reference the parent element declarations; normally this 2382 # would happen naturally as a consequence of appending this 2383 # type's content model to the parent's, but with restriction 2384 # there is no such re-use unless we do this. 2385 self.__scopedElementDeclarations.update(self.__baseTypeDefinition.__scopedElementDeclarations) 2386 else: 2387 # Clause 3.2 2388 assert self.DM_extension == method 2389 assert self.__baseTypeDefinition.isResolved() 2390 parent_content_type = self.__baseTypeDefinition.contentType() 2391 if self.CT_EMPTY == self.__effectiveContent: 2392 content_type = parent_content_type # ASSIGN EXTENSION PARENT ONLY 2393 elif self.CT_EMPTY == parent_content_type: 2394 # Clause 3.2.2 2395 content_type = ( ct, self.__effectiveContent ) # ASSIGN EXTENSION LOCAL ONLY 2396 else: 2397 assert type(parent_content_type) == tuple 2398 m = ModelGroup(compositor=ModelGroup.C_SEQUENCE, particles=[ parent_content_type[1], self.__effectiveContent ], **ckw) 2399 content_type = ( ct, Particle(m, **ckw) ) # ASSIGN EXTENSION PARENT AND LOCAL 2400 2401 assert (self.CT_EMPTY == content_type) or ((type(content_type) == tuple) and (content_type[1] is not None)) 2402 return content_type 2403 2404 __isResolved = False 2405 def isResolved (self): 2406 """Indicate whether this complex type is fully defined. 2407 2408 All built-in type definitions are resolved upon creation. 2409 Schema-defined type definitionss are held unresolved until the 2410 schema has been completely read, so that references to later 2411 schema-defined types can be resolved. Resolution is performed 2412 after the entire schema has been scanned and type-definition 2413 instances created for all topLevel{Simple,Complex}Types. 2414 2415 If a built-in type definition is also defined in a schema 2416 (which it should be), the built-in definition is kept, with 2417 the schema-related information copied over from the matching 2418 schema-defined type definition. The former then replaces the 2419 latter in the list of type definitions to be resolved. See 2420 Schema._addNamedComponent. 2421 """ 2422 return self.__isResolved 2423 2424 # Back door to allow the ur-type to re-resolve itself. Only needed when 2425 # we're generating bindings for XMLSchema itself. 2426 def _setDerivationMethod (self, derivation_method): 2427 self.__derivationMethod = derivation_method 2428 self.__isResolved = True 2429 return self 2430 2431 def __setContentFromDOM (self, node, **kw): 2432 schema = kw.get('schema') 2433 assert schema is not None 2434 self.__prohibitedSubstitutions = schema.blockForNode(node, self._DM_Map) 2435 self.__final = schema.finalForNode(node, self._DM_Map) 2436 2437 attr_val = domutils.NodeAttribute(node, 'abstract') 2438 if attr_val is not None: 2439 self.__abstract = datatypes.boolean(attr_val) 2440 2441 # Assume we're in the short-hand case: the entire content is 2442 # implicitly wrapped in a complex restriction of the ur-type. 2443 definition_node_list = node.childNodes 2444 is_complex_content = True 2445 self.__baseTypeDefinition = ComplexTypeDefinition.UrTypeDefinition() 2446 method = self.DM_restriction 2447 2448 # Determine whether above assumption is correct by looking for 2449 # element content and seeing if it's one of the wrapper 2450 # elements. 2451 first_elt = domutils.LocateFirstChildElement(node) 2452 content_node = None 2453 clause2_std = None 2454 ctsc_restriction_node = None 2455 if first_elt: 2456 have_content = False 2457 if xsd.nodeIsNamed(first_elt, 'simpleContent'): 2458 have_content = True 2459 is_complex_content = False 2460 elif xsd.nodeIsNamed(first_elt, 'complexContent'): 2461 have_content = True 2462 else: 2463 # Not one of the wrappers; use implicit wrapper around 2464 # the children 2465 if not Particle.IsParticleNode(first_elt, 'attributeGroup', 'attribute', 'anyAttribute'): 2466 raise pyxb.SchemaValidationError('Unexpected element %s at root of complexType' % (first_elt.nodeName,)) 2467 if have_content: 2468 # Repeat the search to verify that only the one child is present. 2469 content_node = domutils.LocateFirstChildElement(node, require_unique=True) 2470 assert content_node == first_elt 2471 2472 # Identify the contained restriction or extension 2473 # element, and extract the base type. 2474 ions = domutils.LocateFirstChildElement(content_node, absent_ok=False) 2475 if xsd.nodeIsNamed(ions, 'restriction'): 2476 method = self.DM_restriction 2477 if not is_complex_content: 2478 # Clause 2 of complex type with simple content 2479 ctsc_restriction_node = ions 2480 ions_st = domutils.LocateUniqueChild(ions,'simpleType') 2481 if ions_st is not None: 2482 clause2_std = SimpleTypeDefinition.CreateFromDOM(ions_st, **kw) 2483 elif xsd.nodeIsNamed(ions, 'extension'): 2484 method = self.DM_extension 2485 else: 2486 raise pyxb.SchemaValidationError('Expected restriction or extension as sole child of %s in %s' % (content_node.nodeName, self.name())) 2487 self.__baseExpandedName = domutils.NodeAttributeQName(ions, 'base') 2488 if self.__baseExpandedName is None: 2489 raise pyxb.SchemaValidationError('Element %s missing base attribute' % (ions.nodeName,)) 2490 self.__baseTypeDefinition = None 2491 # The content is defined by the restriction/extension element 2492 definition_node_list = ions.childNodes 2493 self.__derivationMethod = method 2494 self.__isComplexContent = is_complex_content 2495 self.__ctscRestrictionNode = ctsc_restriction_node 2496 self.__ctscClause2STD = clause2_std 2497 2498 (attributes, attribute_group_names, any_attribute) = self._attributeRelevantChildren(definition_node_list) 2499 self.__usesC1 = set() 2500 for cn in attributes: 2501 au = AttributeUse.CreateFromDOM(cn, **kw) 2502 self.__usesC1.add(au) 2503 self.__attributeGroupNames = attribute_group_names 2504 self.__anyAttribute = any_attribute 2505 2506 if self.__isComplexContent: 2507 self.__setComplexContentFromDOM(node, content_node, definition_node_list, self.__derivationMethod, **kw) 2508 2509 # Creation does not attempt to do resolution. Queue up the newly created 2510 # whatsis so we can resolve it after everything's been read in. 2511 self._annotationFromDOM(node) 2512 2513 if not self.isResolved(): 2514 self._queueForResolution('creation') 2515 2516 return self 2517 2518 # Resolution of a CTD can be delayed for the following reasons: 2519 # 2520 # * It extends or restricts a base type that has not been resolved 2521 # [_resolve] 2522 # 2523 # * It refers to an attribute or attribute group that has not been 2524 # resolved [__completeProcessing] 2525 # 2526 # * It includes an attribute that matches in NCName and namespace 2527 # an unresolved attribute from the base type 2528 # [__completeProcessing] 2529 # 2530 # * The content model includes a particle which cannot be resolved 2531 # (so has not contributed any local element declarations). 2532 # res:CTD 2533 def _resolve (self): 2534 if self.isResolved(): 2535 return self 2536 2537 # @todo: implement prohibitedSubstitutions, final, annotations 2538 2539 # See whether we've resolved through to the base type 2540 if self.__baseTypeDefinition is None: 2541 base_type = self.__baseExpandedName.typeDefinition() 2542 if base_type is None: 2543 raise pyxb.SchemaValidationError('Cannot locate %s: need import?' % (self.__baseExpandedName,)) 2544 if not base_type.isResolved(): 2545 # Have to delay resolution until the type this 2546 # depends on is available. 2547 self._queueForResolution('unresolved base type %s' % (self.__baseExpandedName,), depends_on=base_type) 2548 return self 2549 self.__baseTypeDefinition = base_type 2550 2551 # Only build the content once. This will not complete if the content 2552 # is a restriction of an unresolved simple type; otherwise, it only 2553 # depends on the base type which we know is good. 2554 if self.__contentType is None: 2555 if self.__isComplexContent: 2556 content_type = self.__complexContent(self.__derivationMethod) 2557 self.__contentStyle = 'complex' 2558 else: 2559 # The definition node list is not relevant to simple content 2560 content_type = self.__simpleContent(self.__derivationMethod) 2561 if content_type is None: 2562 self._queueForResolution('restriction of unresolved simple type') 2563 return self 2564 self.__contentStyle = 'simple' 2565 assert content_type is not None 2566 self.__contentType = content_type 2567 2568 # Last chance for failure is if we haven't been able to 2569 # extract all the element declarations that might appear in 2570 # this complex type. That technically wouldn't stop this from 2571 # being resolved, but it does prevent us from using it as a 2572 # context. 2573 if isinstance(self.__contentType, tuple) and isinstance(self.__contentType[1], Particle): 2574 prt = self.__contentType[1] 2575 if not prt.isAdaptable(self): 2576 self._queueForResolution('content particle %s is not deep-resolved' % (prt,)) 2577 return self 2578 self.__contentType = (self.__contentType[0], prt._adaptForScope(self, self)) 2579 2580 return self.__completeProcessing(self.__derivationMethod, self.__contentStyle) 2581 2582 def pythonSupport (self): 2583 """Complex type definitions have no built-in type support.""" 2584 return None 2585 2586 def __str__ (self): 2587 if self.isAnonymous(): 2588 return 'CTD{Anonymous}[%x]' % (id(self),) 2589 return 'CTD[%s]' % (self.expandedName(),) 2590 2591class _UrTypeDefinition (ComplexTypeDefinition, _Singleton_mixin): 2592 """Subclass ensures there is only one ur-type.""" 2593 def pythonSupport (self): 2594 """The ur-type does have a Python class backing it up.""" 2595 return datatypes.anyType 2596 2597 def _resolve (self): 2598 # The ur type is always resolved, except when it gets unresolved 2599 # through being updated from an instance read from the schema. 2600 return self._setDerivationMethod(self.DM_restriction) 2601 2602 2603class AttributeGroupDefinition (_SchemaComponent_mixin, _NamedComponent_mixin, pyxb.namespace.resolution._Resolvable_mixin, _Annotated_mixin, _AttributeWildcard_mixin): 2604 """An XMLSchema U{Attribute Group Definition<http://www.w3.org/TR/xmlschema-1/#cAttribute_Group_Definitions>} component.""" 2605 __PrivateTransient = set() 2606 2607 # A frozenset of AttributeUse instances 2608 __attributeUses = None 2609 2610 def __init__ (self, *args, **kw): 2611 super(AttributeGroupDefinition, self).__init__(*args, **kw) 2612 #assert 'scope' in kw 2613 #assert self._scopeIsIndeterminate() 2614 2615 def __str__ (self): 2616 return 'AGD[%s]' % (self.expandedName(),) 2617 2618 @classmethod 2619 def CreateBaseInstance (cls, name, schema, attribute_uses): 2620 """Create an attribute declaration component for a specified namespace.""" 2621 kw = { 'name' : name, 2622 'schema' : schema, 2623 'namespace_context' : schema.targetNamespace().initialNamespaceContext(), 2624 'scope' : _ScopedDeclaration_mixin.SCOPE_global } 2625 bi = cls(**kw) 2626 bi.__attributeUses = frozenset(attribute_uses) 2627 bi.__isResolved = True 2628 return bi 2629 2630 __anyAttribute = None 2631 __attributeGroupNames = None 2632 __PrivateTransient.update(['anyAttribute', 'attributeGroupNames']) 2633 2634 # CFD:AGD CFD:AttributeGroupDefinition 2635 @classmethod 2636 def CreateFromDOM (cls, node, **kw): 2637 """Create an attribute group definition from the given DOM node. 2638 2639 """ 2640 2641 assert xsd.nodeIsNamed(node, 'attributeGroup') 2642 name = domutils.NodeAttribute(node, 'name') 2643 2644 # Attribute group definitions can only appear at the top level of the 2645 # schema, and any definitions in them are scope indeterminate until 2646 # they're referenced in a complex type. 2647 kw.update({ 'scope' : _ScopedDeclaration_mixin.XSCOPE_indeterminate }) 2648 rv = cls(name=name, node=node, **kw) 2649 2650 rv._annotationFromDOM(node) 2651 2652 # Attribute group definitions must not be references 2653 if domutils.NodeAttribute(node, 'ref'): 2654 raise pyxb.SchemaValidationError('Attribute reference at top level') 2655 2656 kw.pop('node', None) 2657 kw['owner'] = rv 2658 2659 (attributes, attribute_group_names, any_attribute) = rv._attributeRelevantChildren(node.childNodes) 2660 rv.__attributeUses = set() 2661 for cn in attributes: 2662 rv.__attributeUses.add(AttributeUse.CreateFromDOM(cn, **kw)) 2663 rv.__attributeGroupNames = attribute_group_names 2664 rv.__anyAttribute = any_attribute 2665 2666 # Unconditionally queue for resolution, to avoid repeating the 2667 # wildcard code. 2668 rv._queueForResolution('creation') 2669 2670 return rv 2671 2672 # Indicates whether we have resolved any references 2673 __isResolved = False 2674 def isResolved (self): 2675 return self.__isResolved 2676 2677 def _resolve (self): 2678 if self.__isResolved: 2679 return self 2680 2681 uses = self.__attributeUses 2682 attribute_groups = [] 2683 for ag_en in self.__attributeGroupNames: 2684 agd = ag_en.attributeGroupDefinition() 2685 if agd is None: 2686 raise pyxb.SchemaValidationError('Attribute group %s cannot be found' % (ag_en,)) 2687 if not agd.isResolved(): 2688 self._queueForResolution('attributeGroup %s not resolved' % (ag_en,)) 2689 return self 2690 attribute_groups.append(agd) 2691 uses = uses.union(agd.attributeUses()) 2692 2693 self.__attributeUses = frozenset(uses) 2694 2695 # "Complete wildcard" per CTD 2696 local_wildcard = None 2697 if self.__anyAttribute is not None: 2698 local_wildcard = Wildcard.CreateFromDOM(self.__anyAttribute) 2699 self._setAttributeWildcard(_AttributeWildcard_mixin.CompleteWildcard(self._namespaceContext(), attribute_groups, local_wildcard)) 2700 2701 self.__isResolved = True 2702 return self 2703 2704 # bR:AGD 2705 def _bindingRequires_vx (self, include_lax): 2706 """Attribute group declarations require their uses, but only if lax.""" 2707 if not include_lax: 2708 return frozenset() 2709 return frozenset(self.attributeUses()) 2710 2711 def attributeUses (self): 2712 return self.__attributeUses 2713 2714class ModelGroupDefinition (_SchemaComponent_mixin, _NamedComponent_mixin, _Annotated_mixin): 2715 """An XMLSchema U{Model Group Definition<http://www.w3.org/TR/xmlschema-1/#cModel_Group_Definitions>} component.""" 2716 # Reference to a _ModelGroup 2717 __modelGroup = None 2718 2719 def modelGroup (self): 2720 """The model group for which this definition provides a name.""" 2721 return self.__modelGroup 2722 2723 # CFD:MGD CFD:ModelGroupDefinition 2724 @classmethod 2725 def CreateFromDOM (cls, node, **kw): 2726 """Create a Model Group Definition from a DOM element node. 2727 2728 wxs is a Schema instance within which the model group is being 2729 defined. 2730 2731 node is a DOM element. The name must be 'group', and the node 2732 must be in the XMLSchema namespace. The node must have a 2733 'name' attribute, and must not have a 'ref' attribute. 2734 """ 2735 assert xsd.nodeIsNamed(node, 'group') 2736 2737 assert domutils.NodeAttribute(node, 'ref') is None 2738 2739 name = domutils.NodeAttribute(node, 'name') 2740 kw['scope'] = _ScopedDeclaration_mixin.XSCOPE_indeterminate 2741 rv = cls(name=name, node=node, **kw) 2742 rv._annotationFromDOM(node) 2743 2744 kw.pop('node', None) 2745 kw['owner'] = rv 2746 2747 for cn in node.childNodes: 2748 if Node.ELEMENT_NODE != cn.nodeType: 2749 continue 2750 if ModelGroup.IsGroupMemberNode(cn): 2751 assert not rv.__modelGroup 2752 # Model group definitions always occur at the top level of the 2753 # schema, so the elements declared in them are not bound to a 2754 # scope until they are referenced in a complex type. 2755 rv.__modelGroup = ModelGroup.CreateFromDOM(cn, model_group_definition=rv, **kw) 2756 assert rv.__modelGroup is not None 2757 return rv 2758 2759 # bR:MGD 2760 def _bindingRequires_vx (self, include_lax): 2761 """Model group definitions depend on the contained model group.""" 2762 if not include_lax: 2763 return frozenset() 2764 return frozenset([self.__modelGroup]) 2765 2766 def __str__ (self): 2767 return 'MGD[%s: %s]' % (self.name(), self.modelGroup()) 2768 2769 2770class ModelGroup (_ParticleTree_mixin, _SchemaComponent_mixin, _Annotated_mixin): 2771 """An XMLSchema U{Model Group<http://www.w3.org/TR/xmlschema-1/#cModel_Group>} component.""" 2772 C_INVALID = 0 2773 C_ALL = 0x01 2774 C_CHOICE = 0x02 2775 C_SEQUENCE = 0x03 2776 2777 # One of the C_* values above. Set at construction time from the 2778 # keyword parameter "compositor". 2779 __compositor = C_INVALID 2780 def compositor (self): 2781 return self.__compositor 2782 2783 @classmethod 2784 def CompositorToString (cls, compositor): 2785 """Map a compositor value to a string.""" 2786 if cls.C_ALL == compositor: 2787 return 'all' 2788 if cls.C_CHOICE == compositor: 2789 return 'choice' 2790 if cls.C_SEQUENCE == compositor: 2791 return 'sequence' 2792 return 'invalid' 2793 2794 def compositorToString (self): 2795 """Return a string representing the compositor value.""" 2796 return self.CompositorToString(self.__compositor) 2797 2798 # A list of Particle instances. Set at construction time from 2799 # the keyword parameter "particles". 2800 __particles = None 2801 def particles (self): 2802 return self.__particles 2803 2804 def isAdaptable (self, ctd): 2805 """A model group has an unresolvable particle if any of its 2806 particles is unresolvable. Duh.""" 2807 for p in self.particles(): 2808 if not p.isAdaptable(ctd): 2809 return False 2810 return True 2811 2812 def effectiveTotalRange (self, particle): 2813 """Return the minimum and maximum of the number of elements that can 2814 appear in a sequence matched by this particle. 2815 2816 See U{http://www.w3.org/TR/xmlschema-1/#cos-seq-range} 2817 """ 2818 if self.__compositor in (self.C_ALL, self.C_SEQUENCE): 2819 sum_minoccurs = 0 2820 sum_maxoccurs = 0 2821 for prt in self.__particles: 2822 (prt_min, prt_max) = prt.effectiveTotalRange() 2823 sum_minoccurs += prt_min 2824 if sum_maxoccurs is not None: 2825 if prt_max is None: 2826 sum_maxoccurs = None 2827 else: 2828 sum_maxoccurs += prt_max 2829 prod_maxoccurs = particle.maxOccurs() 2830 if prod_maxoccurs is not None: 2831 if sum_maxoccurs is None: 2832 prod_maxoccurs = None 2833 else: 2834 prod_maxoccurs *= sum_maxoccurs 2835 return (sum_minoccurs * particle.minOccurs(), prod_maxoccurs) 2836 assert self.__compositor == self.C_CHOICE 2837 if 0 == len(self.__particles): 2838 min_minoccurs = 0 2839 max_maxoccurs = 0 2840 else: 2841 (min_minoccurs, max_maxoccurs) = self.__particles[0].effectiveTotalRange() 2842 for prt in self.__particles[1:]: 2843 (prt_min, prt_max) = prt.effectiveTotalRange() 2844 if prt_min < min_minoccurs: 2845 min_minoccurs = prt_min 2846 if prt_max is None: 2847 max_maxoccurs = None 2848 elif (max_maxoccurs is not None) and (prt_max > max_maxoccurs): 2849 max_maxoccurs = prt_max 2850 min_minoccurs *= particle.minOccurs() 2851 if (max_maxoccurs is not None) and (particle.maxOccurs() is not None): 2852 max_maxoccurs *= particle.maxOccurs() 2853 return (min_minoccurs, max_maxoccurs) 2854 2855 # The ModelGroupDefinition that names this ModelGroup, or None if 2856 # the ModelGroup is anonymous. This is set at construction time 2857 # from the keyword parameter "model_group_definition". 2858 __modelGroupDefinition = None 2859 def modelGroupDefinition (self): 2860 """The ModelGroupDefinition that names this group, or None if it is unnamed.""" 2861 return self.__modelGroupDefinition 2862 2863 def __init__ (self, compositor, particles, *args, **kw): 2864 """Create a new model group. 2865 2866 compositor must be a legal compositor value (one of C_ALL, C_CHOICE, C_SEQUENCE). 2867 2868 particles must be a list of zero or more Particle instances. 2869 2870 scope is the _ScopeDeclaration_mixin context into which new 2871 declarations are recorded. It can be SCOPE_global, a complex 2872 type definition, or None if this is (or is within) a named 2873 model group. 2874 2875 model_group_definition is an instance of ModelGroupDefinition 2876 if this is a named model group. It defaults to None 2877 indicating a local group. 2878 """ 2879 2880 super(ModelGroup, self).__init__(*args, **kw) 2881 assert 'scope' in kw 2882 self.__compositor = compositor 2883 self.__particles = particles 2884 self.__modelGroupDefinition = kw.get('model_group_definition') 2885 2886 def hasWildcardElement (self): 2887 """Return True if the model includes a wildcard amongst its particles.""" 2888 for p in self.particles(): 2889 if p.hasWildcardElement(): 2890 return True 2891 return False 2892 2893 # bR:MG 2894 def _bindingRequires_vx (self, include_lax): 2895 if not include_lax: 2896 return frozenset() 2897 return frozenset(self.__particles) 2898 2899 # CFD:MG CFD:ModelGroup 2900 @classmethod 2901 def CreateFromDOM (cls, node, **kw): 2902 """Create a model group from the given DOM node. 2903 2904 wxs is a Schema instance within which the model group is being 2905 defined. 2906 2907 node is a DOM element. The name must be one of ( 'all', 2908 'choice', 'sequence' ), and the node must be in the XMLSchema 2909 namespace. 2910 2911 scope is the _ScopeDeclaration_mxin context that is assigned 2912 to declarations that appear within the model group. It can be 2913 None, indicating no scope defined, or a complex type 2914 definition. 2915 """ 2916 2917 scope = kw['scope'] 2918 assert _ScopedDeclaration_mixin.ScopeIsIndeterminate(scope) or isinstance(scope, ComplexTypeDefinition) 2919 2920 if xsd.nodeIsNamed(node, 'all'): 2921 compositor = cls.C_ALL 2922 elif xsd.nodeIsNamed(node, 'choice'): 2923 compositor = cls.C_CHOICE 2924 else: 2925 assert xsd.nodeIsNamed(node, 'sequence') 2926 compositor = cls.C_SEQUENCE 2927 particles = [] 2928 # Remove the owner from particle constructor arguments: we need to set it later 2929 kw.pop('owner', None) 2930 for cn in node.childNodes: 2931 if Node.ELEMENT_NODE != cn.nodeType: 2932 continue 2933 if Particle.IsParticleNode(cn): 2934 # NB: Ancestor of particle is set in the ModelGroup constructor 2935 particle = Particle.CreateFromDOM(node=cn, **kw); 2936 if 0 == particle.maxOccurs(): 2937 if getattr(cn, '_location', False): 2938 location = ' at ' + str(cn._location()); 2939 else: 2940 location = ''; 2941 _log.warning('Particle %s%s discarded due to maxOccurs 0' % (particle, location)) 2942 else: 2943 particles.append(particle) 2944 elif not xsd.nodeIsNamed(cn, 'annotation'): 2945 raise pyxb.SchemaValidationError('Unexpected element %s in model group' % (cn.nodeName,)) 2946 rv = cls(compositor, particles, node=node, **kw) 2947 for p in particles: 2948 p._setOwner(rv) 2949 rv._annotationFromDOM(node) 2950 return rv 2951 2952 @classmethod 2953 def IsGroupMemberNode (cls, node): 2954 return xsd.nodeIsNamed(node, 'all', 'choice', 'sequence') 2955 2956 # aFS:MG 2957 def _adaptForScope (self, owner, ctd): 2958 rv = self 2959 assert isinstance(ctd, ComplexTypeDefinition) 2960 maybe_rv = self._clone(owner, ctd._objectOrigin()) 2961 scoped_particles = [ _p._adaptForScope(maybe_rv, ctd) for _p in self.particles() ] 2962 do_clone = (self._scope() != ctd) or (self.particles() != scoped_particles) 2963 if do_clone: 2964 rv = maybe_rv 2965 rv.__particles = scoped_particles 2966 return rv 2967 2968 def _walkParticleTree (self, visit, arg): 2969 visit(self, True, arg) 2970 for p in self.particles(): 2971 p._walkParticleTree(visit, arg) 2972 visit(self, False, arg) 2973 2974 def __str__ (self): 2975 comp = None 2976 if self.C_ALL == self.compositor(): 2977 comp = 'ALL' 2978 elif self.C_CHOICE == self.compositor(): 2979 comp = 'CHOICE' 2980 elif self.C_SEQUENCE == self.compositor(): 2981 comp = 'SEQUENCE' 2982 return '%s:(%s)' % (comp, six.u(',').join( [ six.text_type(_p) for _p in self.particles() ] ) ) 2983 2984class Particle (_ParticleTree_mixin, _SchemaComponent_mixin, pyxb.namespace.resolution._Resolvable_mixin): 2985 """An XMLSchema U{Particle<http://www.w3.org/TR/xmlschema-1/#cParticle>} component.""" 2986 2987 # The minimum number of times the term may appear. 2988 __minOccurs = 1 2989 def minOccurs (self): 2990 """The minimum number of times the term may appear. 2991 2992 Defaults to 1.""" 2993 return self.__minOccurs 2994 2995 # Upper limit on number of times the term may appear. 2996 __maxOccurs = 1 2997 def maxOccurs (self): 2998 """Upper limit on number of times the term may appear. 2999 3000 If None, the term may appear any number of times; otherwise, 3001 this is an integral value indicating the maximum number of times 3002 the term may appear. The default value is 1; the value, unless 3003 None, must always be at least minOccurs(). 3004 """ 3005 return self.__maxOccurs 3006 3007 # A reference to a ModelGroup, WildCard, or ElementDeclaration 3008 __term = None 3009 def term (self): 3010 """A reference to a ModelGroup, Wildcard, or ElementDeclaration.""" 3011 return self.__term 3012 __pendingTerm = None 3013 3014 __refExpandedName = None 3015 __resolvableType = None 3016 3017 def effectiveTotalRange (self): 3018 """Extend the concept of effective total range to all particles. 3019 3020 See U{http://www.w3.org/TR/xmlschema-1/#cos-seq-range} and 3021 U{http://www.w3.org/TR/xmlschema-1/#cos-choice-range} 3022 """ 3023 if isinstance(self.__term, ModelGroup): 3024 return self.__term.effectiveTotalRange(self) 3025 return (self.minOccurs(), self.maxOccurs()) 3026 3027 def isEmptiable (self): 3028 """Return C{True} iff this particle can legitimately match an empty 3029 sequence (no content). 3030 3031 See U{http://www.w3.org/TR/xmlschema-1/#cos-group-emptiable} 3032 """ 3033 return 0 == self.effectiveTotalRange()[0] 3034 3035 def hasWildcardElement (self): 3036 """Return True iff this particle has a wildcard in its term. 3037 3038 Note that the wildcard may be in a nested model group.""" 3039 return self.term().hasWildcardElement() 3040 3041 def __init__ (self, term, *args, **kw): 3042 """Create a particle from the given DOM node. 3043 3044 term is a XML Schema Component: one of ModelGroup, 3045 ElementDeclaration, and Wildcard. 3046 3047 The following keyword arguments are processed: 3048 3049 min_occurs is a non-negative integer value with default 1, 3050 denoting the minimum number of terms required by the content 3051 model. 3052 3053 max_occurs is a positive integer value with default 1, or None 3054 indicating unbounded, denoting the maximum number of terms 3055 allowed by the content model. 3056 3057 scope is the _ScopeDeclaration_mxin context that is assigned 3058 to declarations that appear within the particle. It can be 3059 None, indicating no scope defined, or a complex type 3060 definition. 3061 """ 3062 3063 super(Particle, self).__init__(*args, **kw) 3064 3065 min_occurs = kw.get('min_occurs', 1) 3066 max_occurs = kw.get('max_occurs', 1) 3067 3068 assert 'scope' in kw 3069 assert (self._scopeIsIndeterminate()) or isinstance(self._scope(), ComplexTypeDefinition) 3070 3071 if term is not None: 3072 self.__term = term 3073 3074 assert isinstance(min_occurs, six.integer_types) 3075 self.__minOccurs = min_occurs 3076 assert (max_occurs is None) or isinstance(max_occurs, six.integer_types) 3077 self.__maxOccurs = max_occurs 3078 if self.__maxOccurs is not None: 3079 if self.__minOccurs > self.__maxOccurs: 3080 raise pyxb.LogicError('Particle minOccurs %s is greater than maxOccurs %s on creation' % (min_occurs, max_occurs)) 3081 3082 # res:Particle 3083 def _resolve (self): 3084 if self.isResolved(): 3085 return self 3086 3087 # @RESOLUTION@ 3088 if ModelGroup == self.__resolvableType: 3089 group_decl = self.__refExpandedName.modelGroupDefinition() 3090 if group_decl is None: 3091 raise pyxb.SchemaValidationError('Model group reference %s cannot be found' % (self.__refExpandedName,)) 3092 3093 self.__pendingTerm = group_decl.modelGroup() 3094 assert self.__pendingTerm is not None 3095 elif ElementDeclaration == self.__resolvableType: 3096 # 3.9.2 says use 3.3.2, which is Element. The element inside a 3097 # particle is a localElement, so we either get the one it refers 3098 # to (which is top-level), or create a local one here. 3099 if self.__refExpandedName is not None: 3100 assert self.__pendingTerm is None 3101 self.__pendingTerm = self.__refExpandedName.elementDeclaration() 3102 if self.__pendingTerm is None: 3103 raise pyxb.SchemaValidationError('Unable to locate element referenced by %s' % (self.__refExpandedName,)) 3104 assert self.__pendingTerm is not None 3105 3106 # Whether this is a local declaration or one pulled in from the 3107 # global type definition symbol space, its name is now reserved in 3108 # this type. 3109 assert self.__pendingTerm is not None 3110 else: 3111 assert False 3112 3113 self.__term = self.__pendingTerm 3114 assert self.__term is not None 3115 3116 return self 3117 3118 def isResolved (self): 3119 return self.__term is not None 3120 3121 # CFD:Particle 3122 @classmethod 3123 def CreateFromDOM (cls, node, **kw): 3124 """Create a particle from the given DOM node. 3125 3126 wxs is a Schema instance within which the model group is being 3127 defined. 3128 3129 node is a DOM element. The name must be one of ( 'group', 3130 'element', 'any', 'all', 'choice', 'sequence' ), and the node 3131 must be in the XMLSchema namespace. 3132 3133 scope is the _ScopeDeclaration_mxin context that is assigned 3134 to declarations that appear within the model group. It can be 3135 None, indicating no scope defined, or a complex type 3136 definition. 3137 """ 3138 scope = kw['scope'] 3139 assert _ScopedDeclaration_mixin.ScopeIsIndeterminate(scope) or isinstance(scope, ComplexTypeDefinition) 3140 3141 kw.update({ 'min_occurs' : 1 3142 , 'max_occurs' : 1 3143 , 'node' : node }) 3144 3145 if not Particle.IsParticleNode(node): 3146 raise pyxb.LogicError('Attempted to create particle from illegal element %s' % (node.nodeName,)) 3147 attr_val = domutils.NodeAttribute(node, 'minOccurs') 3148 if attr_val is not None: 3149 kw['min_occurs'] = datatypes.nonNegativeInteger(attr_val) 3150 attr_val = domutils.NodeAttribute(node, 'maxOccurs') 3151 if attr_val is not None: 3152 if 'unbounded' == attr_val: 3153 kw['max_occurs'] = None 3154 else: 3155 kw['max_occurs'] = datatypes.nonNegativeInteger(attr_val) 3156 3157 rv = cls(None, **kw) 3158 3159 kw.pop('node', None) 3160 kw['owner'] = rv 3161 3162 rv.__refExpandedName = domutils.NodeAttributeQName(node, 'ref') 3163 rv.__pendingTerm = None 3164 rv.__resolvableType = None 3165 if xsd.nodeIsNamed(node, 'group'): 3166 # 3.9.2 says use 3.8.2, which is ModelGroup. The group 3167 # inside a particle is a groupRef. If there is no group 3168 # with that name, this throws an exception as expected. 3169 if rv.__refExpandedName is None: 3170 raise pyxb.SchemaValidationError('group particle without reference') 3171 rv.__resolvableType = ModelGroup 3172 elif xsd.nodeIsNamed(node, 'element'): 3173 if rv.__refExpandedName is None: 3174 schema = kw.get('schema') 3175 assert schema is not None 3176 target_namespace = schema.targetNamespaceForNode(node, ElementDeclaration) 3177 incoming_tns = kw.get('target_namespace') 3178 if incoming_tns is not None: 3179 assert incoming_tns == target_namespace 3180 else: 3181 kw['target_namespace'] = target_namespace 3182 rv.__term = ElementDeclaration.CreateFromDOM(node=node, **kw) 3183 else: 3184 # NOTE: 3.3.3 clause 2.2 specifies that if ref is used, all 3185 # the other configuration attributes like nillable and default 3186 # must be absent. 3187 for tag in ('nillable', 'default', 'fixed', 'form', 'block', 'type'): 3188 av = domutils.NodeAttribute(node, tag) 3189 if av is not None: 3190 raise pyxb.SchemaValidationError('element with "ref" cannot have "%s"' % (tag,)) 3191 rv.__resolvableType = ElementDeclaration 3192 assert not xsd.nodeIsNamed(node.parentNode, 'schema') 3193 elif xsd.nodeIsNamed(node, 'any'): 3194 # 3.9.2 says use 3.10.2, which is Wildcard. 3195 rv.__term = Wildcard.CreateFromDOM(node=node) 3196 elif ModelGroup.IsGroupMemberNode(node): 3197 # Choice, sequence, and all inside a particle are explicit 3198 # groups (or a restriction of explicit group, in the case 3199 # of all) 3200 rv.__term = ModelGroup.CreateFromDOM(node, **kw) 3201 else: 3202 raise pyxb.LogicError('Unhandled node in Particle.CreateFromDOM: %s' % (node.toxml("utf-8"),)) 3203 3204 if not rv.isResolved(): 3205 rv._queueForResolution('creation') 3206 return rv 3207 3208 # bR:PRT 3209 def _bindingRequires_vx (self, include_lax): 3210 if not include_lax: 3211 return frozenset() 3212 return frozenset([ self.__term ]) 3213 3214 # aFS:PRT 3215 def _adaptForScope (self, owner, ctd): 3216 rv = self 3217 assert isinstance(ctd, ComplexTypeDefinition) 3218 maybe_rv = self._clone(owner, ctd._objectOrigin()) 3219 term = rv.__term._adaptForScope(maybe_rv, ctd) 3220 do_clone = (self._scope() != ctd) or (rv.__term != term) 3221 if do_clone: 3222 rv = maybe_rv 3223 rv.__term = term 3224 return rv 3225 3226 def isAdaptable (self, ctd): 3227 """A particle has an unresolvable particle if it cannot be 3228 resolved, or if it has resolved to a term which is a model 3229 group that has an unresolvable particle. 3230 """ 3231 if not self.isResolved(): 3232 return False 3233 return self.term().isAdaptable(ctd) 3234 3235 def walkParticleTree (self, visit, arg): 3236 """The entry-point to walk a particle tree defining a content model. 3237 3238 See L{_ParticleTree_mixin._walkParticleTree}.""" 3239 self._walkParticleTree(visit, arg) 3240 3241 def _walkParticleTree (self, visit, arg): 3242 visit(self, True, arg) 3243 self.__term._walkParticleTree(visit, arg) 3244 visit(self, False, arg) 3245 3246 @classmethod 3247 def IsTypedefNode (cls, node): 3248 return xsd.nodeIsNamed(node, 'group', 'all', 'choice', 'sequence') 3249 3250 @classmethod 3251 def IsParticleNode (cls, node, *others): 3252 return xsd.nodeIsNamed(node, 'group', 'all', 'choice', 'sequence', 'element', 'any', *others) 3253 3254 def __str__ (self): 3255 #return 'PART{%s:%d,%s}' % (self.term(), self.minOccurs(), self.maxOccurs()) 3256 return 'PART{%s:%d,%s}[%x]' % ('TERM', self.minOccurs(), self.maxOccurs(), id(self)) 3257 3258 3259# 3.10.1 3260class Wildcard (_ParticleTree_mixin, _SchemaComponent_mixin, _Annotated_mixin): 3261 """An XMLSchema U{Wildcard<http://www.w3.org/TR/xmlschema-1/#cParticle>} component.""" 3262 3263 NC_any = '##any' #<<< The namespace constraint "##any" 3264 NC_not = '##other' #<<< A flag indicating constraint "##other" 3265 NC_targetNamespace = '##targetNamespace' 3266 NC_local = '##local' 3267 3268 __namespaceConstraint = None 3269 def namespaceConstraint (self): 3270 """A constraint on the namespace for the wildcard. 3271 3272 Valid values are: 3273 - L{Wildcard.NC_any} 3274 - A tuple ( L{Wildcard.NC_not}, a_namespace ) 3275 - set(of_namespaces) 3276 3277 Note that namespace are represented by 3278 L{Namespace<pyxb.namespace.Namespace>} instances, not the URIs that 3279 actually define a namespace. Absence of a namespace is represented by 3280 C{None}, both in the "not" pair and in the set. 3281 """ 3282 return self.__namespaceConstraint 3283 3284 @classmethod 3285 def IntensionalUnion (cls, constraints): 3286 """http://www.w3.org/TR/xmlschema-1/#cos-aw-union""" 3287 assert 0 < len(constraints) 3288 o1 = constraints.pop(0) 3289 while 0 < len(constraints): 3290 o2 = constraints.pop(0) 3291 # 1 3292 if (o1 == o2): 3293 continue 3294 # 2 3295 if (cls.NC_any == o1) or (cls.NC_any == o2): 3296 o1 = cls.NC_any 3297 continue 3298 # 3 3299 if isinstance(o1, set) and isinstance(o2, set): 3300 o1 = o1.union(o2) 3301 continue 3302 # 4 3303 if (isinstance(o1, tuple) and isinstance(o2, tuple)) and (o1[1] != o2[1]): 3304 o1 = ( cls.NC_not, None ) 3305 continue 3306 # At this point, one must be a negated namespace and the 3307 # other a set. Identify them. 3308 c_tuple = None 3309 c_set = None 3310 if isinstance(o1, tuple): 3311 assert isinstance(o2, set) 3312 c_tuple = o1 3313 c_set = o2 3314 else: 3315 assert isinstance(o1, set) 3316 assert isinstance(o2, tuple) 3317 c_tuple = o2 3318 c_set = o1 3319 negated_ns = c_tuple[1] 3320 if negated_ns is not None: 3321 # 5.1 3322 if (negated_ns in c_set) and (None in c_set): 3323 o1 = cls.NC_any 3324 continue 3325 # 5.2 3326 if negated_ns in c_set: 3327 o1 = ( cls.NC_not, None ) 3328 continue 3329 # 5.3 3330 if None in c_set: 3331 raise pyxb.SchemaValidationError('Union of wildcard namespace constraints not expressible') 3332 o1 = c_tuple 3333 continue 3334 # 6 3335 if None in c_set: 3336 o1 = cls.NC_any 3337 else: 3338 o1 = ( cls.NC_not, None ) 3339 return o1 3340 3341 @classmethod 3342 def IntensionalIntersection (cls, constraints): 3343 """http://www.w3.org/TR/xmlschema-1/#cos-aw-intersect""" 3344 assert 0 < len(constraints) 3345 o1 = constraints.pop(0) 3346 while 0 < len(constraints): 3347 o2 = constraints.pop(0) 3348 # 1 3349 if (o1 == o2): 3350 continue 3351 # 2 3352 if (cls.NC_any == o1) or (cls.NC_any == o2): 3353 if cls.NC_any == o1: 3354 o1 = o2 3355 continue 3356 # 4 3357 if isinstance(o1, set) and isinstance(o2, set): 3358 o1 = o1.intersection(o2) 3359 continue 3360 if isinstance(o1, tuple) and isinstance(o2, tuple): 3361 ns1 = o1[1] 3362 ns2 = o2[1] 3363 # 5 3364 if (ns1 is not None) and (ns2 is not None) and (ns1 != ns2): 3365 raise pyxb.SchemaValidationError('Intersection of wildcard namespace constraints not expressible') 3366 # 6 3367 assert (ns1 is None) or (ns2 is None) 3368 if ns1 is None: 3369 assert ns2 is not None 3370 o1 = ( cls.NC_not, ns2 ) 3371 else: 3372 assert ns1 is not None 3373 o1 = ( cls.NC_not, ns1 ) 3374 continue 3375 # 3 3376 # At this point, one must be a negated namespace and the 3377 # other a set. Identify them. 3378 c_tuple = None 3379 c_set = None 3380 if isinstance(o1, tuple): 3381 assert isinstance(o2, set) 3382 c_tuple = o1 3383 c_set = o2 3384 else: 3385 assert isinstance(o1, set) 3386 assert isinstance(o2, tuple) 3387 c_tuple = o2 3388 c_set = o1 3389 negated_ns = c_tuple[1] 3390 if negated_ns in c_set: 3391 c_set.remove(negated_ns) 3392 if None in c_set: 3393 c_set.remove(None) 3394 o1 = c_set 3395 return o1 3396 3397 PC_skip = 'skip' #<<< No constraint is applied 3398 PC_lax = 'lax' #<<< Validate against available uniquely determined declaration 3399 PC_strict = 'strict' #<<< Validate against declaration or xsi:type which must be available 3400 3401 # One of PC_* 3402 __processContents = None 3403 def processContents (self): 3404 return self.__processContents 3405 3406 def hasWildcardElement (self): 3407 """Return True, since Wildcard components are wildcards.""" 3408 return True 3409 3410 def __init__ (self, *args, **kw): 3411 assert 0 == len(args) 3412 super(Wildcard, self).__init__(*args, **kw) 3413 self.__namespaceConstraint = kw['namespace_constraint'] 3414 self.__processContents = kw['process_contents'] 3415 3416 def isAdaptable (self, ctd): 3417 return True 3418 3419 def _walkParticleTree (self, visit, arg): 3420 visit(self, None, arg) 3421 3422 # aFS:WC 3423 def _adaptForScope (self, owner, ctd): 3424 """Wildcards are scope-independent; return self""" 3425 return self 3426 3427 # CFD:Wildcard 3428 @classmethod 3429 def CreateFromDOM (cls, node, **kw): 3430 namespace_context = pyxb.namespace.NamespaceContext.GetNodeContext(node) 3431 assert xsd.nodeIsNamed(node, 'any', 'anyAttribute') 3432 nc = domutils.NodeAttribute(node, 'namespace') 3433 if nc is None: 3434 namespace_constraint = cls.NC_any 3435 else: 3436 if cls.NC_any == nc: 3437 namespace_constraint = cls.NC_any 3438 elif cls.NC_not == nc: 3439 namespace_constraint = ( cls.NC_not, namespace_context.targetNamespace() ) 3440 else: 3441 ncs = set() 3442 for ns_uri in nc.split(): 3443 if cls.NC_local == ns_uri: 3444 ncs.add(None) 3445 elif cls.NC_targetNamespace == ns_uri: 3446 ncs.add(namespace_context.targetNamespace()) 3447 else: 3448 ncs.add(pyxb.namespace.NamespaceForURI(ns_uri, create_if_missing=True)) 3449 namespace_constraint = frozenset(ncs) 3450 3451 pc = domutils.NodeAttribute(node, 'processContents') 3452 if pc is None: 3453 process_contents = cls.PC_strict 3454 else: 3455 if pc in [ cls.PC_skip, cls.PC_lax, cls.PC_strict ]: 3456 process_contents = pc 3457 else: 3458 raise pyxb.SchemaValidationError('illegal value "%s" for any processContents attribute' % (pc,)) 3459 3460 rv = cls(node=node, namespace_constraint=namespace_constraint, process_contents=process_contents, **kw) 3461 rv._annotationFromDOM(node) 3462 return rv 3463 3464# 3.11.1 3465class IdentityConstraintDefinition (_SchemaComponent_mixin, _NamedComponent_mixin, _Annotated_mixin, pyxb.namespace.resolution._Resolvable_mixin): 3466 """An XMLSchema U{Identity Constraint Definition<http://www.w3.org/TR/xmlschema-1/#cIdentity-constraint_Definitions>} component.""" 3467 3468 ICC_KEY = 0x01 3469 ICC_KEYREF = 0x02 3470 ICC_UNIQUE = 0x04 3471 3472 __identityConstraintCategory = None 3473 def identityConstraintCategory (self): 3474 return self.__identityConstraintCategory 3475 3476 __selector = None 3477 def selector (self): 3478 return self.__selector 3479 3480 __fields = None 3481 def fields (self): 3482 return self.__fields 3483 3484 __referencedKey = None 3485 __referAttribute = None 3486 __icc = None 3487 3488 __annotations = None 3489 def annotations (self): 3490 return self.__annotations 3491 3492 # CFD:ICD CFD:IdentityConstraintDefinition 3493 @classmethod 3494 def CreateFromDOM (cls, node, **kw): 3495 name = domutils.NodeAttribute(node, 'name') 3496 scope = kw['scope'] 3497 assert _ScopedDeclaration_mixin.ScopeIsIndeterminate(scope) or _ScopedDeclaration_mixin.IsValidScope(scope) 3498 rv = cls(name=name, node=node, **kw) 3499 3500 kw.pop('node', None) 3501 kw['owner'] = rv 3502 3503 #self._annotationFromDOM(node) 3504 rv.__isResolved = True 3505 icc = None 3506 if xsd.nodeIsNamed(node, 'key'): 3507 icc = rv.ICC_KEY 3508 elif xsd.nodeIsNamed(node, 'keyref'): 3509 icc = rv.ICC_KEYREF 3510 rv.__referAttribute = domutils.NodeAttribute(node, 'refer') 3511 if rv.__referAttribute is None: 3512 raise pyxb.SchemaValidationError('Require refer attribute on keyref elements') 3513 rv.__isResolved = False 3514 elif xsd.nodeIsNamed(node, 'unique'): 3515 icc = rv.ICC_UNIQUE 3516 else: 3517 raise pyxb.LogicError('Unexpected identity constraint node %s' % (node.toxml("utf-8"),)) 3518 rv.__icc = icc 3519 3520 cn = domutils.LocateUniqueChild(node, 'selector') 3521 rv.__selector = domutils.NodeAttribute(cn, 'xpath') 3522 if rv.__selector is None: 3523 raise pyxb.SchemaValidationError('selector element missing xpath attribute') 3524 3525 rv.__fields = [] 3526 for cn in domutils.LocateMatchingChildren(node, 'field'): 3527 xp_attr = domutils.NodeAttribute(cn, 'xpath') 3528 if xp_attr is None: 3529 raise pyxb.SchemaValidationError('field element missing xpath attribute') 3530 rv.__fields.append(xp_attr) 3531 3532 rv._annotationFromDOM(node) 3533 rv.__annotations = [] 3534 if rv.annotation() is not None: 3535 rv.__annotations.append(rv) 3536 3537 for cn in node.childNodes: 3538 if (Node.ELEMENT_NODE != cn.nodeType): 3539 continue 3540 an = None 3541 if xsd.nodeIsNamed(cn, 'selector', 'field'): 3542 an = domutils.LocateUniqueChild(cn, 'annotation') 3543 elif xsd.nodeIsNamed(cn, 'annotation'): 3544 an = cn 3545 if an is not None: 3546 rv.__annotations.append(Annotation.CreateFromDOM(an, **kw)) 3547 3548 rv.__identityConstraintCategory = icc 3549 if rv.ICC_KEYREF != rv.__identityConstraintCategory: 3550 rv._namespaceContext().targetNamespace().addCategoryObject('identityConstraintDefinition', rv.name(), rv) 3551 3552 if not rv.isResolved(): 3553 rv._queueForResolution('creation') 3554 return rv 3555 3556 __isResolved = False 3557 def isResolved (self): 3558 return self.__isResolved 3559 3560 # res:ICD res:IdentityConstraintDefinition 3561 def _resolve (self): 3562 if self.isResolved(): 3563 return self 3564 3565 icc = self.__icc 3566 if self.ICC_KEYREF == icc: 3567 refer_en = self._namespaceContext().interpretQName(self.__referAttribute) 3568 refer = refer_en.identityConstraintDefinition() 3569 if refer is None: 3570 self._queueForResolution('Identity constraint definition %s cannot be found' % (refer_en,), depends_on=refer) 3571 return self 3572 self.__referencedKey = refer 3573 self.__isResolved = True 3574 return self 3575 3576 # bR:ICD 3577 def _bindingRequires_vx (self, include_lax): 3578 """Constraint definitions that are by reference require the referenced constraint.""" 3579 rv = set() 3580 if include_lax and (self.__referencedKey is not None): 3581 rv.add(self.__referencedKey) 3582 return frozenset(rv) 3583 3584 3585 3586# 3.12.1 3587class NotationDeclaration (_SchemaComponent_mixin, _NamedComponent_mixin, _Annotated_mixin): 3588 """An XMLSchema U{Notation Declaration<http://www.w3.org/TR/xmlschema-1/#cNotation_Declarations>} component.""" 3589 __systemIdentifier = None 3590 def systemIdentifier (self): 3591 return self.__systemIdentifier 3592 3593 __publicIdentifier = None 3594 def publicIdentifier (self): 3595 return self.__publicIdentifier 3596 3597 # CFD:ND CFD:NotationDeclaration 3598 @classmethod 3599 def CreateFromDOM (cls, node, **kw): 3600 name = domutils.NodeAttribute(node, 'name') 3601 rv = cls(name=name, node=node, **kw) 3602 3603 rv.__systemIdentifier = domutils.NodeAttribute(node, 'system') 3604 rv.__publicIdentifier = domutils.NodeAttribute(node, 'public') 3605 3606 rv._annotationFromDOM(node) 3607 return rv 3608 3609 # bR:ND 3610 def _bindingRequires_vx (self, include_lax): 3611 return frozenset() 3612 3613# 3.13.1 3614class Annotation (_SchemaComponent_mixin): 3615 """An XMLSchema U{Annotation<http://www.w3.org/TR/xmlschema-1/#cAnnotation>} component.""" 3616 3617 __applicationInformation = None 3618 def applicationInformation (self): 3619 return self.__applicationInformation 3620 3621 __userInformation = None 3622 def userInformation (self): 3623 return self.__userInformation 3624 3625 # Define so superclasses can take keywords 3626 def __init__ (self, **kw): 3627 application_information = kw.pop('application_information', None) 3628 user_information = kw.pop('user_information', None) 3629 super(Annotation, self).__init__(**kw) 3630 if (user_information is not None) and (not isinstance(user_information, list)): 3631 user_information = [ six.text_type(user_information) ] 3632 if (application_information is not None) and (not isinstance(application_information, list)): 3633 application_information = [ six.text_type(application_information) ] 3634 self.__userInformation = user_information 3635 self.__applicationInformation = application_information 3636 3637 # @todo: what the hell is this? From 3.13.2, I think it's a place 3638 # to stuff attributes from the annotation element, which makes 3639 # sense, as well as from the annotation's parent element, which 3640 # doesn't. Apparently it's for attributes that don't belong to 3641 # the XMLSchema namespace; so maybe we're not supposed to add 3642 # those to the other components. Note that these are attribute 3643 # information items, not attribute uses. 3644 __attributes = None 3645 3646 # CFD:Annotation 3647 @classmethod 3648 def CreateFromDOM (cls, node, **kw): 3649 rv = cls(node=node, **kw) 3650 3651 # @todo:: Scan for attributes in the node itself that do not 3652 # belong to the XMLSchema namespace. 3653 3654 # Node should be an XMLSchema annotation node 3655 assert xsd.nodeIsNamed(node, 'annotation') 3656 app_info = [] 3657 user_info = [] 3658 for cn in node.childNodes: 3659 if xsd.nodeIsNamed(cn, 'appinfo'): 3660 app_info.append(cn) 3661 elif xsd.nodeIsNamed(cn, 'documentation'): 3662 user_info.append(cn) 3663 else: 3664 pass 3665 if 0 < len(app_info): 3666 rv.__applicationInformation = app_info 3667 if 0 < len(user_info): 3668 rv.__userInformation = user_info 3669 3670 return rv 3671 3672 __RemoveMultiQuote_re = re.compile('""+') 3673 def asDocString (self): 3674 """Return the text in a form suitable for embedding in a 3675 triple-double-quoted docstring. 3676 3677 Any sequence of two or more double quotes is replaced by a sequence of 3678 single quotes that is the same length. Following this, spaces are 3679 added at the start and the end as necessary to ensure a double quote 3680 does not appear in those positions.""" 3681 rv = self.text() 3682 rv = self.__RemoveMultiQuote_re.sub(lambda _mo: "'" * (_mo.end(0) - _mo.start(0)), rv) 3683 if rv.startswith('"'): 3684 rv = ' ' + rv 3685 if rv.endswith('"'): 3686 rv = rv + ' ' 3687 return rv 3688 3689 def text (self): 3690 if self.__userInformation is None: 3691 return '' 3692 text = [] 3693 # Values in userInformation are DOM "documentation" elements. 3694 # We want their combined content. 3695 for dn in self.__userInformation: 3696 for cn in dn.childNodes: 3697 if Node.TEXT_NODE == cn.nodeType: 3698 text.append(cn.data) 3699 return ''.join(text) 3700 3701 def __str__ (self): 3702 """Return the catenation of all user information elements in the 3703 annotation as a single unicode string. Returns the empty string if 3704 there are no user information elements.""" 3705 return self.text() 3706 3707# Section 3.14. 3708class SimpleTypeDefinition (_SchemaComponent_mixin, _NamedComponent_mixin, pyxb.namespace.resolution._Resolvable_mixin, _Annotated_mixin): 3709 """An XMLSchema U{Simple Type Definition<http://www.w3.org/TR/xmlschema-1/#Simple_Type_Definitions>} component.""" 3710 3711 # Reference to the SimpleTypeDefinition on which this is based. 3712 # The value must be non-None except for the simple ur-type 3713 # definition. 3714 __baseTypeDefinition = None 3715 def baseTypeDefinition (self): 3716 return self.__baseTypeDefinition 3717 3718 __memberTypes = None 3719 __itemTypeExpandedName = None 3720 __baseExpandedName = None 3721 __memberTypesExpandedNames = None 3722 __localFacets = None 3723 3724 # A map from a subclass of facets.Facet to an instance of that class. 3725 # Presence of a facet class as a key in this map is the indicator that the 3726 # type definition and its subtypes are permitted to use the corresponding 3727 # facet. All facets in force for this type are present in the map, 3728 # including those constraints inherited parent types. 3729 __facets = None 3730 def facets (self): 3731 assert (self.__facets is None) or isinstance(self.__facets, six.dictionary_type) 3732 return self.__facets 3733 3734 # The facets.FundamentalFacet instances that describe this type 3735 __fundamentalFacets = None 3736 def fundamentalFacets (self): 3737 """A frozenset of instances of facets.FundamentallFacet.""" 3738 return self.__fundamentalFacets 3739 3740 STD_empty = 0 #<<< Marker indicating an empty set of STD forms 3741 STD_extension = 0x01 #<<< Representation for extension in a set of STD forms 3742 STD_list = 0x02 #<<< Representation for list in a set of STD forms 3743 STD_restriction = 0x04 #<<< Representation of restriction in a set of STD forms 3744 STD_union = 0x08 #<<< Representation of union in a set of STD forms 3745 3746 _STD_Map = { 'extension' : STD_extension 3747 , 'list' : STD_list 3748 , 'restriction' : STD_restriction 3749 , 'union' : STD_union } 3750 3751 # Bitmask defining the subset that comprises the final property 3752 __final = STD_empty 3753 @classmethod 3754 def _FinalToString (cls, final_value): 3755 """Convert a final value to a string.""" 3756 tags = [] 3757 if final_value & cls.STD_extension: 3758 tags.append('extension') 3759 if final_value & cls.STD_list: 3760 tags.append('list') 3761 if final_value & cls.STD_restriction: 3762 tags.append('restriction') 3763 if final_value & cls.STD_union: 3764 tags.append('union') 3765 return ' '.join(tags) 3766 3767 VARIETY_absent = 0x01 #<<< Only used for the ur-type 3768 VARIETY_atomic = 0x02 #<<< Use for types based on a primitive type 3769 VARIETY_list = 0x03 #<<< Use for lists of atomic-variety types 3770 VARIETY_union = 0x04 #<<< Use for types that aggregate other types 3771 3772 # Derivation alternative 3773 _DA_empty = 'none specified' 3774 _DA_restriction = 'restriction' 3775 _DA_list = 'list' 3776 _DA_union = 'union' 3777 3778 def _derivationAlternative (self): 3779 return self.__derivationAlternative 3780 __derivationAlternative = None 3781 3782 # Identify the sort of value collection this holds. This field is 3783 # used to identify unresolved definitions. 3784 __variety = None 3785 def variety (self): 3786 return self.__variety 3787 @classmethod 3788 def VarietyToString (cls, variety): 3789 """Convert a variety value to a string.""" 3790 if cls.VARIETY_absent == variety: 3791 return 'absent' 3792 if cls.VARIETY_atomic == variety: 3793 return 'atomic' 3794 if cls.VARIETY_list == variety: 3795 return 'list' 3796 if cls.VARIETY_union == variety: 3797 return 'union' 3798 return '?NoVariety?' 3799 3800 # For atomic variety only, the root (excepting ur-type) type. 3801 __primitiveTypeDefinition = None 3802 def primitiveTypeDefinition (self, throw_if_absent=True): 3803 if throw_if_absent: 3804 assert self.VARIETY_atomic == self.variety() 3805 if self.__primitiveTypeDefinition is None: 3806 raise pyxb.LogicError('Expected primitive type for %s in %s', self, self.targetNamespace()) 3807 return self.__primitiveTypeDefinition 3808 3809 # For list variety only, the type of items in the list 3810 __itemTypeDefinition = None 3811 def itemTypeDefinition (self): 3812 assert self.VARIETY_list == self.variety() 3813 if self.__itemTypeDefinition is None: 3814 raise pyxb.LogicError('Expected item type') 3815 return self.__itemTypeDefinition 3816 3817 # For union variety only, the sequence of candidate members 3818 __memberTypeDefinitions = None 3819 def memberTypeDefinitions (self): 3820 assert self.VARIETY_union == self.variety() 3821 if self.__memberTypeDefinitions is None: 3822 raise pyxb.LogicError('Expected member types') 3823 return self.__memberTypeDefinitions 3824 3825 # bR:STD 3826 def _bindingRequires_vx (self, include_lax): 3827 """Implement base class method. 3828 3829 This STD depends on its baseTypeDefinition, unless its variety 3830 is absent. Other dependencies are on item, primitive, or 3831 member type definitions.""" 3832 type_definitions = set() 3833 if self != self.baseTypeDefinition(): 3834 type_definitions.add(self.baseTypeDefinition()) 3835 if self.VARIETY_absent == self.variety(): 3836 type_definitions = set() 3837 elif self.VARIETY_atomic == self.variety(): 3838 if self != self.primitiveTypeDefinition(): 3839 type_definitions.add(self.primitiveTypeDefinition()) 3840 elif self.VARIETY_list == self.variety(): 3841 assert self != self.itemTypeDefinition() 3842 type_definitions.add(self.itemTypeDefinition()) 3843 else: 3844 assert self.VARIETY_union == self.variety() 3845 assert self not in self.memberTypeDefinitions() 3846 type_definitions.update(self.memberTypeDefinitions()) 3847 # NB: This type also depends on the value type definitions for 3848 # any facets that apply to it. This fact only matters when 3849 # generating the datatypes_facets source. That, and the fact 3850 # that there are dependency loops (e.g., integer requires a 3851 # nonNegativeInteger for its length facet) means we don't 3852 # bother adding in those. 3853 return frozenset(type_definitions) 3854 3855 # A non-property field that holds a reference to the DOM node from 3856 # which the type is defined. The value is held only between the 3857 # point where the simple type definition instance is created until 3858 # the point it is resolved. 3859 __domNode = None 3860 3861 # Indicate that this instance was defined as a built-in rather 3862 # than from a DOM instance. 3863 __isBuiltin = False 3864 3865 # Allocate one of these. Users should use one of the Create* 3866 # factory methods instead. 3867 3868 def __init__ (self, *args, **kw): 3869 super(SimpleTypeDefinition, self).__init__(*args, **kw) 3870 self.__variety = kw['variety'] 3871 3872 def __setstate__ (self, state): 3873 """Extend base class unpickle support to retain link between 3874 this instance and the Python class that it describes. 3875 3876 This is because the pythonSupport value is a class reference, 3877 not an instance reference, so it wasn't deserialized, and its 3878 class member link was never set. 3879 """ 3880 super_fn = getattr(super(SimpleTypeDefinition, self), '__setstate__', lambda _state: self.__dict__.update(_state)) 3881 super_fn(state) 3882 if self.__pythonSupport is not None: 3883 self.__pythonSupport._SimpleTypeDefinition(self) 3884 3885 def __str__ (self): 3886 if self.name() is not None: 3887 elts = [ self.name(), ':' ] 3888 else: 3889 elts = [ '<anonymous>:' ] 3890 if self.VARIETY_absent == self.variety(): 3891 elts.append('the ur-type') 3892 elif self.VARIETY_atomic == self.variety(): 3893 elts.append('restriction of %s' % (self.baseTypeDefinition().name(),)) 3894 elif self.VARIETY_list == self.variety(): 3895 elts.append('list of %s' % (self.itemTypeDefinition().name(),)) 3896 elif self.VARIETY_union == self.variety(): 3897 elts.append('union of %s' % (six.u(' ').join([six.text_type(_mtd.name()) for _mtd in self.memberTypeDefinitions()],))) 3898 else: 3899 # Gets here if the type has not been resolved. 3900 elts.append('?') 3901 #raise pyxb.LogicError('Unexpected variety %s' % (self.variety(),)) 3902 if self.__facets: 3903 felts = [] 3904 for (k, v) in six.iteritems(self.__facets): 3905 if v is not None: 3906 felts.append(six.text_type(v)) 3907 elts.append(six.u('\n %s') % (','.join(felts),)) 3908 if self.__fundamentalFacets: 3909 elts.append("\n ") 3910 elts.append(six.u(',').join( [six.text_type(_f) for _f in self.__fundamentalFacets ])) 3911 return 'STD[%s]' % (''.join(elts),) 3912 3913 def _updateFromOther_csc (self, other): 3914 """Override fields in this instance with those from the other. 3915 3916 This method is invoked only by Schema._addNamedComponent, and 3917 then only when a built-in type collides with a schema-defined 3918 type. Material like facets is not (currently) held in the 3919 built-in copy, so the DOM information is copied over to the 3920 built-in STD, which is subsequently re-resolved. 3921 3922 Returns self. 3923 """ 3924 assert self != other 3925 assert self.isNameEquivalent(other) 3926 super(SimpleTypeDefinition, self)._updateFromOther_csc(other) 3927 3928 # The other STD should be an unresolved schema-defined type. 3929 assert other.__baseTypeDefinition is None, 'Update from resolved STD %s' % (other,) 3930 assert other.__domNode is not None 3931 self.__domNode = other.__domNode 3932 3933 # Preserve the python support 3934 if other.__pythonSupport is not None: 3935 # @todo: ERROR multiple references 3936 self.__pythonSupport = other.__pythonSupport 3937 3938 # Mark this instance as unresolved so it is re-examined 3939 self.__variety = None 3940 return self 3941 3942 def isBuiltin (self): 3943 """Indicate whether this simple type is a built-in type.""" 3944 return self.__isBuiltin 3945 3946 __SimpleUrTypeDefinition = None 3947 @classmethod 3948 def SimpleUrTypeDefinition (cls, schema=None, in_builtin_definition=False): 3949 """Create the SimpleTypeDefinition instance that approximates the simple ur-type. 3950 3951 See section 3.14.7.""" 3952 3953 #if in_builtin_definition and (cls.__SimpleUrTypeDefinition is not None): 3954 # raise pyxb.LogicError('Multiple definitions of SimpleUrType') 3955 if cls.__SimpleUrTypeDefinition is None: 3956 # Note: We use a singleton subclass 3957 assert schema is not None 3958 3959 ns_ctx = schema.targetNamespace().initialNamespaceContext() 3960 3961 kw = { 'name' : 'anySimpleType', 3962 'schema' : schema, 3963 'namespace_context' : ns_ctx, 3964 'binding_namespace' : schema.targetNamespace(), 3965 'variety' : cls.VARIETY_absent, 3966 'scope' : _ScopedDeclaration_mixin.SCOPE_global } 3967 bi = _SimpleUrTypeDefinition(**kw) 3968 bi._setPythonSupport(datatypes.anySimpleType) 3969 3970 # The baseTypeDefinition is the ur-type. 3971 bi.__baseTypeDefinition = ComplexTypeDefinition.UrTypeDefinition() 3972 bi.__derivationAlternative = cls._DA_restriction 3973 # The simple ur-type has an absent variety, not an atomic 3974 # variety, so does not have a primitiveTypeDefinition 3975 3976 # No facets on the ur type 3977 bi.__facets = {} 3978 bi.__fundamentalFacets = frozenset() 3979 3980 bi.__resolveBuiltin() 3981 3982 cls.__SimpleUrTypeDefinition = bi 3983 return cls.__SimpleUrTypeDefinition 3984 3985 @classmethod 3986 def _CreateXMLInstance (cls, name, schema): 3987 """Create STD instances for built-in types. 3988 3989 For example, xml:space is a restriction of NCName; xml:lang is a union. 3990 3991 """ 3992 from pyxb.binding import xml_ 3993 kw = { 'schema' : schema, 3994 'binding_namespace' : schema.targetNamespace(), 3995 'namespace_context' : schema.targetNamespace().initialNamespaceContext(), 3996 'scope' : _ScopedDeclaration_mixin.SCOPE_global, 3997 'variety' : cls.VARIETY_atomic } 3998 if 'space' == name: 3999 bi = cls(**kw) 4000 bi.__derivationAlternative = cls._DA_restriction 4001 bi.__baseTypeDefinition = datatypes.NCName.SimpleTypeDefinition() 4002 bi.__primitiveTypeDefinition = bi.__baseTypeDefinition.__primitiveTypeDefinition 4003 bi._setPythonSupport(xml_.STD_ANON_space) 4004 bi.setNameInBinding('STD_ANON_space') 4005 elif 'lang' == name: 4006 bi = cls(**kw) 4007 bi.__baseTypeDefinition = cls.SimpleUrTypeDefinition() 4008 bi.__memberTypes = [ datatypes.language.SimpleTypeDefinition() ] 4009 bi.__derivationAlternative = cls._DA_union 4010 bi.__primitiveTypeDefinition = bi 4011 bi._setPythonSupport(xml_.STD_ANON_lang) 4012 bi.setNameInBinding('STD_ANON_lang') 4013 else: 4014 raise pyxb.IncompleteImplementationError('No implementation for xml:%s' % (name,)) 4015 bi.__facets = { } 4016 for v in six.itervalues(bi.pythonSupport().__dict__): 4017 if isinstance(v, facets.ConstrainingFacet): 4018 bi.__facets[v.__class__] = v 4019 return bi 4020 4021 @classmethod 4022 def CreatePrimitiveInstance (cls, name, schema, python_support): 4023 """Create a primitive simple type in the target namespace. 4024 4025 This is mainly used to pre-load standard built-in primitive 4026 types, such as those defined by XMLSchema Datatypes. You can 4027 use it for your own schemas as well, if you have special types 4028 that require explicit support to for Pythonic conversion. 4029 4030 All parameters are required and must be non-None. 4031 """ 4032 4033 kw = { 'name' : name, 4034 'schema' : schema, 4035 'binding_namespace' : schema.targetNamespace(), 4036 'namespace_context' : schema.targetNamespace().initialNamespaceContext(), 4037 'scope' : _ScopedDeclaration_mixin.SCOPE_global, 4038 'variety' : cls.VARIETY_atomic } 4039 4040 bi = cls(**kw) 4041 bi._setPythonSupport(python_support) 4042 4043 # Primitive types are based on the ur-type, and have 4044 # themselves as their primitive type definition. 4045 bi.__derivationAlternative = cls._DA_restriction 4046 bi.__baseTypeDefinition = cls.SimpleUrTypeDefinition() 4047 bi.__primitiveTypeDefinition = bi 4048 4049 # Primitive types are built-in 4050 bi.__resolveBuiltin() 4051 assert bi.isResolved() 4052 return bi 4053 4054 @classmethod 4055 def CreateDerivedInstance (cls, name, schema, parent_std, python_support): 4056 """Create a derived simple type in the target namespace. 4057 4058 This is used to pre-load standard built-in derived types. You 4059 can use it for your own schemas as well, if you have special 4060 types that require explicit support to for Pythonic 4061 conversion. 4062 """ 4063 assert parent_std 4064 assert parent_std.__variety in (cls.VARIETY_absent, cls.VARIETY_atomic) 4065 kw = { 'name' : name, 4066 'schema' : schema, 4067 'binding_namespace' : schema.targetNamespace(), 4068 'namespace_context' : schema.targetNamespace().initialNamespaceContext(), 4069 'scope' : _ScopedDeclaration_mixin.SCOPE_global, 4070 'variety' : parent_std.__variety } 4071 4072 bi = cls(**kw) 4073 bi._setPythonSupport(python_support) 4074 4075 # We were told the base type. If this is atomic, we re-use 4076 # its primitive type. Note that these all may be in different 4077 # namespaces. 4078 bi.__baseTypeDefinition = parent_std 4079 bi.__derivationAlternative = cls._DA_restriction 4080 if cls.VARIETY_atomic == bi.__variety: 4081 bi.__primitiveTypeDefinition = bi.__baseTypeDefinition.__primitiveTypeDefinition 4082 4083 # Derived types are built-in 4084 bi.__resolveBuiltin() 4085 return bi 4086 4087 @classmethod 4088 def CreateListInstance (cls, name, schema, item_std, python_support): 4089 """Create a list simple type in the target namespace. 4090 4091 This is used to preload standard built-in list types. You can 4092 use it for your own schemas as well, if you have special types 4093 that require explicit support to for Pythonic conversion; but 4094 note that such support is identified by the item_std. 4095 """ 4096 4097 kw = { 'name' : name, 4098 'schema' : schema, 4099 'binding_namespace' : schema.targetNamespace(), 4100 'namespace_context' : schema.targetNamespace().initialNamespaceContext(), 4101 'scope' : _ScopedDeclaration_mixin.SCOPE_global, 4102 'variety' : cls.VARIETY_list } 4103 bi = cls(**kw) 4104 bi._setPythonSupport(python_support) 4105 4106 # The base type is the ur-type. We were given the item type. 4107 bi.__baseTypeDefinition = cls.SimpleUrTypeDefinition() 4108 assert item_std 4109 bi.__itemTypeDefinition = item_std 4110 4111 # List types are built-in 4112 bi.__resolveBuiltin() 4113 return bi 4114 4115 @classmethod 4116 def CreateUnionInstance (cls, name, schema, member_stds): 4117 """(Placeholder) Create a union simple type in the target namespace. 4118 4119 This function has not been implemented.""" 4120 raise pyxb.IncompleteImplementationError('No support for built-in union types') 4121 4122 def __singleSimpleTypeChild (self, body, other_elts_ok=False): 4123 simple_type_child = None 4124 for cn in body.childNodes: 4125 if (Node.ELEMENT_NODE == cn.nodeType): 4126 if not xsd.nodeIsNamed(cn, 'simpleType'): 4127 if other_elts_ok: 4128 continue 4129 raise pyxb.SchemaValidationError('Context requires element to be xs:simpleType') 4130 assert not simple_type_child 4131 simple_type_child = cn 4132 if simple_type_child is None: 4133 raise pyxb.SchemaValidationError('Content requires an xs:simpleType member (or a base attribute)') 4134 return simple_type_child 4135 4136 # The __initializeFrom* methods are responsible for identifying 4137 # the variety and the baseTypeDefinition. The remainder of the 4138 # resolution is performed by the __completeResolution method. 4139 # Note that in some cases resolution might yet be premature, so 4140 # variety is not saved until it is complete. All this stuff is 4141 # from section 3.14.2. 4142 4143 def __initializeFromList (self, body, **kw): 4144 self.__baseTypeDefinition = self.SimpleUrTypeDefinition() 4145 self.__itemTypeExpandedName = domutils.NodeAttributeQName(body, 'itemType') 4146 if self.__itemTypeExpandedName is None: 4147 # NOTE: The newly created anonymous item type will 4148 # not be resolved; the caller needs to handle 4149 # that. 4150 self.__itemTypeDefinition = self.CreateFromDOM(self.__singleSimpleTypeChild(body), **kw) 4151 return self.__completeResolution(body, self.VARIETY_list, self._DA_list) 4152 4153 def __initializeFromRestriction (self, body, **kw): 4154 if self.__baseTypeDefinition is None: 4155 self.__baseExpandedName = domutils.NodeAttributeQName(body, 'base') 4156 if self.__baseExpandedName is None: 4157 self.__baseTypeDefinition = self.CreateFromDOM(self.__singleSimpleTypeChild(body, other_elts_ok=True), **kw) 4158 return self.__completeResolution(body, None, self._DA_restriction) 4159 4160 __localMemberTypes = None 4161 def __initializeFromUnion (self, body, **kw): 4162 self.__baseTypeDefinition = self.SimpleUrTypeDefinition() 4163 mta = domutils.NodeAttribute(body, 'memberTypes') 4164 self.__memberTypesExpandedNames = None 4165 if mta is not None: 4166 nsc = pyxb.namespace.NamespaceContext.GetNodeContext(body) 4167 self.__memberTypesExpandedNames = [ nsc.interpretQName(_mten) for _mten in mta.split() ] 4168 if self.__localMemberTypes is None: 4169 self.__localMemberTypes = [] 4170 for cn in body.childNodes: 4171 if (Node.ELEMENT_NODE == cn.nodeType) and xsd.nodeIsNamed(cn, 'simpleType'): 4172 self.__localMemberTypes.append(self.CreateFromDOM(cn, **kw)) 4173 return self.__completeResolution(body, self.VARIETY_union, self._DA_union) 4174 4175 def __resolveBuiltin (self): 4176 if self.hasPythonSupport(): 4177 self.__facets = { } 4178 for v in six.itervalues(self.pythonSupport().__dict__): 4179 if isinstance(v, facets.ConstrainingFacet): 4180 self.__facets[v.__class__] = v 4181 if v.ownerTypeDefinition() is None: 4182 v.setFromKeywords(_constructor=True, owner_type_definition=self) 4183 self.__isBuiltin = True 4184 return self 4185 4186 def __defineDefaultFacets (self, variety): 4187 """Create facets for varieties that can take facets that are undeclared. 4188 4189 This means unions, which per section 4.1.2.3 of 4190 http://www.w3.org/TR/xmlschema-2/ can have enumeration or 4191 pattern restrictions.""" 4192 if self.VARIETY_union != variety: 4193 return self 4194 self.__facets.setdefault(facets.CF_pattern) 4195 self.__facets.setdefault(facets.CF_enumeration) 4196 return self 4197 4198 def __processHasFacetAndProperty (self, variety): 4199 """Identify the facets and properties for this stype. 4200 4201 This method simply identifies the facets that apply to this 4202 specific type, and records property values. Only 4203 explicitly-associated facets and properties are stored; others 4204 from base types will also affect this type. The information 4205 is taken from the applicationInformation children of the 4206 definition's annotation node, if any. If there is no support 4207 for the XMLSchema_hasFacetAndProperty namespace, this is a 4208 no-op. 4209 4210 Upon return, self.__facets is a map from the class for an 4211 associated fact to None, and self.__fundamentalFacets is a 4212 frozenset of instances of FundamentalFacet. 4213 4214 The return value is self. 4215 """ 4216 self.__facets = { } 4217 self.__fundamentalFacets = frozenset() 4218 if self.annotation() is None: 4219 return self.__defineDefaultFacets(variety) 4220 app_info = self.annotation().applicationInformation() 4221 if app_info is None: 4222 return self.__defineDefaultFacets(variety) 4223 facet_map = { } 4224 fundamental_facets = set() 4225 seen_facets = set() 4226 for ai in app_info: 4227 for cn in ai.childNodes: 4228 if Node.ELEMENT_NODE != cn.nodeType: 4229 continue 4230 if pyxb.namespace.XMLSchema_hfp.nodeIsNamed(cn, 'hasFacet'): 4231 facet_name = domutils.NodeAttribute(cn, 'name')# , pyxb.namespace.XMLSchema_hfp) 4232 if facet_name is None: 4233 raise pyxb.SchemaValidationError('hasFacet missing name attribute in %s' % (cn,)) 4234 if facet_name in seen_facets: 4235 raise pyxb.SchemaValidationError('Multiple hasFacet specifications for %s' % (facet_name,)) 4236 seen_facets.add(facet_name) 4237 facet_class = facets.ConstrainingFacet.ClassForFacet(facet_name) 4238 #facet_map[facet_class] = facet_class(base_type_definition=self) 4239 facet_map[facet_class] = None 4240 if pyxb.namespace.XMLSchema_hfp.nodeIsNamed(cn, 'hasProperty'): 4241 fundamental_facets.add(facets.FundamentalFacet.CreateFromDOM(cn, self)) 4242 if 0 < len(facet_map): 4243 assert self.__baseTypeDefinition == self.SimpleUrTypeDefinition() 4244 self.__facets = facet_map 4245 assert isinstance(self.__facets, six.dictionary_type) 4246 if 0 < len(fundamental_facets): 4247 self.__fundamentalFacets = frozenset(fundamental_facets) 4248 return self 4249 4250 # NB: Must be done after resolution of the base type 4251 def __updateFacets (self, body): 4252 4253 # Create local list consisting of facet classes matched in children 4254 # and the map of keywords used to initialize the local instance. 4255 4256 local_facets = {} 4257 for fc in facets.Facet.Facets: 4258 children = domutils.LocateMatchingChildren(body, fc.Name()) 4259 if 0 < len(children): 4260 fi = fc(base_type_definition=self.__baseTypeDefinition, 4261 owner_type_definition=self) 4262 if isinstance(fi, facets._LateDatatype_mixin): 4263 fi.bindValueDatatype(self) 4264 for cn in children: 4265 kw = { 'annotation': domutils.LocateUniqueChild(cn, 'annotation') } 4266 for ai in range(0, cn.attributes.length): 4267 attr = cn.attributes.item(ai) 4268 # Convert name from unicode to string 4269 kw[six.text_type(attr.localName)] = attr.value 4270 try: 4271 fi.setFromKeywords(**kw) 4272 except pyxb.PyXBException as e: 4273 raise pyxb.SchemaValidationError('Error assigning facet %s in %s: %s' % (fc.Name(), self.expandedName(), e)) 4274 local_facets[fc] = fi 4275 self.__localFacets = local_facets 4276 4277 # We want a map from the union of the facet classes from this STD up 4278 # through its baseTypeDefinition (if present). Map elements should be 4279 # to None if the facet has not been constrained, or to the nearest 4280 # ConstrainingFacet instance if it is. ConstrainingFacet instances 4281 # created for local constraints also need a pointer to the 4282 # corresponding facet from the ancestor type definition, because those 4283 # constraints also affect this type. 4284 base_facets = {} 4285 4286 # Built-ins didn't get their facets() setting configured, so use the 4287 # _FacetMap() instead. 4288 if self.__baseTypeDefinition.isBuiltin(): 4289 pstd = self.__baseTypeDefinition.pythonSupport() 4290 if pstd != datatypes.anySimpleType: 4291 base_facets.update(pstd._FacetMap()) 4292 elif self.__baseTypeDefinition.facets(): 4293 assert isinstance(self.__baseTypeDefinition.facets(), six.dictionary_type) 4294 base_facets.update(self.__baseTypeDefinition.facets()) 4295 base_facets.update(self.facets()) 4296 4297 self.__facets = self.__localFacets 4298 for fc in six.iterkeys(base_facets): 4299 self.__facets.setdefault(fc, base_facets[fc]) 4300 assert isinstance(self.__facets, six.dictionary_type) 4301 4302 def _createRestriction (self, owner, body): 4303 """Create a new simple type with this as its base. 4304 4305 The type is owned by the provided owner, and may have facet 4306 restrictions defined by the body. 4307 @param owner: the owner for the newly created type 4308 @type owner: L{ComplexTypeDefinition} 4309 @param body: the DOM node from which facet information will be extracted 4310 @type body: C{xml.dom.Node} 4311 @rtype: L{SimpleTypeDefinition} 4312 """ 4313 std = SimpleTypeDefinition(owner=owner, namespace_context=owner._namespaceContext(), variety=None, scope=self._scope(), schema=owner._schema()) 4314 std.__baseTypeDefinition = self 4315 return std.__completeResolution(body, None, self._DA_restriction) 4316 4317 # Complete the resolution of some variety of STD. Note that the 4318 # variety is compounded by an alternative, since there is no 4319 # 'restriction' variety. 4320 def __completeResolution (self, body, variety, alternative): 4321 assert self.__variety is None 4322 if self.__baseTypeDefinition is None: 4323 assert self.__baseExpandedName is not None 4324 base_type = self.__baseExpandedName.typeDefinition() 4325 if not isinstance(base_type, SimpleTypeDefinition): 4326 raise pyxb.SchemaValidationError('Unable to locate base type %s' % (self.__baseExpandedName,)) 4327 self.__baseTypeDefinition = base_type 4328 # If the base type exists but has not yet been resolved, 4329 # delay processing this type until the one it depends on 4330 # has been completed. 4331 assert self.__baseTypeDefinition != self 4332 if not self.__baseTypeDefinition.isResolved(): 4333 self._queueForResolution('base type %s is not resolved' % (self.__baseTypeDefinition,), depends_on=self.__baseTypeDefinition) 4334 return self 4335 if variety is None: 4336 # 3.14.1 specifies that the variety is the variety of the base 4337 # type definition which, by the way, can't be the ur type. 4338 variety = self.__baseTypeDefinition.__variety 4339 assert variety is not None 4340 4341 if self.VARIETY_absent == variety: 4342 # The ur-type is always resolved. So are restrictions of it, 4343 # which is how we might get here. 4344 pass 4345 elif self.VARIETY_atomic == variety: 4346 # Atomic types (and their restrictions) use the primitive 4347 # type, which is the highest type that is below the 4348 # ur-type (which is not atomic). 4349 ptd = self 4350 while isinstance(ptd, SimpleTypeDefinition) and (self.VARIETY_atomic == ptd.__baseTypeDefinition.variety()): 4351 ptd = ptd.__baseTypeDefinition 4352 4353 self.__primitiveTypeDefinition = ptd 4354 elif self.VARIETY_list == variety: 4355 if self._DA_list == alternative: 4356 if self.__itemTypeExpandedName is not None: 4357 self.__itemTypeDefinition = self.__itemTypeExpandedName.typeDefinition() 4358 if not isinstance(self.__itemTypeDefinition, SimpleTypeDefinition): 4359 raise pyxb.SchemaValidationError('Unable to locate STD %s for items' % (self.__itemTypeExpandedName,)) 4360 elif self._DA_restriction == alternative: 4361 self.__itemTypeDefinition = self.__baseTypeDefinition.__itemTypeDefinition 4362 else: 4363 raise pyxb.LogicError('completeResolution list variety with alternative %s' % (alternative,)) 4364 elif self.VARIETY_union == variety: 4365 if self._DA_union == alternative: 4366 # First time we try to resolve, create the member type 4367 # definitions. If something later prevents us from resolving 4368 # this type, we don't want to create them again, because we 4369 # might already have references to them. 4370 if self.__memberTypeDefinitions is None: 4371 mtd = [] 4372 # If present, first extract names from memberTypes, 4373 # and add each one to the list 4374 if self.__memberTypesExpandedNames is not None: 4375 for mn_en in self.__memberTypesExpandedNames: 4376 # THROW if type has not been defined 4377 std = mn_en.typeDefinition() 4378 if std is None: 4379 raise pyxb.SchemaValidationError('Unable to locate member type %s' % (mn_en,)) 4380 # Note: We do not need these to be resolved (here) 4381 assert isinstance(std, SimpleTypeDefinition) 4382 mtd.append(std) 4383 # Now look for local type definitions 4384 mtd.extend(self.__localMemberTypes) 4385 self.__memberTypeDefinitions = mtd 4386 assert None not in self.__memberTypeDefinitions 4387 4388 # Replace any member types that are themselves unions with the 4389 # members of those unions, in order. Note that doing this 4390 # might indicate we can't resolve this type yet, which is why 4391 # we separated the member list creation and the substitution 4392 # phases 4393 mtd = [] 4394 for mt in self.__memberTypeDefinitions: 4395 assert isinstance(mt, SimpleTypeDefinition) 4396 if not mt.isResolved(): 4397 self._queueForResolution('member type not resolved', depends_on=mt) 4398 return self 4399 if self.VARIETY_union == mt.variety(): 4400 mtd.extend(mt.memberTypeDefinitions()) 4401 else: 4402 mtd.append(mt) 4403 elif self._DA_restriction == alternative: 4404 assert self.__baseTypeDefinition 4405 # Base type should have been resolved before we got here 4406 assert self.__baseTypeDefinition.isResolved() 4407 mtd = self.__baseTypeDefinition.__memberTypeDefinitions 4408 assert mtd is not None 4409 else: 4410 raise pyxb.LogicError('completeResolution union variety with alternative %s' % (alternative,)) 4411 # Save a unique copy 4412 self.__memberTypeDefinitions = mtd[:] 4413 else: 4414 raise pyxb.LogicError('completeResolution with variety 0x%02x' % (variety,)) 4415 4416 # Determine what facets, if any, apply to this type. This 4417 # should only do something if this is a primitive type. 4418 self.__processHasFacetAndProperty(variety) 4419 try: 4420 pyxb.namespace.NamespaceContext.PushContext(pyxb.namespace.NamespaceContext.GetNodeContext(body)) 4421 self.__updateFacets(body) 4422 finally: 4423 pyxb.namespace.NamespaceContext.PopContext() 4424 4425 self.__derivationAlternative = alternative 4426 self.__variety = variety 4427 self.__domNode = None 4428 return self 4429 4430 def isResolved (self): 4431 """Indicate whether this simple type is fully defined. 4432 4433 Type resolution for simple types means that the corresponding 4434 schema component fields have been set. Specifically, that 4435 means variety, baseTypeDefinition, and the appropriate 4436 additional fields depending on variety. See _resolve() for 4437 more information. 4438 """ 4439 # Only unresolved nodes have an unset variety 4440 return (self.__variety is not None) 4441 4442 # STD:res 4443 def _resolve (self): 4444 """Attempt to resolve the type. 4445 4446 Type resolution for simple types means that the corresponding 4447 schema component fields have been set. Specifically, that 4448 means variety, baseTypeDefinition, and the appropriate 4449 additional fields depending on variety. 4450 4451 All built-in STDs are resolved upon creation. Schema-defined 4452 STDs are held unresolved until the schema has been completely 4453 read, so that references to later schema-defined STDs can be 4454 resolved. Resolution is performed after the entire schema has 4455 been scanned and STD instances created for all 4456 topLevelSimpleTypes. 4457 4458 If a built-in STD is also defined in a schema (which it should 4459 be for XMLSchema), the built-in STD is kept, with the 4460 schema-related information copied over from the matching 4461 schema-defined STD. The former then replaces the latter in 4462 the list of STDs to be resolved. 4463 4464 Types defined by restriction have the same variety as the type 4465 they restrict. If a simple type restriction depends on an 4466 unresolved type, this method simply queues it for resolution 4467 in a later pass and returns. 4468 """ 4469 if self.__variety is not None: 4470 return self 4471 assert self.__domNode 4472 node = self.__domNode 4473 4474 kw = { 'owner' : self 4475 , 'schema' : self._schema() } 4476 4477 bad_instance = False 4478 # The guts of the node should be exactly one instance of 4479 # exactly one of these three types. 4480 candidate = domutils.LocateUniqueChild(node, 'list') 4481 if candidate: 4482 self.__initializeFromList(candidate, **kw) 4483 4484 candidate = domutils.LocateUniqueChild(node, 'restriction') 4485 if candidate: 4486 if self.__variety is None: 4487 self.__initializeFromRestriction(candidate, **kw) 4488 else: 4489 bad_instance = True 4490 4491 candidate = domutils.LocateUniqueChild(node, 'union') 4492 if candidate: 4493 if self.__variety is None: 4494 self.__initializeFromUnion(candidate, **kw) 4495 else: 4496 bad_instance = True 4497 4498 if self.__baseTypeDefinition is None: 4499 raise pyxb.SchemaValidationError('xs:simpleType must have list, union, or restriction as child') 4500 4501 if self._schema() is not None: 4502 self.__final = self._schema().finalForNode(node, self._STD_Map) 4503 4504 # It is NOT an error to fail to resolve the type. 4505 if bad_instance: 4506 raise pyxb.SchemaValidationError('Expected exactly one of list, restriction, union as child of simpleType') 4507 4508 return self 4509 4510 # CFD:STD CFD:SimpleTypeDefinition 4511 @classmethod 4512 def CreateFromDOM (cls, node, **kw): 4513 # Node should be an XMLSchema simpleType node 4514 assert xsd.nodeIsNamed(node, 'simpleType') 4515 4516 name = domutils.NodeAttribute(node, 'name') 4517 4518 rv = cls(name=name, node=node, variety=None, **kw) 4519 rv._annotationFromDOM(node) 4520 4521 # Creation does not attempt to do resolution. Queue up the newly created 4522 # whatsis so we can resolve it after everything's been read in. 4523 rv.__domNode = node 4524 rv._queueForResolution('creation') 4525 4526 return rv 4527 4528 # pythonSupport is None, or a subclass of datatypes.simpleTypeDefinition. 4529 # When set, this simple type definition instance must be uniquely 4530 # associated with the python support type. 4531 __pythonSupport = None 4532 4533 def _setPythonSupport (self, python_support): 4534 # Includes check that python_support is not None 4535 assert issubclass(python_support, basis.simpleTypeDefinition) 4536 # Can't share support instances 4537 self.__pythonSupport = python_support 4538 self.__pythonSupport._SimpleTypeDefinition(self) 4539 if self.nameInBinding() is None: 4540 self.setNameInBinding(self.__pythonSupport.__name__) 4541 return self.__pythonSupport 4542 4543 def hasPythonSupport (self): 4544 return self.__pythonSupport is not None 4545 4546 def pythonSupport (self): 4547 if self.__pythonSupport is None: 4548 raise pyxb.LogicError('%s: No support defined' % (self.name(),)) 4549 return self.__pythonSupport 4550 4551 def stringToPython (self, string): 4552 return self.pythonSupport().stringToPython(string) 4553 4554 def pythonToString (self, value): 4555 return self.pythonSupport().pythonToString(value) 4556 4557class _SimpleUrTypeDefinition (SimpleTypeDefinition, _Singleton_mixin): 4558 """Subclass ensures there is only one simple ur-type.""" 4559 pass 4560 4561class _ImportElementInformationItem (_Annotated_mixin): 4562 """Data associated with an 4563 U{import<http://www.w3.org/TR/xmlschema-1/#composition-schemaImport>} 4564 statement within a schema.""" 4565 4566 def id (self): 4567 """The value of the C{id} attribute from the import statement.""" 4568 return self.__id 4569 __id = None 4570 4571 def namespace (self): 4572 """The L{pyxb.namespace.Namespace} instance corresponding to the value 4573 of the C{namespace} attribute from the import statement.""" 4574 return self.__namespace 4575 __namespace = None 4576 4577 def schemaLocation (self): 4578 """The value of the C{schemaLocation} attribute from the import 4579 statement, normalized relative to the location of the importing 4580 schema.""" 4581 return self.__schemaLocation 4582 __schemaLocation = None 4583 4584 def prefix (self): 4585 """The prefix from a namespace declaration for L{namespace} that was 4586 active in the context of the import element, or C{None} if there was 4587 no relevant namespace declaration in scope at that point. 4588 4589 This is propagated to be used as the default prefix for the 4590 corresponding namespace if no prefix had been assigned. 4591 """ 4592 return self.__prefix 4593 __prefix = None 4594 4595 def schema (self): 4596 """The L{Schema} instance corresponding to the imported schema, if 4597 available. 4598 4599 Normally C{import} statements will be fulfilled by loading components 4600 from a L{namespace archive<pyxb.namespace.NamespaceArchive>} in which 4601 the corresponding namespace is marked as public. Where there are 4602 cycles in the namespace dependency graph, or the schema for a 4603 namespace are associated with a restricted profile of another 4604 namespace, there may be no such archive and instead the components are 4605 obtained using this schema.""" 4606 return self.__schema 4607 __schema = None 4608 4609 def __init__ (self, importing_schema, node, **kw): 4610 """Gather the information relative to an C{import} statement. 4611 4612 If the imported namespace can be loaded from an archive, the 4613 C{schemaLocation} attribute is ignored. Otherwise, it attempts to 4614 retrieve and parse the corresponding schema (if this has not already 4615 been done). 4616 4617 @param importing_schema: The L{Schema} instance in which the import 4618 was found. 4619 @param node: The C{xml.dom.DOM} node incorporating the schema 4620 information. 4621 4622 @raise Exception: Any exception raised when attempting to retrieve and 4623 parse data from the schema location. 4624 """ 4625 4626 super(_ImportElementInformationItem, self).__init__(**kw) 4627 uri = domutils.NodeAttribute(node, 'namespace') 4628 if uri is None: 4629 raise pyxb.IncompleteImplementationError('import statements without namespace not supported') 4630 schema_location = pyxb.utils.utility.NormalizeLocation(domutils.NodeAttribute(node, 'schemaLocation'), importing_schema.location()) 4631 self.__schemaLocation = schema_location 4632 ns = self.__namespace = pyxb.namespace.NamespaceForURI(uri, create_if_missing=True) 4633 need_schema = ns.isImportAugmentable() 4634 if not need_schema: 4635 # Discard location if we expect to be able to learn about this 4636 # namespace from an archive or a built-in description 4637 self.__schemaLocation = None 4638 4639 ns_ctx = pyxb.namespace.NamespaceContext.GetNodeContext(node) 4640 if self.schemaLocation() is not None: 4641 # @todo: NOTICE 4642 (has_schema, schema_instance) = self.__namespace.lookupSchemaByLocation(schema_location) 4643 if not has_schema: 4644 ckw = { 'absolute_schema_location' : schema_location, 4645 'generation_uid' : importing_schema.generationUID(), 4646 'uri_content_archive_directory' : importing_schema._uriContentArchiveDirectory(), 4647 } 4648 try: 4649 schema_instance = Schema.CreateFromLocation(**ckw) 4650 except Exception: 4651 _log.exception('Import %s cannot read schema location %s (%s)', ns, self.__schemaLocation, schema_location) 4652 raise 4653 self.__schema = schema_instance 4654 elif need_schema: 4655 _log.warning('No information available on imported namespace %s', uri) 4656 4657 # If we think we found a schema, make sure it's in the right 4658 # namespace. 4659 if self.__schema is not None: 4660 if ns != self.__schema.targetNamespace(): 4661 raise pyxb.SchemaValidationError('Import expected namespace %s but got %s' % (ns, self.__schema.targetNamespace())) 4662 4663 self.__prefix = ns_ctx.prefixForNamespace(self.namespace()) 4664 4665 self._annotationFromDOM(node) 4666 4667class Schema (_SchemaComponent_mixin): 4668 """An XMLSchema U{Schema<http://www.w3.org/TR/xmlschema-1/#Schemas>}.""" 4669 4670 def __getstate__ (self): 4671 raise pyxb.LogicError('Attempt to serialize Schema instance') 4672 4673 # List of annotations 4674 __annotations = None 4675 4676 # True when we have started seeing elements, attributes, or 4677 # notations. 4678 __pastProlog = False 4679 4680 def location (self): 4681 """URI or path to where the schema can be found. 4682 4683 For schema created by a user, the location should be provided to the 4684 constructor using the C{schema_location} keyword. In the case of 4685 imported or included schema, the including schema's location is used 4686 as the base URI for determining the absolute URI of the included 4687 schema from its (possibly relative) location value. For files, 4688 the scheme and authority portions are generally absent, as is often 4689 the abs_path part.""" 4690 return self.__location 4691 __location = None 4692 4693 def locationTag (self): 4694 return self.__locationTag 4695 __locationTag = None 4696 4697 def signature (self): 4698 return self.__signature 4699 __signature = None 4700 4701 def generationUID (self): 4702 return self.__generationUID 4703 __generationUID = None 4704 4705 def originRecord (self): 4706 return self.__originRecord 4707 __originRecord = None 4708 4709 def targetNamespace (self): 4710 """The targetNamespace of a componen. 4711 4712 This is None, or a reference to a Namespace in which the 4713 component is declared (either as a global or local to one of 4714 the namespace's complex type definitions). This is immutable 4715 after creation. 4716 """ 4717 return self.__targetNamespace 4718 __targetNamespace = None 4719 4720 def defaultNamespace (self): 4721 """Default namespace of the schema. 4722 4723 Will be None unless the schema has an 'xmlns' attribute. The 4724 value must currently be provided as a keyword parameter to the 4725 constructor. """ 4726 return self.__defaultNamespace 4727 __defaultNamespace = None 4728 4729 def referencedNamespaces (self): 4730 return self.__referencedNamespaces 4731 __referencedNamespaces = None 4732 4733 __namespaceData = None 4734 4735 def importEIIs (self): 4736 return self.__importEIIs 4737 __importEIIs = None 4738 4739 def importedSchema (self): 4740 return self.__importedSchema 4741 __importedSchema = None 4742 def includedSchema (self): 4743 return self.__includedSchema 4744 __includedSchema = None 4745 4746 _QUALIFIED = "qualified" 4747 _UNQUALIFIED = "unqualified" 4748 4749 # Default values for standard recognized schema attributes 4750 __attributeMap = { pyxb.namespace.ExpandedName(None, 'attributeFormDefault') : _UNQUALIFIED 4751 , pyxb.namespace.ExpandedName(None, 'elementFormDefault') : _UNQUALIFIED 4752 , pyxb.namespace.ExpandedName(None, 'blockDefault') : '' 4753 , pyxb.namespace.ExpandedName(None, 'finalDefault') : '' 4754 , pyxb.namespace.ExpandedName(None, 'id') : None 4755 , pyxb.namespace.ExpandedName(None, 'targetNamespace') : None 4756 , pyxb.namespace.ExpandedName(None, 'version') : None 4757 , pyxb.namespace.XML.createExpandedName('lang') : None 4758 } 4759 4760 def _setAttributeFromDOM (self, attr): 4761 """Override the schema attribute with the given DOM value.""" 4762 self.__attributeMap[pyxb.namespace.ExpandedName(attr.name)] = attr.nodeValue 4763 return self 4764 4765 def _setAttributesFromMap (self, attr_map): 4766 """Override the schema attributes with values from the given map.""" 4767 self.__attributeMap.update(attr_map) 4768 return self 4769 4770 def schemaHasAttribute (self, attr_name): 4771 """Return True iff the schema has an attribute with the given (nc)name.""" 4772 if isinstance(attr_name, six.string_types): 4773 attr_name = pyxb.namespace.ExpandedName(None, attr_name) 4774 return attr_name in self.__attributeMap 4775 4776 def schemaAttribute (self, attr_name): 4777 """Return the schema attribute value associated with the given (nc)name. 4778 4779 @param attr_name: local name for the attribute in the schema element. 4780 @return: the value of the corresponding attribute, or C{None} if it 4781 has not been defined and has no default. 4782 @raise KeyError: C{attr_name} is not a valid attribute for a C{schema} element. 4783 """ 4784 if isinstance(attr_name, six.string_types): 4785 attr_name = pyxb.namespace.ExpandedName(None, attr_name) 4786 return self.__attributeMap[attr_name] 4787 4788 __SchemaCategories = ( 'typeDefinition', 'attributeGroupDefinition', 'modelGroupDefinition', 4789 'attributeDeclaration', 'elementDeclaration', 'notationDeclaration', 4790 'identityConstraintDefinition' ) 4791 4792 def _uriContentArchiveDirectory (self): 4793 return self.__uriContentArchiveDirectory 4794 __uriContentArchiveDirectory = None 4795 4796 def __init__ (self, *args, **kw): 4797 # Force resolution of available namespaces if not already done 4798 if not kw.get('_bypass_preload', False): 4799 pyxb.namespace.archive.NamespaceArchive.PreLoadArchives() 4800 4801 assert 'schema' not in kw 4802 self.__uriContentArchiveDirectory = kw.get('uri_content_archive_directory') 4803 self.__location = kw.get('schema_location') 4804 if self.__location is not None: 4805 schema_path = self.__location 4806 if 0 <= schema_path.find(':'): 4807 schema_path = urlparse.urlparse(schema_path)[2] # .path 4808 self.__locationTag = os.path.split(schema_path)[1].split('.')[0] 4809 4810 self.__generationUID = kw.get('generation_uid') 4811 if self.__generationUID is None: 4812 _log.warning('No generationUID provided') 4813 self.__generationUID = pyxb.utils.utility.UniqueIdentifier() 4814 4815 self.__signature = kw.get('schema_signature') 4816 4817 super(Schema, self).__init__(*args, **kw) 4818 self.__importEIIs = set() 4819 self.__includedSchema = set() 4820 self.__importedSchema = set() 4821 self.__targetNamespace = self._namespaceContext().targetNamespace() 4822 if not isinstance(self.__targetNamespace, pyxb.namespace.Namespace): 4823 raise pyxb.LogicError('Schema constructor requires valid Namespace instance as target_namespace') 4824 4825 # NB: This will raise pyxb.SchemaUniquenessError if it appears this 4826 # schema has already been incorporated into the target namespace. 4827 self.__originRecord = self.__targetNamespace.addSchema(self) 4828 4829 self.__targetNamespace.configureCategories(self.__SchemaCategories) 4830 if self.__defaultNamespace is not None: 4831 self.__defaultNamespace.configureCategories(self.__SchemaCategories) 4832 4833 self.__attributeMap = self.__attributeMap.copy() 4834 self.__annotations = [] 4835 # @todo: This isn't right if namespaces are introduced deeper in the document 4836 self.__referencedNamespaces = list(six.itervalues(self._namespaceContext().inScopeNamespaces())) 4837 4838 __TopLevelComponentMap = { 4839 'element' : ElementDeclaration, 4840 'attribute' : AttributeDeclaration, 4841 'notation' : NotationDeclaration, 4842 'simpleType' : SimpleTypeDefinition, 4843 'complexType' : ComplexTypeDefinition, 4844 'group' : ModelGroupDefinition, 4845 'attributeGroup' : AttributeGroupDefinition 4846 } 4847 4848 @classmethod 4849 def CreateFromDocument (cls, xmls, **kw): 4850 if not ('schema_signature' in kw): 4851 kw['schema_signature'] = pyxb.utils.utility.HashForText(xmls) 4852 return cls.CreateFromDOM(domutils.StringToDOM(xmls, **kw), **kw) 4853 4854 @classmethod 4855 def CreateFromLocation (cls, **kw): 4856 """Create a schema from a schema location. 4857 4858 Reads an XML document from the schema location and creates a schema 4859 using it. All keyword parameters are passed to L{CreateFromDOM}. 4860 4861 @keyword schema_location: A file path or a URI. If this is a relative 4862 URI and C{parent_uri} is present, the actual location will be 4863 L{normallzed<pyxb.utils.utility.NormalizeLocation>}. 4864 @keyword parent_uri: The context within which schema_location will be 4865 normalized, if necessary. 4866 @keyword absolute_schema_location: A file path or URI. This value is 4867 not normalized, and supersedes C{schema_location}. 4868 """ 4869 schema_location = kw.pop('absolute_schema_location', pyxb.utils.utility.NormalizeLocation(kw.get('schema_location'), kw.get('parent_uri'), kw.get('prefix_map'))) 4870 kw['location_base'] = kw['schema_location'] = schema_location 4871 assert isinstance(schema_location, six.string_types), 'Unexpected value %s type %s for schema_location' % (schema_location, type(schema_location)) 4872 uri_content_archive_directory = kw.get('uri_content_archive_directory') 4873 return cls.CreateFromDocument(pyxb.utils.utility.DataFromURI(schema_location, archive_directory=uri_content_archive_directory), **kw) 4874 4875 @classmethod 4876 def CreateFromStream (cls, stream, **kw): 4877 return cls.CreateFromDocument(stream.read(), **kw) 4878 4879 @classmethod 4880 def CreateFromDOM (cls, node, namespace_context=None, schema_location=None, schema_signature=None, generation_uid=None, **kw): 4881 """Take the root element of the document, and scan its attributes under 4882 the assumption it is an XMLSchema schema element. That means 4883 recognize namespace declarations and process them. Also look for 4884 and set the default namespace. All other attributes are passed up 4885 to the parent class for storage.""" 4886 4887 # Get the context of any schema that is including (not importing) this 4888 # one. 4889 including_context = kw.get('including_context') 4890 4891 root_node = node 4892 if Node.DOCUMENT_NODE == node.nodeType: 4893 root_node = root_node.documentElement 4894 if Node.ELEMENT_NODE != root_node.nodeType: 4895 raise pyxb.LogicError('Must be given a DOM node of type ELEMENT') 4896 4897 assert (namespace_context is None) or isinstance(namespace_context, pyxb.namespace.NamespaceContext) 4898 ns_ctx = pyxb.namespace.NamespaceContext.GetNodeContext(root_node, 4899 parent_context=namespace_context, 4900 including_context=including_context) 4901 4902 tns = ns_ctx.targetNamespace() 4903 if tns is None: 4904 raise pyxb.SchemaValidationError('No targetNamespace associated with content (not a schema?)') 4905 schema = cls(namespace_context=ns_ctx, schema_location=schema_location, schema_signature=schema_signature, generation_uid=generation_uid, **kw) 4906 schema.__namespaceData = ns_ctx 4907 4908 if schema.targetNamespace() != ns_ctx.targetNamespace(): 4909 raise pyxb.SchemaValidationError('targetNamespace %s conflicts with %s' % (schema.targetNamespace(), ns_ctx.targetNamespace())) 4910 4911 # Update the attribute map 4912 for ai in range(root_node.attributes.length): 4913 schema._setAttributeFromDOM(root_node.attributes.item(ai)) 4914 4915 # Verify that the root node is an XML schema element 4916 if not xsd.nodeIsNamed(root_node, 'schema'): 4917 raise pyxb.SchemaValidationError('Root node %s of document is not an XML schema element' % (root_node.nodeName,)) 4918 4919 for cn in root_node.childNodes: 4920 if Node.ELEMENT_NODE == cn.nodeType: 4921 rv = schema.__processTopLevelNode(cn) 4922 if rv is None: 4923 _log.info('Unrecognized: %s %s', cn.nodeName, cn.toxml("utf-8")) 4924 elif Node.TEXT_NODE == cn.nodeType: 4925 # Non-element content really should just be whitespace. 4926 # If something else is seen, print it for inspection. 4927 text = cn.data.strip() 4928 if text: 4929 _log.info('Ignored text: %s', text) 4930 elif Node.COMMENT_NODE == cn.nodeType: 4931 pass 4932 else: 4933 # ATTRIBUTE_NODE 4934 # CDATA_SECTION_NODE 4935 # ENTITY_NODE 4936 # PROCESSING_INSTRUCTION 4937 # DOCUMENT_NODE 4938 # DOCUMENT_TYPE_NODE 4939 # NOTATION_NODE 4940 _log.info('Ignoring non-element: %s', cn) 4941 4942 # Do not perform resolution yet: we may be done with this schema, but 4943 # the namespace may incorporate additional ones, and we can't resolve 4944 # until everything's present. 4945 return schema 4946 4947 _SA_All = '#all' 4948 4949 def __ebvForNode (self, attr, dom_node, candidate_map): 4950 ebv = domutils.NodeAttribute(dom_node, attr) 4951 if ebv is None: 4952 ebv = self.schemaAttribute('%sDefault' % (attr,)) 4953 rv = 0 4954 if ebv == self._SA_All: 4955 for v in six.itervalues(candidate_map): 4956 rv += v 4957 else: 4958 for candidate in ebv.split(): 4959 rv += candidate_map.get(candidate, 0) 4960 return rv 4961 4962 def blockForNode (self, dom_node, candidate_map): 4963 """Return a bit mask indicating a set of options read from the node's "block" attribute or the schema's "blockDefault" attribute. 4964 4965 A value of '#all' means enable every options; otherwise, the attribute 4966 value should be a list of tokens, for which the corresponding value 4967 will be added to the return value. 4968 4969 @param dom_node: the node from which the "block" attribute will be retrieved 4970 @type dom_node: C{xml.dom.Node} 4971 @param candidate_map: map from strings to bitmask values 4972 """ 4973 return self.__ebvForNode('block', dom_node, candidate_map) 4974 4975 def finalForNode (self, dom_node, candidate_map): 4976 """Return a bit mask indicating a set of options read from the node's 4977 "final" attribute or the schema's "finalDefault" attribute. 4978 4979 A value of '#all' means enable every options; otherwise, the attribute 4980 value should be a list of tokens, for which the corresponding value 4981 will be added to the return value. 4982 4983 @param dom_node: the node from which the "final" attribute will be retrieved 4984 @type dom_node: C{xml.dom.Node} 4985 @param candidate_map: map from strings to bitmask values 4986 """ 4987 return self.__ebvForNode('final', dom_node, candidate_map) 4988 4989 def targetNamespaceForNode (self, dom_node, declaration_type): 4990 """Determine the target namespace for a local attribute or element declaration. 4991 4992 Look at the node's C{form} attribute, or if none the schema's 4993 C{attributeFormDefault} or C{elementFormDefault} value. If the 4994 resulting value is C{"qualified"} and the parent schema has a 4995 non-absent target namespace, return it to use as the declaration 4996 target namespace. Otherwise, return None to indicate that the 4997 declaration has no namespace. 4998 4999 @param dom_node: The node defining an element or attribute declaration 5000 @param declaration_type: Either L{AttributeDeclaration} or L{ElementDeclaration} 5001 @return: L{pyxb.namespace.Namespace} or None 5002 """ 5003 5004 form_type = domutils.NodeAttribute(dom_node, 'form') 5005 if form_type is None: 5006 if declaration_type == ElementDeclaration: 5007 form_type = self.schemaAttribute('elementFormDefault') 5008 elif declaration_type == AttributeDeclaration: 5009 form_type = self.schemaAttribute('attributeFormDefault') 5010 else: 5011 raise pyxb.LogicError('Expected ElementDeclaration or AttributeDeclaration: got %s' % (declaration_type,)) 5012 tns = None 5013 if (self._QUALIFIED == form_type): 5014 tns = self.targetNamespace() 5015 if tns.isAbsentNamespace(): 5016 tns = None 5017 else: 5018 if (self._UNQUALIFIED != form_type): 5019 raise pyxb.SchemaValidationError('Form type neither %s nor %s' % (self._QUALIFIED, self._UNQUALIFIED)) 5020 return tns 5021 5022 def __requireInProlog (self, node_name): 5023 """Throw a SchemaValidationException referencing the given 5024 node if we have passed the sequence point representing the end 5025 of prolog elements.""" 5026 5027 if self.__pastProlog: 5028 raise pyxb.SchemaValidationError('Unexpected node %s after prolog' % (node_name,)) 5029 5030 def __processInclude (self, node): 5031 self.__requireInProlog(node.nodeName) 5032 # See section 4.2.1 of Structures. 5033 abs_uri = pyxb.utils.utility.NormalizeLocation(domutils.NodeAttribute(node, 'schemaLocation'), self.__location) 5034 (has_schema, schema_instance) = self.targetNamespace().lookupSchemaByLocation(abs_uri) 5035 if not has_schema: 5036 kw = { 'absolute_schema_location': abs_uri, 5037 'including_context': self.__namespaceData, 5038 'generation_uid': self.generationUID(), 5039 'uri_content_archive_directory': self._uriContentArchiveDirectory(), 5040 } 5041 try: 5042 schema_instance = self.CreateFromLocation(**kw) 5043 except pyxb.SchemaUniquenessError as e: 5044 _log.warning('Skipping apparent redundant inclusion of %s defining %s (hash matches %s)', e.schemaLocation(), e.namespace(), e.existingSchema().location()) 5045 except Exception as e: 5046 _log.exception('INCLUDE %s caught', abs_uri) 5047 raise 5048 if schema_instance: 5049 if self.targetNamespace() != schema_instance.targetNamespace(): 5050 raise pyxb.SchemaValidationError('Included namespace %s not consistent with including namespace %s' % (schema_instance.targetNamespace(), self.targetNamespace())) 5051 self.__includedSchema.add(schema_instance) 5052 return node 5053 5054 def __processImport (self, node): 5055 """Process an import directive. 5056 5057 This attempts to locate schema (named entity) information for 5058 a namespace that is referenced by this schema. 5059 """ 5060 5061 self.__requireInProlog(node.nodeName) 5062 import_eii = _ImportElementInformationItem(self, node) 5063 if import_eii.schema() is not None: 5064 self.__importedSchema.add(import_eii.schema()) 5065 self.targetNamespace().importNamespace(import_eii.namespace()) 5066 ins = import_eii.namespace() 5067 if ins.prefix() is None: 5068 ins.setPrefix(import_eii.prefix()) 5069 self.__importEIIs.add(import_eii) 5070 return node 5071 5072 def __processRedefine (self, node): 5073 self.__requireInProlog(node.nodeName) 5074 raise pyxb.IncompleteImplementationError('redefine not implemented') 5075 5076 def __processAnnotation (self, node): 5077 self._addAnnotation(Annotation.CreateFromDOM(node)) 5078 return self 5079 5080 def __processTopLevelNode (self, node): 5081 """Process a DOM node from the top level of the schema. 5082 5083 This should return a non-None value if the node was 5084 successfully recognized.""" 5085 if xsd.nodeIsNamed(node, 'include'): 5086 return self.__processInclude(node) 5087 if xsd.nodeIsNamed(node, 'import'): 5088 return self.__processImport(node) 5089 if xsd.nodeIsNamed(node, 'redefine'): 5090 return self.__processRedefine(node) 5091 if xsd.nodeIsNamed(node, 'annotation'): 5092 return self.__processAnnotation(node) 5093 5094 component = self.__TopLevelComponentMap.get(node.localName) 5095 if component is not None: 5096 self.__pastProlog = True 5097 kw = { 'scope' : _ScopedDeclaration_mixin.SCOPE_global, 5098 'schema' : self, 5099 'owner' : self } 5100 return self._addNamedComponent(component.CreateFromDOM(node, **kw)) 5101 5102 raise pyxb.SchemaValidationError('Unexpected top-level element %s' % (node.nodeName,)) 5103 5104 def _addAnnotation (self, annotation): 5105 self.__annotations.append(annotation) 5106 return annotation 5107 5108 def _addNamedComponent (self, nc): 5109 tns = self.targetNamespace() 5110 assert tns is not None 5111 if not isinstance(nc, _NamedComponent_mixin): 5112 raise pyxb.LogicError('Attempt to add unnamed %s instance to dictionary' % (nc.__class__,)) 5113 if nc.isAnonymous(): 5114 raise pyxb.LogicError('Attempt to add anonymous component to dictionary: %s', (nc.__class__,)) 5115 if isinstance(nc, _ScopedDeclaration_mixin): 5116 assert _ScopedDeclaration_mixin.SCOPE_global == nc.scope() 5117 if isinstance(nc, (SimpleTypeDefinition, ComplexTypeDefinition)): 5118 return self.__addTypeDefinition(nc) 5119 if isinstance(nc, AttributeDeclaration): 5120 return self.__addAttributeDeclaration(nc) 5121 if isinstance(nc, AttributeGroupDefinition): 5122 return self.__addAttributeGroupDefinition(nc) 5123 if isinstance(nc, ModelGroupDefinition): 5124 return tns.addCategoryObject('modelGroupDefinition', nc.name(), nc) 5125 if isinstance(nc, ElementDeclaration): 5126 return tns.addCategoryObject('elementDeclaration', nc.name(), nc) 5127 if isinstance(nc, NotationDeclaration): 5128 return tns.addCategoryObject('notationDeclaration', nc.name(), nc) 5129 if isinstance(nc, IdentityConstraintDefinition): 5130 return tns.addCategoryObject('identityConstraintDefinition', nc.name(), nc) 5131 assert False, 'No support to record named component of type %s' % (nc.__class__,) 5132 5133 def __addTypeDefinition (self, td): 5134 local_name = td.name() 5135 assert self.__targetNamespace 5136 tns = self.targetNamespace() 5137 old_td = tns.typeDefinitions().get(local_name) 5138 if (old_td is not None) and (old_td != td): 5139 if isinstance(td, ComplexTypeDefinition) != isinstance(old_td, ComplexTypeDefinition): 5140 raise pyxb.SchemaValidationError('Name %s used for both simple and complex types' % (td.name(),)) 5141 5142 if not old_td._allowUpdateFromOther(td): 5143 raise pyxb.SchemaValidationError('Attempt to re-define non-builtin type definition %s' % (tns.createExpandedName(local_name),)) 5144 5145 # Copy schema-related information from the new definition 5146 # into the old one, and continue to use the old one. 5147 td = tns._replaceComponent(td, old_td._updateFromOther(td)) 5148 else: 5149 tns.addCategoryObject('typeDefinition', td.name(), td) 5150 assert td is not None 5151 return td 5152 5153 def __addAttributeDeclaration (self, ad): 5154 local_name = ad.name() 5155 assert self.__targetNamespace 5156 tns = self.targetNamespace() 5157 old_ad = tns.attributeDeclarations().get(local_name) 5158 if (old_ad is not None) and (old_ad != ad): 5159 if not old_ad._allowUpdateFromOther(ad): 5160 raise pyxb.SchemaValidationError('Attempt to re-define non-builtin attribute declaration %s' % (tns.createExpandedName(local_name),)) 5161 5162 # Copy schema-related information from the new definition 5163 # into the old one, and continue to use the old one. 5164 ad = tns._replaceComponent(ad, old_ad._updateFromOther(ad)) 5165 else: 5166 tns.addCategoryObject('attributeDeclaration', ad.name(), ad) 5167 assert ad is not None 5168 return ad 5169 5170 def __addAttributeGroupDefinition (self, agd): 5171 local_name = agd.name() 5172 assert self.__targetNamespace 5173 tns = self.targetNamespace() 5174 old_agd = tns.attributeGroupDefinitions().get(local_name) 5175 if (old_agd is not None) and (old_agd != agd): 5176 if not old_agd._allowUpdateFromOther(agd): 5177 raise pyxb.SchemaValidationError('Attempt to re-define non-builtin attribute group definition %s' % (tns.createExpandedName(local_name),)) 5178 5179 # Copy schema-related information from the new definition 5180 # into the old one, and continue to use the old one. 5181 tns._replaceComponent(agd, old_agd._updateFromOther(agd)) 5182 else: 5183 tns.addCategoryObject('attributeGroupDefinition', agd.name(), agd) 5184 assert agd is not None 5185 return agd 5186 5187 def __str__ (self): 5188 return 'SCH[%s]' % (self.location(),) 5189 5190 5191def _AddSimpleTypes (namespace): 5192 """Add to the schema the definitions of the built-in types of XMLSchema. 5193 This should only be invoked by L{pyxb.namespace} when the built-in 5194 namespaces are initialized. """ 5195 # Add the ur type 5196 #schema = namespace.schema() 5197 schema = Schema(namespace_context=pyxb.namespace.XMLSchema.initialNamespaceContext(), schema_location='URN:noLocation:PyXB:XMLSchema', generation_uid=pyxb.namespace.BuiltInObjectUID, _bypass_preload=True) 5198 td = schema._addNamedComponent(ComplexTypeDefinition.UrTypeDefinition(schema, in_builtin_definition=True)) 5199 assert td.isResolved() 5200 # Add the simple ur type 5201 td = schema._addNamedComponent(SimpleTypeDefinition.SimpleUrTypeDefinition(schema, in_builtin_definition=True)) 5202 assert td.isResolved() 5203 # Add definitions for all primitive and derived simple types 5204 pts_std_map = {} 5205 for dtc in datatypes._PrimitiveDatatypes: 5206 name = dtc.__name__.rstrip('_') 5207 td = schema._addNamedComponent(SimpleTypeDefinition.CreatePrimitiveInstance(name, schema, dtc)) 5208 assert td.isResolved() 5209 assert dtc.SimpleTypeDefinition() == td 5210 pts_std_map.setdefault(dtc, td) 5211 for dtc in datatypes._DerivedDatatypes: 5212 name = dtc.__name__.rstrip('_') 5213 parent_std = pts_std_map[dtc.XsdSuperType()] 5214 td = schema._addNamedComponent(SimpleTypeDefinition.CreateDerivedInstance(name, schema, parent_std, dtc)) 5215 assert td.isResolved() 5216 assert dtc.SimpleTypeDefinition() == td 5217 pts_std_map.setdefault(dtc, td) 5218 for dtc in datatypes._ListDatatypes: 5219 list_name = dtc.__name__.rstrip('_') 5220 element_name = dtc._ItemType.__name__.rstrip('_') 5221 element_std = schema.targetNamespace().typeDefinitions().get(element_name) 5222 assert element_std is not None 5223 td = schema._addNamedComponent(SimpleTypeDefinition.CreateListInstance(list_name, schema, element_std, dtc)) 5224 assert td.isResolved() 5225 global _PastAddBuiltInTypes 5226 _PastAddBuiltInTypes = True 5227 5228 return schema 5229 5230import sys 5231import pyxb.namespace.builtin 5232pyxb.namespace.builtin._InitializeBuiltinNamespaces(sys.modules[__name__]) 5233 5234## Local Variables: 5235## fill-column:78 5236## End: 5237