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