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

Source Code for Module pyxb.binding.basis

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