Package pyxb :: Package binding :: Module basis
[hide private]
[frames] | no frames]

Source Code for Module pyxb.binding.basis

   1  # -*- coding: utf-8 -*- 
   2  # Copyright 2009-2012, 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  """This module contains support classes from which schema-specific bindings 
  17  inherit, and that describe the content models of those schema.""" 
  18   
  19  import logging 
  20  import pyxb 
  21  import xml.dom 
  22  import pyxb.utils.domutils as domutils 
  23  import pyxb.utils.utility as utility 
  24  import types 
  25  import pyxb.namespace 
  26  from pyxb.namespace.builtin import XMLSchema_instance as XSI 
  27   
  28  _log = logging.getLogger(__name__) 
29 30 -class _TypeBinding_mixin (utility.Locatable_mixin):
31 32 @classmethod
33 - def _PerformValidation (cls):
34 """Determine whether the content model should be validated. 35 36 Proper validation is not yet supported in PyXB. The low level binding 37 material consults this function, but not always in a context where the 38 direction of translation is clear. Conseequently, this method 39 indicates that validation should be performed only when both 40 generation and parsing validation are enabled.""" 41 # return True 42 return pyxb._GenerationRequiresValid and pyxb._ParsingRequiresValid
43 44 _ExpandedName = None 45 """The expanded name of the component.""" 46 47 _DefinitionLocation = None 48 """Where the definition can be found in the originating schema.""" 49 50 _ReservedSymbols = set([ 'validateBinding', 'toDOM', 'toxml', 'Factory', 'property' ]) 51 52 if pyxb._CorruptionDetectionEnabled:
53 - def __setattr__ (self, name, value):
54 if name in self._ReservedSymbols: 55 raise pyxb.BindingError('Attempt to set reserved name %s in instance of %s' % (name, type(self))) 56 return super(_TypeBinding_mixin, self).__setattr__(name, value)
57 58 _PyXBFactoryKeywords = ( '_dom_node', '_fallback_namespace', '_from_xml', 59 '_apply_whitespace_facet', '_validate_constraints', 60 '_require_value', '_nil', '_element', 61 '_convert_string_values' ) 62 """Keywords that are interpreted by __new__ or __init__ in one or more 63 classes in the PyXB type hierarchy. All these keywords must be removed 64 before invoking base Python __init__ or __new__.""" 65 66 # While simple type definitions cannot be abstract, they can appear in 67 # many places where complex types can, so we want it to be legal to test 68 # for abstractness without checking whether the object is a complex type. 69 _Abstract = False 70
71 - def _namespaceContext (self):
72 """Return a L{namespace context <pyxb.binding.NamespaceContext>} 73 associated with the binding instance. 74 75 This will return C{None} unless something has provided a context to 76 the instance. Context is provided when instances are generated by the 77 DOM and SAX-based translators.""" 78 return self.__namespaceContext
79 - def _setNamespaceContext (self, namespace_context):
80 """Associate a L{namespace context <pyxb.binding.NamespaceContext>} 81 with the binding instance.""" 82 self.__namespaceContext = namespace_context 83 return self
84 __namespaceContext = None 85
86 - def _setElement (self, element):
87 """Associate a L{pyxb.binding.basis.element} with the instance.""" 88 self.__element = element 89 return self
90 - def _element (self):
91 """Return a L{pyxb.binding.basis.element} associated with the binding 92 instance. 93 94 This will return C{None} unless an element has been associated. 95 Constructing a binding instance using the element instance will add 96 this association. 97 """ 98 return self.__element
99 __element = None 100 101 __xsiNil = None
102 - def _isNil (self):
103 """Indicate whether this instance is U{nil 104 <http://www.w3.org/TR/xmlschema-1/#xsi_nil>}. 105 106 The value is set by the DOM and SAX parsers when building an instance 107 from a DOM element with U{xsi:nil 108 <http://www.w3.org/TR/xmlschema-1/#xsi_nil>} set to C{true}. 109 110 @return: C{None} if the element used to create the instance is not 111 U{nillable<http://www.w3.org/TR/xmlschema-1/#nillable>}. 112 If it is nillable, returns C{True} or C{False} depending on 113 whether the instance itself is U{nil<http://www.w3.org/TR/xmlschema-1/#xsi_nil>}. 114 """ 115 return self.__xsiNil
116 - def _setIsNil (self):
117 """Set the xsi:nil property of the instance. 118 119 @raise pyxb.NoNillableSupportError: the instance is not associated 120 with an element that is L{nillable 121 <pyxb.binding.basis.element.nillable>}. 122 """ 123 if self.__xsiNil is None: 124 raise pyxb.NoNillableSupportError(type(self)) 125 self.__xsiNil = True 126 self._resetContent()
127
128 - def _resetContent (self):
129 pass
130 131 __constructedWithValue = False
132 - def __checkNilCtor (self, args):
133 self.__constructedWithValue = (0 < len(args)) 134 if self.__xsiNil: 135 if self.__constructedWithValue: 136 raise pyxb.ContentInNilElementError(args[0]) 137 else: 138 # Types that descend from string will, when constructed from an 139 # element with empty content, appear to have no constructor value, 140 # while in fact an empty string should have been passed. 141 if issubclass(type(self), basestring): 142 self.__constructedWithValue = True
143 - def _constructedWithValue (self):
144 return self.__constructedWithValue
145 146 # Flag used to control whether we print a warning when creating a complex 147 # type instance that does not have an associated element. Not sure yet 148 # whether that'll be common practice or common error. 149 __WarnedUnassociatedElement = False 150
151 - def __init__ (self, *args, **kw):
152 # Strip keyword not used above this level. 153 element = kw.pop('_element', None) 154 is_nil = kw.pop('_nil', False) 155 super(_TypeBinding_mixin, self).__init__(*args, **kw) 156 if (element is None) or element.nillable(): 157 self.__xsiNil = is_nil 158 self.__checkNilCtor(args) 159 if element is not None: 160 self._setElement(element)
161 162 @classmethod
163 - def _PreFactory_vx (cls, args, kw):
164 """Method invoked upon entry to the Factory method. 165 166 This method is entitled to modify the keywords array. It can also 167 return a state value which is passed to _postFactory_vx.""" 168 return None
169
170 - def _postFactory_vx (cls, state):
171 """Method invoked prior to leaving the Factory method. 172 173 This is an instance method, and is given the state that was returned 174 by _PreFactory_vx.""" 175 return None
176 177 @classmethod
178 - def Factory (cls, *args, **kw):
179 """Provide a common mechanism to create new instances of this type. 180 181 The class constructor won't do, because you can't create 182 instances of union types. 183 184 This method may be overridden in subclasses (like STD_union). Pre- 185 and post-creation actions can be customized on a per-class instance by 186 overriding the L{_PreFactory_vx} and L{_postFactory_vx} methods. 187 188 @keyword _dom_node: If provided, the value must be a DOM node, the 189 content of which will be used to set the value of the instance. 190 191 @keyword _from_xml: If C{True}, the input must be either a DOM node or 192 a unicode string comprising a lexical representation of a value. This 193 is a further control on C{_apply_whitespace_facet} and arises from 194 cases where the lexical and value representations cannot be 195 distinguished by type. The default value is C{True} iff C{_dom_node} 196 is not C{None}. 197 198 @keyword _apply_whitespace_facet: If C{True} and this is a 199 simpleTypeDefinition with a whiteSpace facet, the first argument will 200 be normalized in accordance with that facet prior to invoking the 201 parent constructor. 202 203 @keyword _validate_constraints: If C{True}, any constructed value is 204 checked against constraints applied to the union as well as the member 205 type. 206 207 @keyword _require_value: If C{False} (default), it is permitted to 208 create a value without an initial value. If C{True} and no initial 209 value was provided, causes L{pyxb.MissingContentError} to be raised. 210 Only applies to simpleTypeDefinition instances; this is used when 211 creating values from DOM nodes. 212 """ 213 # Invoke _PreFactory_vx for the superseding class, which is where 214 # customizations will be found. 215 dom_node = kw.get('_dom_node') 216 kw.setdefault('_from_xml', dom_node is not None) 217 used_cls = cls._SupersedingClass() 218 state = used_cls._PreFactory_vx(args, kw) 219 rv = cls._DynamicCreate(*args, **kw) 220 rv._postFactory_vx(state) 221 if isinstance(dom_node, utility.Locatable_mixin): 222 rv._setLocation(dom_node.location) 223 return rv
224
225 - def _substitutesFor (self, element):
226 if (element is None) or (self._element() is None): 227 return False 228 return self._element().substitutesFor(element)
229 230 @classmethod
231 - def _IsUrType (cls):
232 """Return C{True} iff this is the ur-type. 233 234 The only ur-type is {http://www.w3.org/2001/XMLSchema}anyType. The 235 implementation of this method is overridden for 236 L{pyxb.binding.datatypes.anyType}.""" 237 return False
238 239 @classmethod
240 - def _RequireXSIType (cls, value_type):
241 if cls._IsUrType(): 242 # Require xsi:type if value refines xs:anyType 243 return value_type != cls 244 return cls._Abstract and value_type != cls._SupersedingClass()
245 246 @classmethod
247 - def _CompatibleValue (cls, value, **kw):
248 """Return a variant of the value that is compatible with this type. 249 250 Compatibility is defined relative to the type definition associated 251 with the element. The value C{None} is always compatible. If 252 C{value} has a Python type (e.g., C{int}) that is a superclass of the 253 required L{_TypeBinding_mixin} class (e.g., C{xs:byte}), C{value} is 254 used as a constructor parameter to return a new instance of the 255 required type. Note that constraining facets are applied here if 256 necessary (e.g., although a Python C{int} with value C{500} is 257 type-compatible with C{xs:byte}, it is outside the value space, and 258 compatibility will fail). 259 260 @keyword _convert_string_values: If C{True} (default) and the incoming value is 261 a string, an attempt will be made to form a compatible value by using 262 the string as a constructor argument to the this class. This flag is 263 set to C{False} when testing automaton transitions. 264 265 @raise pyxb.BadTypeValueError: if the value is not both 266 type-consistent and value-consistent with the element's type. 267 """ 268 convert_string_values = kw.get('_convert_string_values', True) 269 # None is always None 270 if value is None: 271 return None 272 # Already an instance? 273 if isinstance(value, cls): 274 # @todo: Consider whether we should change the associated _element 275 # of this value. (**Consider** it, don't just do it.) 276 return value 277 value_type = type(value) 278 # All string-based PyXB binding types use unicode, not str 279 if str == value_type: 280 value_type = unicode 281 282 # See if we got passed a Python value which needs to be "downcasted" 283 # to the _TypeBinding_mixin version. 284 if issubclass(cls, value_type): 285 return cls(value) 286 287 # See if we have a numeric type that needs to be cast across the 288 # numeric hierarchy. int to long is the *only* conversion we accept. 289 if isinstance(value, int) and issubclass(cls, long): 290 return cls(value) 291 292 # Same, but for boolean, which Python won't let us subclass 293 if isinstance(value, bool) and issubclass(cls, pyxb.binding.datatypes.boolean): 294 return cls(value) 295 296 # See if we have convert_string_values on, and have a string type that 297 # somebody understands. 298 if convert_string_values and (unicode == value_type): 299 return cls(value) 300 301 # Maybe this is a union? 302 if issubclass(cls, STD_union): 303 for mt in cls._MemberTypes: 304 try: 305 return mt._CompatibleValue(value, **kw) 306 except: 307 pass 308 309 # Any type is compatible with the corresponding ur-type 310 if (pyxb.binding.datatypes.anySimpleType == cls) and issubclass(value_type, simpleTypeDefinition): 311 return value 312 if pyxb.binding.datatypes.anyType == cls: 313 if not isinstance(value, _TypeBinding_mixin): 314 _log.info('Created %s instance from value of type %s', cls._ExpandedName, type(value)) 315 value = cls(value) 316 return value 317 318 # Is this the wrapper class that indicates we should create a binding 319 # from arguments? 320 if isinstance(value, pyxb.BIND): 321 return value.createInstance(cls.Factory, **kw) 322 323 # There may be other things that can be converted to the desired type, 324 # but we can't tell that from the type hierarchy. Too many of those 325 # things result in an undesirable loss of information: for example, 326 # when an all model supports both numeric and string transitions, the 327 # candidate is a number, and the string transition is tested first. 328 raise pyxb.BadTypeValueError('No conversion from %s to %s' % (value_type, cls))
329 330 @classmethod
331 - def _IsSimpleTypeContent (cls):
332 """Return True iff the content of this binding object is a simple type. 333 334 This is true only for descendents of simpleTypeDefinition and instances 335 of complexTypeDefinition that have simple type content.""" 336 raise pyxb.LogicError('Failed to override _TypeBinding_mixin._IsSimpleTypeContent')
337 338 # If the type supports wildcard attributes, this describes their 339 # constraints. (If it doesn't, this should remain None.) Supporting 340 # classes should override this value. 341 _AttributeWildcard = None 342 343 _AttributeMap = { } 344 """Map from expanded names to AttributeUse instances. Non-empty only in 345 L{complexTypeDefinition} subclasses.""" 346 347 @classmethod
348 - def __AttributesFromDOM (cls, node):
349 attribute_settings = { } 350 for ai in range(0, node.attributes.length): 351 attr = node.attributes.item(ai) 352 # NB: Specifically do not consider attr's NamespaceContext, since 353 # attributes do not accept a default namespace. 354 attr_en = pyxb.namespace.ExpandedName(attr) 355 356 # Ignore xmlns and xsi attributes; we've already handled those 357 if attr_en.namespace() in ( pyxb.namespace.XMLNamespaces, XSI ): 358 continue 359 360 value = attr.value 361 au = cls._AttributeMap.get(attr_en) 362 if au is None: 363 if cls._AttributeWildcard is None: 364 raise pyxb.UnrecognizedAttributeError('Attribute %s is not permitted in type %s' % (attr_en, cls._ExpandedName)) 365 attribute_settings[attr_en] = value 366 return attribute_settings
367
368 - def _setAttributesFromKeywordsAndDOM (self, kw, dom_node):
369 """Invoke self._setAttribute based on node attributes and keywords. 370 371 Though attributes can only legally appear in complexTypeDefinition 372 instances, delayed conditional validation requires caching them in 373 simpleTypeDefinition. 374 375 @param kw: keywords passed to the constructor. This map is mutated by 376 the call: keywords corresponding to recognized attributes are removed. 377 378 @param dom_node: an xml.dom Node instance, possibly C{None} 379 """ 380 381 # Extract keywords that match field names 382 attribute_settings = { } 383 if dom_node is not None: 384 attribute_settings.update(self.__AttributesFromDOM(dom_node)) 385 for fu in self._AttributeMap.values(): 386 iv = kw.pop(fu.id(), None) 387 if iv is not None: 388 attribute_settings[fu.name()] = iv 389 for (attr_en, value) in attribute_settings.items(): 390 self._setAttribute(attr_en, value)
391
392 - def toDOM (self, bds=None, parent=None, element_name=None):
393 """Convert this instance to a DOM node. 394 395 The name of the top-level element is either the name of the L{element} 396 instance associated with this instance, or the XML name of the type of 397 this instance. 398 399 @param bds: Support for customizing the generated document 400 @type bds: L{pyxb.utils.domutils.BindingDOMSupport} 401 @param parent: If C{None}, a standalone document is created; 402 otherwise, the created element is a child of the given element. 403 @type parent: C{xml.dom.Element} or C{None} 404 @rtype: C{xml.dom.Document} 405 """ 406 407 if bds is None: 408 bds = domutils.BindingDOMSupport() 409 need_xsi_type = bds.requireXSIType() 410 if isinstance(element_name, (str, unicode)): 411 element_name = pyxb.namespace.ExpandedName(bds.defaultNamespace(), element_name) 412 if (element_name is None) and (self._element() is not None): 413 element_binding = self._element() 414 element_name = element_binding.name() 415 need_xsi_type = need_xsi_type or element_binding.typeDefinition()._RequireXSIType(type(self)) 416 if element_name is None: 417 element_name = self._ExpandedName 418 element = bds.createChildElement(element_name, parent) 419 if need_xsi_type: 420 val_type_qname = self._ExpandedName.localName() 421 tns_prefix = bds.namespacePrefix(self._ExpandedName.namespace()) 422 if tns_prefix is not None: 423 val_type_qname = '%s:%s' % (tns_prefix, val_type_qname) 424 bds.addAttribute(element, XSI.type, val_type_qname) 425 self._toDOM_csc(bds, element) 426 bds.finalize() 427 return bds.document()
428
429 - def toxml (self, encoding=None, bds=None, root_only=False):
430 """Shorthand to get the object as an XML document. 431 432 If you want to set the default namespace, pass in a pre-configured 433 C{bds}. 434 435 @param encoding: The encoding to be used. See 436 @C{xml.dom.Node.toxml()} for a description of why you should always 437 pass @C{'utf-8'} here. Because this method follows the contract of 438 the corresponding C{xml.dom.Node} method, it does not automatically 439 get the default PyXB output encoding. 440 441 @param bds: Optional L{pyxb.utils.domutils.BindingDOMSupport} instance 442 to use for creation. If not provided (default), a new generic one is 443 created. 444 """ 445 dom = self.toDOM(bds) 446 if root_only: 447 dom = dom.documentElement 448 return dom.toxml(encoding)
449
450 - def _toDOM_csc (self, dom_support, parent):
451 assert parent is not None 452 if self.__xsiNil: 453 dom_support.addAttribute(parent, XSI.nil, 'true') 454 return getattr(super(_TypeBinding_mixin, self), '_toDOM_csc', lambda *_args,**_kw: dom_support)(dom_support, parent)
455
456 - def _validateBinding_vx (self):
457 """Override in subclasses for type-specific validation of instance 458 content. 459 460 @return: C{True} if the instance validates 461 @raise pyxb.BindingValidationError: complex content does not match model 462 @raise pyxb.BadTypeValueError: simple content fails to satisfy constraints 463 """ 464 raise pyxb.IncompleteImplementationError('%s did not override _validateBinding_vx' % (type(self),))
465
466 - def validateBinding (self):
467 """Check whether the binding content matches its content model. 468 469 @return: C{True} if validation succeeds. 470 @raise pyxb.BindingValidationError: complex content does not match model 471 @raise pyxb.BadTypeValueError: simple content fails to satisfy constraints 472 """ 473 if self._PerformValidation(): 474 self._validateBinding_vx() 475 return True
476
477 - def _postDOMValidate (self):
478 self.validateBinding() 479 return self
480 481 @classmethod
482 - def _Name (cls):
483 if cls._ExpandedName is not None: 484 name = str(cls._ExpandedName) 485 else: 486 name = str(type(cls)) 487 return name
488
489 -class _DynamicCreate_mixin (pyxb.cscRoot):
490 """Helper to allow overriding the implementation class. 491 492 Generally we'll want to augment the generated bindings by subclassing 493 them, and adding functionality to the subclass. This mix-in provides a 494 way to communicate the existence of the superseding subclass back to the 495 binding infrastructure, so that when it creates an instance it uses the 496 subclass rather than the unaugmented binding class. 497 498 When a raw generated binding is subclassed, L{_SetSupersedingClass} should be 499 invoked on the raw class passing in the superseding subclass. E.g.:: 500 501 class mywsdl (raw.wsdl): 502 pass 503 raw.wsdl._SetSupersedingClass(mywsdl) 504 505 """ 506 507 @classmethod
509 return '_%s__SupersedingClass' % (cls.__name__,)
510 511 @classmethod
513 return '_%s__AlternativeConstructor' % (cls.__name__,)
514 515 @classmethod
516 - def _SupersedingClass (cls):
517 """Return the class stored in the class reference attribute.""" 518 return getattr(cls, cls.__SupersedingClassAttribute(), cls)
519 520 @classmethod
521 - def _AlternativeConstructor (cls):
522 """Return the class stored in the class reference attribute.""" 523 rv = getattr(cls, cls.__AlternativeConstructorAttribute(), None) 524 if isinstance(rv, tuple): 525 rv = rv[0] 526 return rv
527 528 @classmethod
529 - def _SetSupersedingClass (cls, superseding):
530 """Set the class reference attribute. 531 532 @param superseding: A Python class that is a subclass of this class. 533 """ 534 assert (superseding is None) or issubclass(superseding, cls) 535 if superseding is None: 536 cls.__dict__.pop(cls.__SupersedingClassAttribute(), None) 537 else: 538 setattr(cls, cls.__SupersedingClassAttribute(), superseding) 539 return superseding
540 541 @classmethod
542 - def _SetAlternativeConstructor (cls, alternative_constructor):
543 attr = cls.__AlternativeConstructorAttribute() 544 if alternative_constructor is None: 545 cls.__dict__.pop(attr, None) 546 else: 547 # Need to use a tuple as the value: if you use an invokable, this 548 # ends up converting it from a function to an unbound method, 549 # which is not what we want. 550 setattr(cls, attr, (alternative_constructor,)) 551 assert cls._AlternativeConstructor() == alternative_constructor 552 return alternative_constructor
553 554 @classmethod
555 - def _DynamicCreate (cls, *args, **kw):
556 """Invoke the constructor for this class or the one that supersedes it.""" 557 ctor = cls._AlternativeConstructor() 558 if ctor is None: 559 ctor = cls._SupersedingClass() 560 try: 561 return ctor(*args, **kw) 562 except TypeError, e: 563 raise pyxb.BadTypeValueError(e)
564
565 -class simpleTypeDefinition (_TypeBinding_mixin, utility._DeconflictSymbols_mixin, _DynamicCreate_mixin):
566 """L{simpleTypeDefinition} is a base class that is part of the 567 hierarchy of any class that represents the Python datatype for a 568 L{SimpleTypeDefinition<pyxb.xmlschema.structures.SimpleTypeDefinition>}. 569 570 @note: This class, or a descendent of it, must be the first class 571 in the method resolution order when a subclass has multiple 572 parents. Otherwise, constructor keyword arguments may not be 573 removed before passing them on to Python classes that do not 574 accept them. 575 """ 576 577 # A map from leaf classes in the facets module to instance of 578 # those classes that constrain or otherwise affect the datatype. 579 # Note that each descendent of simpleTypeDefinition has its own map. 580 __FacetMap = {} 581 582 _ReservedSymbols = _TypeBinding_mixin._ReservedSymbols.union(set([ 'XsdLiteral', 'xsdLiteral', 583 'XsdSuperType', 'XsdPythonType', 'XsdConstraintsOK', 584 'xsdConstraintsOK', 'XsdValueLength', 'xsdValueLength', 585 'PythonLiteral', 'pythonLiteral', 586 'SimpleTypeDefinition' ])) 587 """Symbols that remain the responsibility of this class. Any 588 public symbols in generated binding subclasses are deconflicted 589 by providing an alternative name in the subclass. (There 590 currently are no public symbols in generated SimpleTypeDefinion 591 bindings.""" 592 593 594 # Determine the name of the class-private facet map. For the base class 595 # this should produce the same attribute name as Python's privatization 596 # scheme. 597 __FacetMapAttributeNameMap = { } 598 @classmethod
599 - def __FacetMapAttributeName (cls):
600 """ """ 601 ''' 602 if cls == simpleTypeDefinition: 603 return '_%s__FacetMap' % (cls.__name__.strip('_'),) 604 605 # It is not uncommon for a class in one namespace to extend a class of 606 # the same name in a different namespace, so encode the namespace URI 607 # in the attribute name (if it is part of a namespace). 608 ns_uri = '' 609 try: 610 ns_uri = cls._ExpandedName.namespaceURI() 611 except Exception: 612 pass 613 nm = '_' + utility.MakeIdentifier('%s_%s_FacetMap' % (ns_uri, cls.__name__.strip('_'))) 614 ''' 615 nm = cls.__FacetMapAttributeNameMap.get(cls) 616 if nm is None: 617 nm = cls.__name__ 618 if nm.endswith('_'): 619 nm += '1' 620 if cls == simpleTypeDefinition: 621 nm = '_%s__FacetMap' % (nm,) 622 else: 623 # It is not uncommon for a class in one namespace to extend a class of 624 # the same name in a different namespace, so encode the namespace URI 625 # in the attribute name (if it is part of a namespace). 626 ns_uri = '' 627 try: 628 ns_uri = cls._ExpandedName.namespaceURI() 629 except Exception: 630 pass 631 nm = '_' + utility.MakeIdentifier('%s_%s_FacetMap' % (ns_uri, nm)) 632 cls.__FacetMapAttributeNameMap[cls] = nm 633 return nm
634 635 @classmethod
636 - def _FacetMap (cls):
637 """Return a reference to the facet map for this datatype. 638 639 The facet map is a map from leaf facet classes to instances of those 640 classes that constrain or otherwise apply to the lexical or value 641 space of the datatype. Classes may inherit their facet map from their 642 superclass, or may create a new class instance if the class adds a new 643 constraint type. 644 645 :raise AttributeError: if the facet map has not been defined""" 646 return getattr(cls, cls.__FacetMapAttributeName())
647 648 @classmethod
649 - def _InitializeFacetMap (cls, *args):
650 """Initialize the facet map for this datatype. 651 652 This must be called exactly once, after all facets belonging to the 653 datatype have been created. 654 655 :raise pyxb.LogicError: if called multiple times (on the same class) 656 :raise pyxb.LogicError: if called when a parent class facet map has not been initialized 657 :return: the facet map""" 658 fm = None 659 try: 660 fm = cls._FacetMap() 661 except AttributeError: 662 pass 663 if fm is not None: 664 raise pyxb.LogicError('%s facet map initialized multiple times: %s' % (cls.__name__, cls.__FacetMapAttributeName())) 665 666 # Search up the type hierarchy to find the nearest ancestor that has a 667 # facet map. This gets a bit tricky: if we hit the ceiling early 668 # because the PSTD hierarchy re-based itself on a new Python type, we 669 # have to jump to the XsdSuperType. 670 source_class = cls 671 while fm is None: 672 # Assume we're staying in this hierarchy. Include source_class in 673 # the candidates, since we might have jumped to it. 674 for super_class in source_class.mro(): 675 assert super_class is not None 676 if (super_class == simpleTypeDefinition): # and (source_class.XsdSuperType() is not None): 677 break 678 if issubclass(super_class, simpleTypeDefinition): 679 try: 680 fm = super_class._FacetMap() 681 break 682 except AttributeError: 683 pass 684 if fm is None: 685 try: 686 source_class = source_class.XsdSuperType() 687 except AttributeError: 688 source_class = None 689 if source_class is None: 690 fm = { } 691 if fm is None: 692 raise pyxb.LogicError('%s is not a child of simpleTypeDefinition' % (cls.__name__,)) 693 fm = fm.copy() 694 for facet in args: 695 fm[type(facet)] = facet 696 setattr(cls, cls.__FacetMapAttributeName(), fm) 697 return fm
698 699 @classmethod
700 - def _ConvertArguments_vx (cls, args, kw):
701 return args
702 703 @classmethod
704 - def _ConvertArguments (cls, args, kw):
705 """Pre-process the arguments. 706 707 This is used before invoking the parent constructor. One application 708 is to apply the whitespace facet processing; if such a request is in 709 the keywords, it is removed so it does not propagate to the 710 superclass. Another application is to convert the arguments from a 711 string to a list. Binding-specific applications are performed in the 712 overloaded L{_ConvertArguments_vx} method.""" 713 dom_node = kw.pop('_dom_node', None) 714 from_xml = kw.get('_from_xml', dom_node is not None) 715 if dom_node is not None: 716 text_content = domutils.ExtractTextContent(dom_node) 717 if text_content is not None: 718 args = (domutils.ExtractTextContent(dom_node),) + args 719 kw['_apply_whitespace_facet'] = True 720 apply_whitespace_facet = kw.pop('_apply_whitespace_facet', from_xml) 721 if (0 < len(args)) and isinstance(args[0], types.StringTypes) and apply_whitespace_facet: 722 cf_whitespace = getattr(cls, '_CF_whiteSpace', None) 723 if cf_whitespace is not None: 724 norm_str = unicode(cf_whitespace.normalizeString(args[0])) 725 args = (norm_str,) + args[1:] 726 kw['_from_xml'] = from_xml 727 return cls._ConvertArguments_vx(args, kw)
728 729 # Must override new, because new gets invoked before init, and usually 730 # doesn't accept keywords. In case it does (e.g., datetime.datetime), 731 # only remove the ones that would normally be interpreted by this class. 732 # Do the same argument conversion as is done in init. Trap errors and 733 # convert them to BadTypeValue errors. 734 # 735 # Note: We explicitly do not validate constraints here. That's 736 # done in the normal constructor; here, we might be in the process 737 # of building a value that eventually will be legal, but isn't 738 # yet.
739 - def __new__ (cls, *args, **kw):
740 # PyXBFactoryKeywords 741 kw.pop('_validate_constraints', None) 742 kw.pop('_require_value', None) 743 kw.pop('_element', None) 744 kw.pop('_fallback_namespace', None) 745 kw.pop('_nil', None) 746 # ConvertArguments will remove _element and _apply_whitespace_facet 747 dom_node = kw.get('_dom_node') 748 args = cls._ConvertArguments(args, kw) 749 kw.pop('_from_xml', dom_node is not None) 750 assert issubclass(cls, _TypeBinding_mixin) 751 try: 752 rv = super(simpleTypeDefinition, cls).__new__(cls, *args, **kw) 753 rv._setAttributesFromKeywordsAndDOM(kw, dom_node) 754 return rv 755 except ValueError, e: 756 raise pyxb.BadTypeValueError(e) 757 except OverflowError, e: 758 raise pyxb.BadTypeValueError(e)
759 760 # Validate the constraints after invoking the parent constructor, 761 # unless told not to.
762 - def __init__ (self, *args, **kw):
763 """Initialize a newly created STD instance. 764 765 Usually there is one positional argument, which is a value that can be 766 converted to the underlying Python type. 767 768 @keyword _validate_constraints: If True (default), the newly 769 constructed value is checked against its constraining facets. 770 @type _validate_constraints: C{bool} 771 """ 772 # PyXBFactoryKeywords 773 validate_constraints = kw.pop('_validate_constraints', self._PerformValidation()) 774 require_value = kw.pop('_require_value', False) 775 # _ConvertArguments handles _dom_node and _apply_whitespace_facet 776 # TypeBinding_mixin handles _nil and _element 777 args = self._ConvertArguments(args, kw) 778 try: 779 super(simpleTypeDefinition, self).__init__(*args, **kw) 780 except OverflowError, e: 781 raise pyxb.BadTypeValueError(e) 782 if require_value and (not self._constructedWithValue()): 783 raise pyxb.MissingContentError('missing value') 784 785 if validate_constraints: 786 self.xsdConstraintsOK()
787 788 789 # The class attribute name used to store the reference to the STD 790 # component instance must be unique to the class, not to this base class. 791 # Otherwise we mistakenly believe we've already associated a STD instance 792 # with a class (e.g., xsd:normalizedString) when in fact it's associated 793 # with the superclass (e.g., xsd:string) 794 @classmethod
795 - def __STDAttrName (cls):
796 return '_%s__SimpleTypeDefinition' % (cls.__name__,)
797 798 @classmethod
799 - def _SimpleTypeDefinition (cls, std):
800 """Set the L{pyxb.xmlschema.structures.SimpleTypeDefinition} instance 801 associated with this binding.""" 802 attr_name = cls.__STDAttrName() 803 if hasattr(cls, attr_name): 804 old_value = getattr(cls, attr_name) 805 if old_value != std: 806 raise pyxb.LogicError('%s: Attempt to override existing STD %s with %s' % (cls, old_value.name(), std.name())) 807 setattr(cls, attr_name, std)
808 809 @classmethod
810 - def SimpleTypeDefinition (cls):
811 """Return the SimpleTypeDefinition instance for the given 812 class. 813 814 This should only be invoked when generating bindings. 815 816 @raise pyxb.IncompleteImplementationError: no STD instance has been 817 associated with the class. 818 819 """ 820 attr_name = cls.__STDAttrName() 821 if hasattr(cls, attr_name): 822 return getattr(cls, attr_name) 823 raise pyxb.IncompleteImplementationError('%s: No STD available' % (cls,))
824 825 @classmethod
826 - def XsdLiteral (cls, value):
827 """Convert from a python value to a string usable in an XML 828 document. 829 830 This should be implemented in the subclass.""" 831 raise pyxb.LogicError('%s does not implement XsdLiteral' % (cls,))
832
833 - def xsdLiteral (self):
834 """Return text suitable for representing the value of this 835 instance in an XML document. 836 837 The base class implementation delegates to the object class's 838 XsdLiteral method.""" 839 if self._isNil(): 840 return '' 841 return self.XsdLiteral(self)
842 843 @classmethod
844 - def XsdSuperType (cls):
845 """Find the nearest parent class in the PST hierarchy. 846 847 The value for anySimpleType is None; for all others, it's a 848 primitive or derived PST descendent (including anySimpleType).""" 849 for sc in cls.mro(): 850 if sc == cls: 851 continue 852 if simpleTypeDefinition == sc: 853 # If we hit the PST base, this is a primitive type or 854 # otherwise directly descends from a Python type; return 855 # the recorded XSD supertype. 856 return cls._XsdBaseType 857 if issubclass(sc, simpleTypeDefinition): 858 return sc 859 raise pyxb.LogicError('No supertype found for %s' % (cls,))
860 861 @classmethod
862 - def _XsdConstraintsPreCheck_vb (cls, value):
863 """Pre-extended class method to verify other things before 864 checking constraints. 865 866 This is used for list types, to verify that the values in the 867 list are acceptable, and for token descendents, to check the 868 lexical/value space conformance of the input. 869 """ 870 super_fn = getattr(super(simpleTypeDefinition, cls), '_XsdConstraintsPreCheck_vb', lambda *a,**kw: value) 871 return super_fn(value)
872 873 # Cache of pre-computed sequences of class facets in the order required 874 # for constraint validation 875 __ClassFacetSequence = { } 876 877 @classmethod
878 - def XsdConstraintsOK (cls, value):
879 """Validate the given value against the constraints on this class. 880 881 @raise pyxb.BadTypeValueError: if any constraint is violated. 882 """ 883 884 value = cls._XsdConstraintsPreCheck_vb(value) 885 886 facet_values = cls.__ClassFacetSequence.get(cls) 887 if facet_values is None: 888 # Constraints for simple type definitions are inherited. Check them 889 # from least derived to most derived. 890 classes = [ _x for _x in cls.mro() if issubclass(_x, simpleTypeDefinition) ] 891 classes.reverse() 892 cache_result = True 893 facet_values = [] 894 for clazz in classes: 895 # When setting up the datatypes, if we attempt to validate 896 # something before the facets have been initialized (e.g., a 897 # nonNegativeInteger used as a length facet for the parent 898 # integer datatype), just ignore that for now. Don't cache 899 # the value, though, since a subsequent check after 900 # initialization should succceed. 901 try: 902 clazz_facets = clazz._FacetMap().values() 903 except AttributeError: 904 cache_result = False 905 clazz_facets = [] 906 for v in clazz_facets: 907 if not (v in facet_values): 908 facet_values.append(v) 909 if cache_result: 910 cls.__ClassFacetSequence[cls] = facet_values 911 for f in facet_values: 912 if not f.validateConstraint(value): 913 raise pyxb.BadTypeValueError('%s violation for %s in %s' % (f.Name(), value, cls.__name__)) 914 return value
915
916 - def xsdConstraintsOK (self):
917 """Validate the value of this instance against its constraints.""" 918 return self.XsdConstraintsOK(self)
919
920 - def _validateBinding_vx (self):
921 if not self._isNil(): 922 self._checkValidValue() 923 return True
924 925 @classmethod
926 - def XsdValueLength (cls, value):
927 """Return the length of the given value. 928 929 The length is calculated by a subclass implementation of 930 _XsdValueLength_vx in accordance with 931 http://www.w3.org/TR/xmlschema-2/#rf-length. 932 933 The return value is a non-negative integer, or C{None} if length 934 constraints should be considered trivially satisfied (as with 935 QName and NOTATION). 936 937 :raise pyxb.LogicError: the provided value is not an instance of cls. 938 :raise pyxb.LogicError: an attempt is made to calculate a length for 939 an instance of a type that does not support length calculations. 940 """ 941 assert isinstance(value, cls) 942 if not hasattr(cls, '_XsdValueLength_vx'): 943 raise pyxb.LogicError('Class %s does not support length validation' % (cls.__name__,)) 944 return cls._XsdValueLength_vx(value)
945
946 - def xsdValueLength (self):
947 """Return the length of this instance within its value space. 948 949 See XsdValueLength.""" 950 return self.XsdValueLength(self)
951 952 @classmethod
953 - def PythonLiteral (cls, value):
954 """Return a string which can be embedded into Python source to 955 represent the given value as an instance of this class.""" 956 class_name = cls.__name__ 957 return '%s(%s)' % (class_name, repr(value))
958
959 - def pythonLiteral (self):
960 """Return a string which can be embedded into Python source to 961 represent the value of this instance.""" 962 return self.PythonLiteral(self)
963
964 - def _toDOM_csc (self, dom_support, parent):
965 assert parent is not None 966 parent.appendChild(dom_support.document().createTextNode(self.xsdLiteral())) 967 return getattr(super(simpleTypeDefinition, self), '_toDOM_csc', lambda *_args,**_kw: dom_support)(dom_support, parent)
968 969 @classmethod
970 - def _IsSimpleTypeContent (cls):
971 """STDs have simple type content.""" 972 return True
973 974 @classmethod
975 - def _IsValidValue (self, value):
976 try: 977 self._CheckValidValue(value) 978 return True 979 except pyxb.PyXBException: 980 pass 981 return False
982 983 @classmethod
984 - def _CheckValidValue (cls, value):
985 986 """NB: Invoking this on a value that is a list will, if necessary, 987 replace the members of the list with new values that are of the 988 correct item type. This is permitted because only with lists is it 989 possible to bypass the normal content validation (by invoking 990 append/extend on the list instance).""" 991 if value is None: 992 raise pyxb.BadTypeValueError('None is not a valid instance of %s' % (cls,)) 993 value_class = cls 994 if issubclass(cls, STD_list): 995 try: 996 iter(value) 997 except TypeError: 998 raise pyxb.BadTypeValueError('%s cannot have non-iterable value type %s' % (cls, type(value))) 999 for v in value: 1000 if not cls._ItemType._IsValidValue(v): 1001 raise pyxb.BadTypeValueError('%s cannot have member of type %s (want %s)' % (cls, type(v), cls._ItemType)) 1002 else: 1003 if issubclass(cls, STD_union): 1004 value_class = None 1005 for mt in cls._MemberTypes: 1006 if mt._IsValidValue(value): 1007 value_class = mt 1008 break 1009 if value_class is None: 1010 raise pyxb.BadTypeValueError('%s cannot have value type %s' % (cls, type(value))) 1011 #if not (isinstance(value, value_class) or issubclass(value_class, type(value))): 1012 if not isinstance(value, value_class): 1013 raise pyxb.BadTypeValueError('Value type %s is not valid for %s' % (type(value), cls)) 1014 value_class.XsdConstraintsOK(value)
1015
1016 - def _checkValidValue (self):
1017 self._CheckValidValue(self)
1018
1019 - def _isValidValue (self):
1020 self._IsValidValue(self)
1021
1022 - def _setAttribute (self, attr_en, value):
1023 raise pyxb.UnrecognizedAttributeError('Attribute %s is not permitted in simple type %s' % (attr_en, self._ExpandedName))
1024 1025 @classmethod
1026 - def _description (cls, name_only=False, user_documentation=True):
1027 name = cls._Name() 1028 if name_only: 1029 return name 1030 desc = [ name, ' restriction of ', cls.XsdSuperType()._description(name_only=True) ] 1031 if user_documentation and (cls._Documentation is not None): 1032 desc.extend(["\n", cls._Documentation]) 1033 return ''.join(desc)
1034
1035 -class STD_union (simpleTypeDefinition):
1036 """Base class for union datatypes. 1037 1038 This class descends only from simpleTypeDefinition. A pyxb.LogicError is 1039 raised if an attempt is made to construct an instance of a subclass of 1040 STD_union. Values consistent with the member types are constructed using 1041 the Factory class method. Values are validated using the _ValidatedMember 1042 class method. 1043 1044 Subclasses must provide a class variable _MemberTypes which is a 1045 tuple of legal members of the union.""" 1046 1047 _MemberTypes = None 1048 """A list of classes which are permitted as values of the union.""" 1049 1050 # Ick: If we don't declare this here, this class's map doesn't get 1051 # initialized. Alternative is to not descend from simpleTypeDefinition. 1052 # @todo Ensure that pattern and enumeration are valid constraints 1053 __FacetMap = {} 1054 1055 @classmethod
1056 - def Factory (cls, *args, **kw):
1057 """Given a value, attempt to create an instance of some member of this 1058 union. The first instance which can be legally created is returned. 1059 1060 @keyword _validate_constraints: If True (default), any constructed 1061 value is checked against constraints applied to the union as well as 1062 the member type. 1063 1064 @raise pyxb.BadTypeValueError: no member type will permit creation of 1065 an instance from the parameters in C{args} and C{kw}. 1066 """ 1067 1068 used_cls = cls._SupersedingClass() 1069 state = used_cls._PreFactory_vx(args, kw) 1070 1071 rv = None 1072 # NB: get, not pop: preserve it for the member type invocations 1073 validate_constraints = kw.get('_validate_constraints', cls._PerformValidation()) 1074 assert isinstance(validate_constraints, bool) 1075 if 0 < len(args): 1076 arg = args[0] 1077 try: 1078 rv = cls._ValidatedMember(arg) 1079 except pyxb.BadTypeValueError: 1080 pass 1081 if rv is None: 1082 kw['_validate_constraints'] = True 1083 for mt in cls._MemberTypes: 1084 try: 1085 rv = mt.Factory(*args, **kw) 1086 break 1087 except pyxb.BadTypeValueError: 1088 pass 1089 except ValueError: 1090 pass 1091 except: 1092 pass 1093 if rv is not None: 1094 if validate_constraints: 1095 cls.XsdConstraintsOK(rv) 1096 rv._postFactory_vx(state) 1097 return rv 1098 raise pyxb.BadTypeValueError('%s cannot construct union member from args %s' % (cls.__name__, args))
1099 1100 @classmethod
1101 - def _ValidatedMember (cls, value):
1102 """Validate the given value as a potential union member. 1103 1104 @raise pyxb.BadTypeValueError: the value is not an instance of a 1105 member type.""" 1106 if not isinstance(value, cls._MemberTypes): 1107 for mt in cls._MemberTypes: 1108 try: 1109 # Force validation so we get the correct type, otherwise 1110 # first member will be accepted. 1111 value = mt.Factory(value, _validate_constraints=True) 1112 return value 1113 except (TypeError, pyxb.BadTypeValueError): 1114 pass 1115 raise pyxb.BadTypeValueError('%s cannot hold a member of type %s' % (cls.__name__, value.__class__.__name__)) 1116 return value
1117
1118 - def __init__ (self, *args, **kw):
1119 raise pyxb.LogicError('%s: cannot construct instances of union' % (self.__class__.__name__,))
1120 1121 @classmethod
1122 - def _description (cls, name_only=False, user_documentation=True):
1123 name = cls._Name() 1124 if name_only: 1125 return name 1126 desc = [ name, ', union of '] 1127 desc.append(', '.join([ _td._description(name_only=True) for _td in cls._MemberTypes ])) 1128 return ''.join(desc)
1129 1130 @classmethod
1131 - def XsdLiteral (cls, value):
1132 """Convert from a binding value to a string usable in an XML document.""" 1133 return cls._ValidatedMember(value).xsdLiteral()
1134
1135 1136 -class STD_list (simpleTypeDefinition, types.ListType):
1137 """Base class for collection datatypes. 1138 1139 This class descends from the Python list type, and incorporates 1140 simpleTypeDefinition. Subclasses must define a class variable _ItemType 1141 which is a reference to the class of which members must be instances.""" 1142 1143 _ItemType = None 1144 """A reference to the binding class for items within this list.""" 1145 1146 # Ick: If we don't declare this here, this class's map doesn't get 1147 # initialized. Alternative is to not descend from simpleTypeDefinition. 1148 __FacetMap = {} 1149 1150 @classmethod
1151 - def _ValidatedItem (cls, value):
1152 """Verify that the given value is permitted as an item of this list. 1153 1154 This may convert the value to the proper type, if it is 1155 compatible but not an instance of the item type. Returns the 1156 value that should be used as the item, or raises an exception 1157 if the value cannot be converted.""" 1158 if isinstance(value, cls._ItemType): 1159 pass 1160 elif issubclass(cls._ItemType, STD_union): 1161 value = cls._ItemType._ValidatedMember(value) 1162 else: 1163 try: 1164 value = cls._ItemType(value) 1165 except (pyxb.BadTypeValueError, TypeError): 1166 raise pyxb.BadTypeValueError('Type %s has member of type %s, must be %s' % (cls.__name__, type(value).__name__, cls._ItemType.__name__)) 1167 return value
1168 1169 @classmethod
1170 - def _ConvertArguments_vx (cls, args, kw):
1171 # If the first argument is a string, split it on spaces and use the 1172 # resulting list of tokens. 1173 if 0 < len(args): 1174 arg1 = args[0] 1175 if isinstance(arg1, types.StringTypes): 1176 args = (arg1.split(),) + args[1:] 1177 arg1 = args[0] 1178 is_iterable = False 1179 try: 1180 iter(arg1) 1181 is_iterable = True 1182 except TypeError: 1183 pass 1184 if is_iterable: 1185 new_arg1 = [] 1186 for i in range(len(arg1)): 1187 new_arg1.append(cls._ValidatedItem(arg1[i])) 1188 args = (new_arg1,) + args[1:] 1189 super_fn = getattr(super(STD_list, cls), '_ConvertArguments_vx', lambda *a,**kw: args) 1190 return super_fn(args, kw)
1191 1192 @classmethod
1193 - def _XsdValueLength_vx (cls, value):
1194 return len(value)
1195 1196 @classmethod
1197 - def XsdLiteral (cls, value):
1198 """Convert from a binding value to a string usable in an XML document.""" 1199 return ' '.join([ cls._ItemType.XsdLiteral(_v) for _v in value ])
1200 1201 @classmethod
1202 - def _description (cls, name_only=False, user_documentation=True):
1203 name = cls._Name() 1204 if name_only: 1205 return name 1206 desc = [ name, ', list of ', cls._ItemType._description(name_only=True) ] 1207 return ''.join(desc)
1208 1209 # Convert a single value to the required type, if not already an instance 1210 @classmethod
1211 - def __ConvertOne (cls, v):
1212 return cls._ValidatedItem(v)
1213 1214 # Convert a sequence of values to the required type, if not already instances
1215 - def __convertMany (self, values):
1216 return [ self._ValidatedItem(_v) for _v in values ]
1217
1218 - def __setitem__ (self, key, value):
1219 if isinstance(key, slice): 1220 super(STD_list, self).__setitem__(key, self.__convertMany(value)) 1221 else: 1222 super(STD_list, self).__setitem__(key, self._ValidatedItem(value))
1223
1224 - def __setslice__ (self, start, end, values):
1225 super(STD_list, self).__setslice__(start, end, self.__convertMany(values))
1226
1227 - def __contains__ (self, item):
1228 return super(STD_list, self).__contains__(self._ValidatedItem(item))
1229 1230 # Standard mutable sequence methods, per Python Library Reference "Mutable Sequence Types" 1231
1232 - def append (self, x):
1233 super(STD_list, self).append(self._ValidatedItem(x))
1234
1235 - def extend (self, x, _from_xml=False):
1236 super(STD_list, self).extend(self.__convertMany(x))
1237
1238 - def count (self, x):
1239 return super(STD_list, self).count(self._ValidatedItem(x))
1240
1241 - def index (self, x, *args):
1242 return super(STD_list, self).index(self._ValidatedItem(x), *args)
1243
1244 - def insert (self, i, x):
1245 super(STD_list, self).insert(i, self._ValidatedItem(x))
1246
1247 - def remove (self, x):
1248 super(STD_list, self).remove(self._ValidatedItem(x))
1249
1250 -class element (utility._DeconflictSymbols_mixin, _DynamicCreate_mixin):
1251 """Class that represents a schema element. 1252 1253 Global and local elements are represented by instances of this class. 1254 """ 1255
1256 - def name (self):
1257 """The expanded name of the element within its scope.""" 1258 return self.__name
1259 __name = None 1260
1261 - def typeDefinition (self):
1262 """The L{_TypeBinding_mixin} subclass for values of this element.""" 1263 return self.__typeDefinition._SupersedingClass()
1264 __typeDefinition = None 1265
1266 - def scope (self):
1267 """The scope of the element. This is either C{None}, representing a 1268 top-level element, or an instance of C{complexTypeDefinition} for 1269 local elements.""" 1270 return self.__scope
1271 __scope = None 1272
1273 - def nillable (self):
1274 """Indicate whether values matching this element can have U{nil 1275 <http://www.w3.org/TR/xmlschema-1/#xsi_nil>} set.""" 1276 return self.__nillable
1277 __nillable = False 1278
1279 - def abstract (self):
1280 """Indicate whether this element is abstract (must use substitution 1281 group members for matches).""" 1282 return self.__abstract
1283 __abstract = False 1284
1285 - def documentation (self):
1286 """Contents of any documentation annotation in the definition.""" 1287 return self.__documentation
1288 __documentation = None 1289
1290 - def defaultValue (self):
1291 return self.__defaultValue
1292 __defaultValue = None 1293
1294 - def substitutionGroup (self):
1295 """The L{element} instance to whose substitution group this element 1296 belongs. C{None} if this element is not part of a substitution 1297 group.""" 1298 return self.__substitutionGroup
1299 - def _setSubstitutionGroup (self, substitution_group):
1300 self.__substitutionGroup = substitution_group 1301 if substitution_group is not None: 1302 self.substitutesFor = self._real_substitutesFor 1303 return self
1304 __substitutionGroup = None 1305
1306 - def findSubstituendUse (self, ctd_class):
1307 eu = ctd_class._ElementMap.get(self.name()) 1308 if eu is not None: 1309 return eu 1310 if self.substitutionGroup() is None: 1311 return None 1312 return self.substitutionGroup().findSubstituendUse(ctd_class)
1313
1314 - def _real_substitutesFor (self, other):
1315 """Determine whether an instance of this element can substitute for the other element. 1316 1317 See U{Substitution Group OK<http://www.w3.org/TR/xmlschema-1/#cos-equiv-derived-ok-rec>)}. 1318 1319 @todo: Do something about blocking constraints. This ignores them, as 1320 does everything leading to this point. 1321 """ 1322 if self.substitutionGroup() is None: 1323 return False 1324 if other is None: 1325 return False 1326 assert isinstance(other, element) 1327 # On the first call, other is likely to be the local element. We need 1328 # the global one. 1329 if other.scope() is not None: 1330 other = other.name().elementBinding() 1331 if other is None: 1332 return False 1333 assert other.scope() is None 1334 # Do both these refer to the same (top-level) element? 1335 if self.name().elementBinding() == other: 1336 return True 1337 return (self.substitutionGroup() == other) or self.substitutionGroup().substitutesFor(other)
1338
1339 - def substitutesFor (self, other):
1340 """Stub replaced by _real_substitutesFor when element supports substitution groups.""" 1341 return False
1342
1343 - def memberElement (self, name):
1344 """Return a reference to the element instance used for the given name 1345 within this element. 1346 1347 The type for this element must be a complex type definition.""" 1348 return self.typeDefinition()._UseForTag(name).elementBinding()
1349
1350 - def __init__ (self, name, type_definition, scope=None, nillable=False, abstract=False, default_value=None, substitution_group=None, documentation=None):
1351 """Create a new element binding. 1352 """ 1353 assert isinstance(name, pyxb.namespace.ExpandedName) 1354 self.__name = name 1355 self.__typeDefinition = type_definition 1356 self.__scope = scope 1357 self.__nillable = nillable 1358 self.__abstract = abstract 1359 self.__defaultValue = default_value 1360 self.__substitutionGroup = substitution_group 1361 self.__documentation = documentation 1362 super(element, self).__init__()
1363
1364 - def __call__ (self, *args, **kw):
1365 """Invoke the Factory method on the type associated with this element. 1366 1367 @keyword _dom_node: If set, specifies a DOM node that should be used 1368 for initialization. In that case, the L{createFromDOM} method is 1369 invoked instead of the type definition Factory method. 1370 1371 @note: Other keywords are passed to L{_TypeBinding_mixin.Factory}. 1372 1373 @raise pyxb.AbstractElementError: This element is abstract and no DOM 1374 node was provided. 1375 """ 1376 dom_node = kw.pop('_dom_node', None) 1377 assert dom_node is None, 'Cannot pass DOM node directly to element constructor; use createFromDOM' 1378 if '_element' in kw: 1379 raise pyxb.LogicError('Cannot set _element in element-based instance creation') 1380 kw['_element'] = self 1381 # Can't create instances of abstract elements. 1382 if self.abstract(): 1383 raise pyxb.AbstractElementError(self) 1384 return self.typeDefinition().Factory(*args, **kw)
1385
1386 - def compatibleValue (self, value, **kw):
1387 """Return a variant of the value that is compatible with this element. 1388 1389 This mostly defers to L{_TypeBinding_mixin._CompatibleValue}. 1390 1391 @raise pyxb.BadTypeValueError: if the value is not both 1392 type-consistent and value-consistent with the element's type. 1393 """ 1394 # None is always None 1395 if value is None: 1396 return None 1397 is_plural = kw.pop('is_plural', False) 1398 if is_plural: 1399 try: 1400 iter(value) 1401 except TypeError: 1402 raise pyxb.BadTypeValueError('Expected plural value, got %s' % (type(value),)) 1403 return [ self.compatibleValue(_v) for _v in value ] 1404 if isinstance(value, _TypeBinding_mixin) and (value._element() is not None) and value._element().substitutesFor(self): 1405 return value 1406 return self.typeDefinition()._CompatibleValue(value, **kw)
1407 1408 # element 1409 @classmethod
1410 - def AnyCreateFromDOM (cls, node, _fallback_namespace):
1411 if xml.dom.Node.DOCUMENT_NODE == node.nodeType: 1412 node = node.documentElement 1413 expanded_name = pyxb.namespace.ExpandedName(node, fallback_namespace=_fallback_namespace) 1414 elt = expanded_name.elementBinding() 1415 if elt is None: 1416 raise pyxb.UnrecognizedElementError(dom_node=node, element_name=expanded_name) 1417 assert isinstance(elt, pyxb.binding.basis.element) 1418 # Pass on the namespace to use when resolving unqualified qnames as in 1419 # xsi:type 1420 return elt._createFromDOM(node, expanded_name, _fallback_namespace=_fallback_namespace)
1421
1422 - def elementForName (self, name):
1423 """Return the element that should be used if this element binding is 1424 permitted and an element with the given name is encountered. 1425 1426 Normally, the incoming name matches the name of this binding, and 1427 C{self} is returned. If the incoming name is different, it is 1428 expected to be the name of a global element which is within this 1429 element's substitution group. In that case, the binding corresponding 1430 to the named element is return. 1431 1432 @return: An instance of L{element}, or C{None} if no element with the 1433 given name can be found. 1434 """ 1435 1436 # Name match means OK. 1437 if self.name() == name: 1438 return self 1439 # No name match means only hope is a substitution group, for which the 1440 # element must be top-level. 1441 top_elt = self.name().elementBinding() 1442 if top_elt is None: 1443 return None 1444 # Members of the substitution group must also be top-level. NB: If 1445 # named_elt == top_elt, then the adoptName call below improperly 1446 # associated the global namespace with a local element of the same 1447 # name; cf. test-namespace-uu:testBad. 1448 elt_en = top_elt.name().adoptName(name) 1449 assert 'elementBinding' in elt_en.namespace()._categoryMap(), 'No element bindings in %s' % (elt_en.namespace(),) 1450 named_elt = elt_en.elementBinding() 1451 if (named_elt is None) or (named_elt == top_elt): 1452 return None 1453 if named_elt.substitutesFor(top_elt): 1454 return named_elt 1455 return None
1456
1457 - def createFromDOM (self, node, expanded_name=None, fallback_namespace=None, **kw):
1458 """Create a binding instance from the given DOM node. 1459 1460 @keyword expanded_name: Optional name for the DOM node. If not 1461 present, is inferred from C{node}. 1462 1463 @keyword fallback_namespace: Optional namespace to use when resolving 1464 unqualified names. 1465 """ 1466 if xml.dom.Node.DOCUMENT_NODE == node.nodeType: 1467 node = node.documentElement 1468 if expanded_name is None: 1469 expanded_name = pyxb.namespace.ExpandedName(node, fallback_namespace=fallback_namespace) 1470 return self._createFromDOM(node, expanded_name, **kw)
1471
1472 - def _createFromDOM (self, node, expanded_name, **kw):
1473 """Create a binding instance from the given DOM node, using the 1474 provided name to identify the correct binding. 1475 1476 The context and information associated with this element is used to 1477 identify the actual element binding to use. By default, C{self} is 1478 used. If this element represents a term in a content model, the name 1479 and namespace of the incoming node may identify a different element. 1480 If that element is a member of this element's substitution group, the 1481 binding associated with the node's name will be used instead. 1482 1483 The type of object returned is determined by the type definition 1484 associated with the element binding and the value of any U{xsi:type 1485 <http://www.w3.org/TR/xmlschema-1/#xsi_type>} attribute found in the 1486 node, modulated by the configuration of L{XSI.ProcessTypeAttribute<pyxb.namespace.builtin._XMLSchema_instance.ProcessTypeAttribute>}. 1487 1488 Keyword parameters are passed to the factory method of the type 1489 associated with the selected element binding. See 1490 L{_TypeBinding_mixin} and any specializations of it. 1491 1492 @param expanded_name: The expanded name of the node. If the value is 1493 C{None}, defaults to the name of this element. (In the case of 1494 substitution groups, the default is wrong, but correct inference 1495 depends on context not available here.) 1496 1497 @keyword _fallback_namespace: Optional namespace to use when resolving 1498 unqualified type names. 1499 1500 @param node: The DOM node specifying the element content. If this is 1501 a (top-level) Document node, its element node is used. 1502 @type node: C{xml.dom.Node} 1503 @return: An instance of L{_TypeBinding_mixin} 1504 @raise pyxb.StructuralBadDocumentError: The node's name does identify an element binding. 1505 @raise pyxb.AbstractElementError: The element binding associated with the node is abstract. 1506 @raise pyxb.BadDocumentError: An U{xsi:type <http://www.w3.org/TR/xmlschema-1/#xsi_type>} attribute in the node fails to resolve to a recognized type 1507 @raise pyxb.BadDocumentError: An U{xsi:type <http://www.w3.org/TR/xmlschema-1/#xsi_type>} attribute in the node resolves to a type that is not a subclass of the type of the element binding. 1508 """ 1509 1510 # Bypass the useless top-level node and start with the element beneath 1511 # it. 1512 if xml.dom.Node.DOCUMENT_NODE == node.nodeType: 1513 node = node.documentElement 1514 1515 # Identify the element binding to be used for the given node. NB: 1516 # Even if found, this may not be equal to self, since we allow you to 1517 # use an abstract substitution group head to create instances from DOM 1518 # nodes that are in that group. 1519 fallback_namespace = kw.pop('_fallback_namespace', None) 1520 element_binding = self.elementForName(expanded_name) 1521 if element_binding is None: 1522 raise pyxb.StructuralBadDocumentError('Element %s cannot create from node %s' % (self.name(), expanded_name)) 1523 1524 # Can't create instances of abstract elements. @todo: Is there any 1525 # way this could be legal given an xsi:type attribute? I'm pretty 1526 # sure "no"... 1527 if element_binding.abstract(): 1528 raise pyxb.AbstractElementError(element_binding) 1529 1530 # Record the element to be associated with the created binding 1531 # instance. 1532 if '_element' in kw: 1533 raise pyxb.LogicError('Cannot set _element in element-based instance creation') 1534 kw['_element'] = element_binding 1535 1536 # Now determine the type binding for the content. If xsi:type is 1537 # used, it won't be the one built into the element binding. 1538 type_class = element_binding.typeDefinition() 1539 1540 # Get the namespace context for the value being created. If none is 1541 # associated, one will be created. Do not make assumptions about the 1542 # namespace context; if the user cared, she should have assigned a 1543 # context before calling this. 1544 ns_ctx = pyxb.namespace.resolution.NamespaceContext.GetNodeContext(node) 1545 (did_replace, type_class) = XSI._InterpretTypeAttribute(XSI.type.getAttribute(node), ns_ctx, fallback_namespace, type_class) 1546 1547 # Pass xsi:nil on to the constructor regardless of whether the element 1548 # is nillable. Another sop to SOAP-encoding WSDL fans who don't 1549 # bother to provide valid schema for their message content. 1550 is_nil = XSI.nil.getAttribute(node) 1551 if is_nil is not None: 1552 kw['_nil'] = pyxb.binding.datatypes.boolean(is_nil) 1553 1554 rv = type_class.Factory(_dom_node=node, _fallback_namespace=fallback_namespace, **kw) 1555 assert rv._element() == element_binding 1556 rv._setNamespaceContext(ns_ctx) 1557 return rv._postDOMValidate()
1558
1559 - def __str__ (self):
1560 return 'Element %s' % (self.name(),)
1561
1562 - def _description (self, name_only=False, user_documentation=True):
1563 name = str(self.name()) 1564 if name_only: 1565 return name 1566 desc = [ name, ' (', self.typeDefinition()._description(name_only=True), ')' ] 1567 if self.scope() is not None: 1568 desc.extend([', local to ', self.scope()._description(name_only=True) ]) 1569 if self.nillable(): 1570 desc.append(', nillable') 1571 if self.substitutionGroup() is not None: 1572 desc.extend([', substitutes for ', self.substitutionGroup()._description(name_only=True) ]) 1573 if user_documentation and (self.documentation() is not None): 1574 desc.extend(["\n", self.documentation() ]) 1575 return ''.join(desc)
1576
1577 -class enumeration_mixin (pyxb.cscRoot):
1578 """Marker in case we need to know that a PST has an enumeration constraint facet.""" 1579 1580 @classmethod
1581 - def values (cls):
1582 """Return a list of values that the enumeration can take.""" 1583 return cls._CF_enumeration.values()
1584 1585 @classmethod
1586 - def itervalues (cls):
1587 """Return a generator for the values that the enumeration can take.""" 1588 return cls._CF_enumeration.itervalues()
1589 1590 @classmethod
1591 - def items (cls):
1592 """Return the associated L{pyxb.binding.facet._EnumerationElement} instances.""" 1593 return cls._CF_enumeration.items()
1594 1595 @classmethod
1596 - def iteritems (cls):
1597 """Generate the associated L{pyxb.binding.facet._EnumerationElement} instances.""" 1598 return cls._CF_enumeration.iteritems()
1599
1600 -class complexTypeDefinition (_TypeBinding_mixin, utility._DeconflictSymbols_mixin, _DynamicCreate_mixin):
1601 """Base for any Python class that serves as the binding for an 1602 XMLSchema complexType. 1603 1604 Subclasses should define a class-level _AttributeMap variable which maps 1605 from the unicode tag of an attribute to the AttributeUse instance that 1606 defines it. Similarly, subclasses should define an _ElementMap variable. 1607 """ 1608 1609 _CT_EMPTY = 'EMPTY' #<<< No content 1610 _CT_SIMPLE = 'SIMPLE' #<<< Simple (character) content 1611 _CT_MIXED = 'MIXED' #<<< Children may be elements or other (e.g., character) content 1612 _CT_ELEMENT_ONLY = 'ELEMENT_ONLY' #<<< Expect only element content. 1613 1614 _ContentTypeTag = None 1615 1616 _TypeDefinition = None 1617 """Subclass of simpleTypeDefinition that corresponds to the type content. 1618 Only valid if _ContentTypeTag is _CT_SIMPLE""" 1619 1620 # A value that indicates whether the content model for this type supports 1621 # wildcard elements. Supporting classes should override this value. 1622 _HasWildcardElement = False 1623 1624 # Map from expanded names to ElementUse instances 1625 _ElementMap = { } 1626 """Map from expanded names to ElementUse instances.""" 1627 1628 # Per-instance map from tags to attribute values for wildcard attributes. 1629 # Value is C{None} if the type does not support wildcard attributes. 1630 __wildcardAttributeMap = None 1631
1632 - def wildcardAttributeMap (self):
1633 """Obtain access to wildcard attributes. 1634 1635 The return value is C{None} if this type does not support wildcard 1636 attributes. If wildcard attributes are allowed, the return value is a 1637 map from QNames to the unicode string value of the corresponding 1638 attribute. 1639 1640 @todo: The map keys should be namespace extended names rather than 1641 QNames, as the in-scope namespace may not be readily available to the 1642 user. 1643 """ 1644 return self.__wildcardAttributeMap
1645 1646 # Per-instance list of DOM nodes interpreted as wildcard elements. 1647 # Value is None if the type does not support wildcard elements. 1648 __wildcardElements = None 1649
1650 - def wildcardElements (self):
1651 """Obtain access to wildcard elements. 1652 1653 The return value is C{None} if the content model for this type does not 1654 support wildcard elements. If wildcard elements are allowed, the 1655 return value is a list of values corresponding to conformant 1656 unrecognized elements, in the order in which they were encountered. 1657 If the containing binding was created from an XML document and enough 1658 information was present to determine the binding of the member 1659 element, the value is a binding instance. Otherwise, the value is the 1660 original DOM Element node. 1661 """ 1662 return self.__wildcardElements
1663
1664 - def __init__ (self, *args, **kw):
1665 """Create a new instance of this binding. 1666 1667 Arguments are used as transition values along the content model. 1668 Keywords are passed to the constructor of any simple content, or used 1669 to initialize attribute and element values whose L{id 1670 <content.ElementUse.id>} (not L{name <content.ElementUse.name>}) 1671 matches the keyword. 1672 1673 @keyword _dom_node: The node to use as the source of binding content. 1674 @type _dom_node: C{xml.dom.Element} 1675 1676 @keyword _from_xml: See L{_TypeBinding_mixin.Factory} 1677 1678 """ 1679 1680 fallback_namespace = kw.pop('_fallback_namespace', None) 1681 is_nil = False 1682 dom_node = kw.pop('_dom_node', None) 1683 from_xml = kw.pop('_from_xml', dom_node is not None) 1684 if dom_node is not None: 1685 if isinstance(dom_node, pyxb.utils.utility.Locatable_mixin): 1686 self._setLocation(dom_node.location) 1687 if xml.dom.Node.DOCUMENT_NODE == dom_node.nodeType: 1688 dom_node = dom_node.documentElement 1689 #kw['_validate_constraints'] = False 1690 is_nil = XSI.nil.getAttribute(dom_node) 1691 if is_nil is not None: 1692 is_nil = kw['_nil'] = pyxb.binding.datatypes.boolean(is_nil) 1693 if self._AttributeWildcard is not None: 1694 self.__wildcardAttributeMap = { } 1695 if self._HasWildcardElement: 1696 self.__wildcardElements = [] 1697 if self._Abstract: 1698 raise pyxb.AbstractInstantiationError(type(self)) 1699 super(complexTypeDefinition, self).__init__(**kw) 1700 self.reset() 1701 self._setAttributesFromKeywordsAndDOM(kw, dom_node) 1702 for fu in self._ElementMap.values(): 1703 iv = kw.pop(fu.id(), None) 1704 if iv is not None: 1705 fu.set(self, iv) 1706 if kw and kw.pop('_strict_keywords', True): 1707 [ kw.pop(_fkw, None) for _fkw in self._PyXBFactoryKeywords ] 1708 if kw: 1709 raise pyxb.ExtraContentError(kw) 1710 if dom_node is not None: 1711 if self._CT_SIMPLE == self._ContentTypeTag: 1712 self.__initializeSimpleContent(args, dom_node) 1713 else: 1714 self._setContentFromDOM(dom_node, fallback_namespace) 1715 elif 0 < len(args): 1716 self.extend(args, _from_xml=from_xml) 1717 else: 1718 if self._CT_SIMPLE == self._ContentTypeTag: 1719 self.__initializeSimpleContent(args, dom_node)
1720
1721 - def __initializeSimpleContent (self, args, dom_node=None):
1722 # Don't propagate the keywords. Python base simple types usually 1723 # don't like them, and even if they do we're not using them here. (Do 1724 # need to propagate _nil, though, to correctly handle types derived 1725 # from basestring.) 1726 value = self._TypeDefinition.Factory(_require_value=not self._isNil(), _dom_node=dom_node, _nil=self._isNil(), *args) 1727 if value._constructedWithValue(): 1728 if self._isNil(): 1729 raise pyxb.ContentInNilElementError(value) 1730 else: 1731 self.append(value)
1732 1733 # Specify the symbols to be reserved for all CTDs. 1734 _ReservedSymbols = _TypeBinding_mixin._ReservedSymbols.union(set([ 'wildcardElements', 'wildcardAttributeMap', 1735 'xsdConstraintsOK', 'content', 'append', 'extend', 'value', 'reset' ])) 1736 1737 # None, or a reference to a ParticleModel instance that defines how to 1738 # reduce a DOM node list to the body of this element. 1739 _ContentModel = None 1740 1741 @classmethod
1742 - def _AddElement (cls, element):
1743 """Method used by generated code to associate the element binding with a use in this type. 1744 1745 This is necessary because all complex type classes appear in the 1746 module prior to any of the element instances (which reference type 1747 classes), so the association must be formed after the element 1748 instances are available.""" 1749 return cls._UseForTag(element.name())._setElementBinding(element)
1750 1751 @classmethod
1752 - def _UseForTag (cls, tag, raise_if_fail=True):
1753 """Return the ElementUse object corresponding to the element name. 1754 1755 @param tag: The L{ExpandedName} of an element in the class.""" 1756 rv = cls._ElementMap.get(tag) 1757 if (rv is None) and raise_if_fail: 1758 raise pyxb.NotAnElementError(tag, cls) 1759 return rv
1760
1761 - def __childrenForDOM (self):
1762 """Generate a list of children in the order in which they should be 1763 added to the parent when creating a DOM representation of this 1764 object. 1765 1766 @note: This is only used when L{pyxb.RequireValidWhenGenerating} has 1767 disabled validation. Consequently, it may not generate valid XML. 1768 """ 1769 order = [] 1770 for eu in self._ElementMap.values(): 1771 value = eu.value(self) 1772 if value is None: 1773 continue 1774 if isinstance(value, list) and eu.isPlural(): 1775 order.extend([ (eu, _v) for _v in value ]) 1776 continue 1777 order.append( (eu, value) ) 1778 return order
1779
1780 - def _validatedChildren (self):
1781 """Provide the child elements and non-element content in an order 1782 consistent with the content model. 1783 1784 Returns a sequence of tuples representing a valid path through the 1785 content model where each transition corresponds to one of the member 1786 element instances within this instance. The tuple is a pair 1787 comprising the L{content.ElementUse} instance and the value for the 1788 transition. 1789 1790 If the content of the instance does not validate against the content 1791 model, C{None} is returned. 1792 1793 The base class implementation uses the 1794 L{content.ParticleModel.validate} method. Subclasses may desire to 1795 override this in cases where the desired order is not maintained by 1796 model interpretation (for example, when an "all" model is used and the 1797 original element order is desired). See L{__childrenForDOM} as an 1798 example of an alternative approach. 1799 1800 @return: C{None} or a list as described above. 1801 """ 1802 if self._ContentTypeTag in (self._CT_EMPTY, self._CT_SIMPLE): 1803 return [] 1804 1805 if self._ContentModel is None: 1806 raise pyxb.NoContentModel(self) 1807 path = self._ContentModel.validate(self._symbolSet()) 1808 if path is not None: 1809 ( symbols, sequence ) = path 1810 if 0 == len(symbols): 1811 return sequence 1812 raise pyxb.BindingValidationError('Ungenerated symbols: %s' % (symbols,) ) 1813 return None
1814
1815 - def _symbolSet (self):
1816 """Return a map from L{content.ElementUse} instances to a list of 1817 values associated with that use. 1818 1819 This is used as the set of symbols available for transitions when 1820 validating content against a model. Note that the order of values 1821 within a use is likely to be significant, although the model cannot 1822 detect this. 1823 1824 The value C{None} should be used to provide a list of wildcard 1825 members. 1826 1827 If an element use has no associated values, it must not appear in the 1828 returned map. 1829 """ 1830 rv = { } 1831 for eu in self._ElementMap.values(): 1832 value = eu.value(self) 1833 if value is None: 1834 continue 1835 converter = eu.elementBinding().compatibleValue 1836 if eu.isPlural(): 1837 if 0 < len(value): 1838 rv[eu] = [ converter(_v) for _v in value ] 1839 else: 1840 rv[eu] = [ converter(value)] 1841 wce = self.wildcardElements() 1842 if (wce is not None) and (0 < len(wce)): 1843 rv[None] = wce[:] 1844 return rv
1845
1846 - def _validateAttributes (self):
1847 for au in self._AttributeMap.values(): 1848 au.validate(self)
1849
1850 - def _validateBinding_vx (self):
1851 if self._isNil(): 1852 if (self._IsSimpleTypeContent() and (self.__content is not None)) or self.__content: 1853 raise pyxb.ContentInNilElementError(self._ExpandedName) 1854 return True 1855 if self._IsSimpleTypeContent() and (self.__content is None): 1856 raise pyxb.MissingContentError(self._TypeDefinition) 1857 try: 1858 order = self._validatedChildren() 1859 except Exception, e: 1860 raise pyxb.BindingValidationError('Error matching content to binding model: %s' % (e,)) 1861 if order is None: 1862 raise pyxb.BindingValidationError('Unable to match content to binding model') 1863 for (eu, value) in order: 1864 if isinstance(value, _TypeBinding_mixin): 1865 value.validateBinding() 1866 elif eu is not None: 1867 _log.warning('Cannot validate value %s in field %s', value, eu.id()) 1868 self._validateAttributes() 1869 return True
1870
1871 - def _setAttribute (self, attr_en, value):
1872 au = self._AttributeMap.get(attr_en, None) 1873 if au is None: 1874 if self._AttributeWildcard is None: 1875 raise pyxb.UnrecognizedAttributeError('Attribute %s is not permitted in type %s' % (attr_en, self._ExpandedName)) 1876 self.__wildcardAttributeMap[attr_en] = value 1877 else: 1878 au.set(self, value) 1879 return au
1880
1881 - def xsdConstraintsOK (self):
1882 """Validate the content against the simple type. 1883 1884 @return: C{True} if the content validates against its type. 1885 @raise pyxb.NotSimpleContentError: this type does not have simple content. 1886 @raise pyxb.MissingContentError: the content of this type has not been set 1887 """ 1888 # @todo: type check 1889 if self._CT_SIMPLE != self._ContentTypeTag: 1890 raise pyxb.NotSimpleContentError(self) 1891 if self._isNil(): 1892 return True 1893 if self.value() is None: 1894 raise pyxb.MissingContentError(self) 1895 return self.value().xsdConstraintsOK()
1896 1897 __content = None
1898 - def content (self):
1899 """Return the content of the element. 1900 1901 This must be a complex type with complex content. The return value is 1902 a list of the element and non-element content in the order in which it 1903 was added. 1904 @raise pyxb.NotComplexContentError: this is not a complex type with mixed or element-only content 1905 """ 1906 if self._ContentTypeTag in (self._CT_EMPTY, self._CT_SIMPLE): 1907 raise pyxb.NotComplexContentError(str(self._ExpandedName)) 1908 return self.__content
1909
1910 - def value (self):
1911 """Return the value of the element. 1912 1913 This must be a complex type with simple content. The returned value 1914 is expected to be an instance of some L{simpleTypeDefinition} class. 1915 1916 @raise pyxb.NotSimpleContentError: this is not a complex type with simple content 1917 """ 1918 if self._CT_SIMPLE != self._ContentTypeTag: 1919 raise pyxb.NotSimpleContentError('%s (%s)' % (str(self._ExpandedName), type(self))) 1920 return self.__content
1921
1922 - def _resetContent (self):
1923 if self._ContentTypeTag in (self._CT_MIXED, self._CT_ELEMENT_ONLY): 1924 self.__setContent([]) 1925 else: 1926 self.__setContent(None)
1927 1928 __modelState = None
1929 - def reset (self):
1930 """Reset the instance. 1931 1932 This resets all element and attribute fields, and discards any 1933 recorded content. It resets the DFA to the initial state of the 1934 content model. 1935 """ 1936 1937 self._resetContent() 1938 for au in self._AttributeMap.values(): 1939 au.reset(self) 1940 for eu in self._ElementMap.values(): 1941 eu.reset(self) 1942 if self._ContentModel is not None: 1943 self.__modelState = self._ContentModel.newState() 1944 return self
1945 1946 @classmethod
1947 - def _ElementBindingUseForName (cls, element_name):
1948 """Determine what the given name means as an element in this type. 1949 1950 Normally, C{element_name} identifies an element definition within this 1951 type. If so, the returned C{element_use} identifies that definition, 1952 and the C{element_binding} is extracted from that use. 1953 1954 It may also be that the C{element_name} does not appear as an element 1955 definition, but that it identifies a global element. In that case, 1956 the returned C{element_binding} identifies the global element. If, 1957 further, that element is a member of a substitution group which does 1958 have an element definition in this class, then the returned 1959 C{element_use} identifies that definition. 1960 1961 If a non-C{None} C{element_use} is returned, there will be an 1962 associated C{element_binding}. However, it is possible to return a 1963 non-C{None} C{element_binding}, but C{None} as the C{element_use}. In 1964 that case, the C{element_binding} can be used to create a binding 1965 instance, but the content model will have to treat it as a wildcard. 1966 1967 @param element_name: The name of the element in this type, either an 1968 expanded name or a local name if the element has an absent namespace. 1969 1970 @return: C{( element_binding, element_use )} 1971 """ 1972 element_use = cls._ElementMap.get(element_name) 1973 element_binding = None 1974 if element_use is None: 1975 try: 1976 element_binding = element_name.elementBinding() 1977 except pyxb.NamespaceError: 1978 pass 1979 if element_binding is not None: 1980 element_use = element_binding.findSubstituendUse(cls) 1981 else: 1982 element_binding = element_use.elementBinding() 1983 return (element_binding, element_use)
1984
1985 - def append (self, value, element_use=None, maybe_element=True, _fallback_namespace=None, require_validation=True, _from_xml=False):
1986 """Add the value to the instance. 1987 1988 The value should be a DOM node or other value that is or can be 1989 converted to a binding instance. If the instance has a DFA state, the 1990 value must be permitted by the content model. 1991 1992 @raise pyxb.ExtraContentError: the value is not permitted at the 1993 current state of the content model. 1994 """ 1995 1996 # @todo: Allow caller to provide default element use; it's available 1997 # in saxer. 1998 element_binding = None 1999 if element_use is not None: 2000 from pyxb.binding import content 2001 assert isinstance(element_use, content.ElementUse) 2002 element_binding = element_use.elementBinding() 2003 assert element_binding is not None 2004 # Convert the value if it's XML and we recognize it. 2005 if isinstance(value, xml.dom.Node): 2006 _from_xml = True 2007 assert maybe_element 2008 assert element_binding is None 2009 node = value 2010 require_validation = pyxb._ParsingRequiresValid 2011 if xml.dom.Node.COMMENT_NODE == node.nodeType: 2012 # @todo: Note that we're allowing comments inside the bodies 2013 # of simple content elements, which isn't really Hoyle. 2014 return self 2015 if node.nodeType in (xml.dom.Node.TEXT_NODE, xml.dom.Node.CDATA_SECTION_NODE): 2016 value = node.data 2017 maybe_element = False 2018 else: 2019 # Do type conversion here 2020 assert xml.dom.Node.ELEMENT_NODE == node.nodeType 2021 expanded_name = pyxb.namespace.ExpandedName(node, fallback_namespace=_fallback_namespace) 2022 (element_binding, element_use) = self._ElementBindingUseForName(expanded_name) 2023 if element_binding is not None: 2024 value = element_binding._createFromDOM(node, expanded_name, _fallback_namespace=_fallback_namespace) 2025 else: 2026 # Might be a resolvable wildcard. See if we can convert it to an 2027 # element. 2028 try: 2029 ns = expanded_name.namespace() 2030 if ns is not None: 2031 for mr in ns.moduleRecords(): 2032 try: 2033 if (mr.module() is None) and (mr.modulePath() is not None): 2034 _log.info('Importing %s to get binding for wildcard %s', mr.modulePath(), expanded_name) 2035 mod = __import__(mr.modulePath()) 2036 for c in mr.modulePath().split('.')[1:]: 2037 mod = getattr(mod, c) 2038 mr._setModule(mod) 2039 # The module holding XMLSchema bindings 2040 # does not have a CreateFromDOM method, 2041 # and shouldn't since we need to convert 2042 # schema instances to DOM more carefully. 2043 # Other namespaces won't have a module if 2044 # the bindings were not imported; this is 2045 # probably worth a warning. 2046 if mr.module() is not None: 2047 value = mr.module().CreateFromDOM(node) 2048 elif mr.namespace() != pyxb.namespace.XMLSchema: 2049 _log.warning('No bindings available for %s', expanded_name) 2050 break 2051 except pyxb.UnrecognizedElementError, e: 2052 _log.info('Ignoring unrecognized element when creating binding for wildcard %s', expanded_name) 2053 except pyxb.PyXBException, e: 2054 _log.warning('Ignoring error when creating binding for wildcard %s', expanded_name, exc_info=e) 2055 except Exception: 2056 _log.exception('Unable to convert DOM node %s to Python instance', expanded_name) 2057 if (not maybe_element) and isinstance(value, basestring) and (self._ContentTypeTag in (self._CT_EMPTY, self._CT_ELEMENT_ONLY)): 2058 if (0 == len(value.strip())) and not self._isNil(): 2059 return self 2060 if self._isNil() and not self._IsSimpleTypeContent(): 2061 raise pyxb.ExtraContentError('%s: Content %s present in element with xsi:nil' % (type(self), value)) 2062 if maybe_element and (self.__modelState is not None): 2063 # Allows element content. 2064 if not require_validation: 2065 if element_use is not None: 2066 element_use.setOrAppend(self, value) 2067 return self 2068 if self.wildcardElements() is not None: 2069 self._appendWildcardElement(value) 2070 return self 2071 raise pyxb.StructuralBadDocumentError('Validation is required when no element_use can be found') 2072 else: 2073 ( consumed, underflow_exc ) = self.__modelState.step(self, value, element_use) 2074 if consumed: 2075 return self 2076 # If what we have is element content, we can't accept it, either 2077 # because the type doesn't accept element content or because it does 2078 # and what we got didn't match the content model. 2079 if (element_binding is not None) or isinstance(value, xml.dom.Node): 2080 raise pyxb.ExtraContentError('%s: Extra content %s starting with %s' % (self._ExpandedName, element_binding, value,)) 2081 2082 # We have something that doesn't seem to be an element. Are we 2083 # expecting simple content? 2084 if self._IsSimpleTypeContent(): 2085 if self.__content is not None: 2086 raise pyxb.ExtraContentError('Extra content starting with %s (already have %s)' % (value, self.__content)) 2087 if not self._isNil(): 2088 if not isinstance(value, self._TypeDefinition): 2089 value = self._TypeDefinition.Factory(value, _from_xml=_from_xml) 2090 self.__setContent(value) 2091 if require_validation: 2092 # NB: This only validates the value, not any associated 2093 # attributes, which is correct to be parallel to complex 2094 # content validation. 2095 self.xsdConstraintsOK() 2096 return self 2097 2098 # Do we allow non-element content? 2099 if not self._IsMixed(): 2100 raise pyxb.UnexpectedNonElementContentError(value) 2101 if isinstance(value, _TypeBinding_mixin): 2102 raise pyxb.ExtraContentError('Extra content starting with %s' % (value,)) 2103 2104 self._addContent(value, element_binding) 2105 return self
2106
2107 - def _appendWildcardElement (self, value):
2108 wcl = self.wildcardElements() 2109 if wcl is None: 2110 raise pyxb.UnrecognizedContentError(value, container=self) 2111 wcl.append(value)
2112
2113 - def extend (self, value_list, _fallback_namespace=None, _from_xml=False):
2114 """Invoke L{append} for each value in the list, in turn.""" 2115 [ self.append(_v, _fallback_namespace=_fallback_namespace, _from_xml=_from_xml) for _v in value_list ] 2116 return self
2117
2118 - def __setContent (self, value):
2119 self.__content = value
2120
2121 - def _addContent (self, child, element_binding):
2122 # This assert is inadequate in the case of plural/non-plural elements with an STD_list base type. 2123 # Trust that validation elsewhere was done correctly. 2124 #assert self._IsMixed() or (not self._PerformValidation()) or isinstance(child, _TypeBinding_mixin) or isinstance(child, types.StringTypes), 'Unrecognized child %s type %s' % (child, type(child)) 2125 assert not (self._ContentTypeTag in (self._CT_EMPTY, self._CT_SIMPLE)) 2126 if isinstance(child, _TypeBinding_mixin) and (child._element() is None): 2127 child._setElement(element_binding) 2128 self.__content.append(child)
2129 2130 @classmethod
2131 - def _IsMixed (cls):
2132 return (cls._CT_MIXED == cls._ContentTypeTag)
2133
2134 - def _postDOMValidate (self):
2135 if self._PerformValidation() and (not self._isNil()) and (self.__modelState is not None): 2136 self.__modelState.verifyComplete() 2137 self._validateAttributes() 2138 return self
2139
2140 - def _setContentFromDOM (self, node, _fallback_namespace):
2141 """Initialize the content of this element from the content of the DOM node.""" 2142 2143 self.extend(node.childNodes[:], _fallback_namespace) 2144 return self._postDOMValidate()
2145
2146 - def _setDOMFromAttributes (self, dom_support, element):
2147 """Add any appropriate attributes from this instance into the DOM element.""" 2148 for au in self._AttributeMap.values(): 2149 if pyxb._GenerationRequiresValid: 2150 au.validate(self) 2151 au.addDOMAttribute(dom_support, self, element) 2152 return element
2153
2154 - def _toDOM_csc (self, dom_support, parent):
2155 """Create a DOM element with the given tag holding the content of this instance.""" 2156 element = parent 2157 self._setDOMFromAttributes(dom_support, element) 2158 if self._isNil(): 2159 pass 2160 elif self._CT_EMPTY == self._ContentTypeTag: 2161 pass 2162 elif self._CT_SIMPLE == self._ContentTypeTag: 2163 assert self.value() is not None, '%s has no value' % (self,) 2164 element.appendChild(dom_support.document().createTextNode(self.value().xsdLiteral())) 2165 else: 2166 if pyxb._GenerationRequiresValid: 2167 order = self._validatedChildren() 2168 else: 2169 order = self.__childrenForDOM() 2170 if order is None: 2171 raise pyxb.DOMGenerationError('Binding value inconsistent with content model') 2172 for (eu, v) in order: 2173 assert v != self 2174 if eu is None: 2175 if isinstance(v, xml.dom.Node): 2176 dom_support.appendChild(v, element) 2177 else: 2178 v.toDOM(dom_support, parent) 2179 else: 2180 eu.toDOM(dom_support, parent, v) 2181 mixed_content = self.content() 2182 for mc in mixed_content: 2183 pass 2184 return getattr(super(complexTypeDefinition, self), '_toDOM_csc', lambda *_args,**_kw: dom_support)(dom_support, parent)
2185 2186 @classmethod
2187 - def _IsSimpleTypeContent (cls):
2188 """CTDs with simple content are simple; other CTDs are not.""" 2189 return cls._CT_SIMPLE == cls._ContentTypeTag
2190 2191 @classmethod
2192 - def _description (cls, name_only=False, user_documentation=True):
2193 name = cls._Name() 2194 if name_only: 2195 return name 2196 desc = [ name ] 2197 if cls._CT_EMPTY == cls._ContentTypeTag: 2198 desc.append(', empty content') 2199 elif cls._CT_SIMPLE == cls._ContentTypeTag: 2200 desc.extend([', simple content type ', cls._TypeDefinition._description(name_only=True)]) 2201 else: 2202 if cls._CT_MIXED == cls._ContentTypeTag: 2203 desc.append(', mixed content') 2204 else: 2205 assert cls._CT_ELEMENT_ONLY == cls._ContentTypeTag 2206 desc.append(', element-only content') 2207 if (0 < len(cls._AttributeMap)) or (cls._AttributeWildcard is not None): 2208 desc.append("\nAttributes:\n ") 2209 desc.append("\n ".join([ _au._description(user_documentation=False) for _au in cls._AttributeMap.values() ])) 2210 if cls._AttributeWildcard is not None: 2211 desc.append("\n Wildcard attribute(s)") 2212 if (0 < len(cls._ElementMap)) or cls._HasWildcardElement: 2213 desc.append("\nElements:\n ") 2214 desc.append("\n ".join([ _eu._description(user_documentation=False) for _eu in cls._ElementMap.values() ])) 2215 if cls._HasWildcardElement: 2216 desc.append("\n Wildcard element(s)") 2217 return ''.join(desc)
2218 2219 ## Local Variables: 2220 ## fill-column:78 2221 ## End: 2222