Merge pull request #136 from Rav3nPL/patch-1
[p2pool.git] / wstools / XMLSchema.py
1 # Copyright (c) 2003, The Regents of the University of California,
2 # through Lawrence Berkeley National Laboratory (subject to receipt of
3 # any required approvals from the U.S. Dept. of Energy).  All rights
4 # reserved. 
5 #
6 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
7 #
8 # This software is subject to the provisions of the Zope Public License,
9 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
10 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
11 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
12 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
13 # FOR A PARTICULAR PURPOSE.
14
15 ident = "$Id$"
16
17 import types, weakref, sys, warnings
18 from Namespaces import SCHEMA, XMLNS, SOAP, APACHE
19 from Utility import DOM, DOMException, Collection, SplitQName, basejoin
20 from StringIO import StringIO
21
22 # If we have no threading, this should be a no-op
23 try:
24     from threading import RLock
25 except ImportError:
26     class RLock:
27         def acquire():
28             pass
29         def release():
30             pass
31
32
33 # Collections in XMLSchema class
34
35 TYPES = 'types'
36 ATTRIBUTE_GROUPS = 'attr_groups'
37 ATTRIBUTES = 'attr_decl'
38 ELEMENTS = 'elements'
39 MODEL_GROUPS = 'model_groups'
40 BUILT_IN_NAMESPACES = [SOAP.ENC,] + SCHEMA.XSD_LIST + [APACHE.AXIS_NS]
41
42 def GetSchema(component):
43     """convience function for finding the parent XMLSchema instance.
44     """
45     parent = component
46     while not isinstance(parent, XMLSchema):
47         parent = parent._parent()
48     return parent
49     
50 class SchemaReader:
51     """A SchemaReader creates XMLSchema objects from urls and xml data.
52     """
53     
54     namespaceToSchema = {}
55     
56     def __init__(self, domReader=None, base_url=None):
57         """domReader -- class must implement DOMAdapterInterface
58            base_url -- base url string
59         """
60         self.__base_url = base_url
61         self.__readerClass = domReader
62         if not self.__readerClass:
63             self.__readerClass = DOMAdapter
64         self._includes = {}
65         self._imports = {}
66
67     def __setImports(self, schema):
68         """Add dictionary of imports to schema instance.
69            schema -- XMLSchema instance
70         """
71         for ns,val in schema.imports.items(): 
72             if self._imports.has_key(ns):
73                 schema.addImportSchema(self._imports[ns])
74
75     def __setIncludes(self, schema):
76         """Add dictionary of includes to schema instance.
77            schema -- XMLSchema instance
78         """
79         for schemaLocation, val in schema.includes.items(): 
80             if self._includes.has_key(schemaLocation):
81                 schema.addIncludeSchema(schemaLocation, self._imports[schemaLocation])
82
83     def addSchemaByLocation(self, location, schema):
84         """provide reader with schema document for a location.
85         """
86         self._includes[location] = schema
87
88     def addSchemaByNamespace(self, schema):
89         """provide reader with schema document for a targetNamespace.
90         """
91         self._imports[schema.targetNamespace] = schema
92
93     def loadFromNode(self, parent, element):
94         """element -- DOM node or document
95            parent -- WSDLAdapter instance
96         """
97         reader = self.__readerClass(element)
98         schema = XMLSchema(parent)
99         #HACK to keep a reference
100         schema.wsdl = parent
101         schema.setBaseUrl(self.__base_url)
102         schema.load(reader)
103         return schema
104         
105     def loadFromStream(self, file, url=None):
106         """Return an XMLSchema instance loaded from a file object.
107            file -- file object
108            url -- base location for resolving imports/includes.
109         """
110         reader = self.__readerClass()
111         reader.loadDocument(file)
112         schema = XMLSchema()
113         if url is not None:
114              schema.setBaseUrl(url)
115         schema.load(reader)
116         self.__setIncludes(schema)
117         self.__setImports(schema)
118         return schema
119
120     def loadFromString(self, data):
121         """Return an XMLSchema instance loaded from an XML string.
122            data -- XML string
123         """
124         return self.loadFromStream(StringIO(data))
125
126     def loadFromURL(self, url, schema=None):
127         """Return an XMLSchema instance loaded from the given url.
128            url -- URL to dereference
129            schema -- Optional XMLSchema instance.
130         """
131         reader = self.__readerClass()
132         if self.__base_url:
133             url = basejoin(self.__base_url,url)
134
135         reader.loadFromURL(url)
136         schema = schema or XMLSchema()
137         schema.setBaseUrl(url)
138         schema.load(reader)
139         self.__setIncludes(schema)
140         self.__setImports(schema)
141         return schema
142
143     def loadFromFile(self, filename):
144         """Return an XMLSchema instance loaded from the given file.
145            filename -- name of file to open
146         """
147         if self.__base_url:
148             filename = basejoin(self.__base_url,filename)
149         file = open(filename, 'rb')
150         try:
151             schema = self.loadFromStream(file, filename)
152         finally:
153             file.close()
154
155         return schema
156
157
158 class SchemaError(Exception): 
159     pass
160
161 class NoSchemaLocationWarning(Exception): 
162     pass
163
164
165 ###########################
166 # DOM Utility Adapters 
167 ##########################
168 class DOMAdapterInterface:
169     def hasattr(self, attr, ns=None):
170         """return true if node has attribute 
171            attr -- attribute to check for
172            ns -- namespace of attribute, by default None
173         """
174         raise NotImplementedError, 'adapter method not implemented'
175
176     def getContentList(self, *contents):
177         """returns an ordered list of child nodes
178            *contents -- list of node names to return
179         """
180         raise NotImplementedError, 'adapter method not implemented'
181
182     def setAttributeDictionary(self, attributes):
183         """set attribute dictionary
184         """
185         raise NotImplementedError, 'adapter method not implemented'
186
187     def getAttributeDictionary(self):
188         """returns a dict of node's attributes
189         """
190         raise NotImplementedError, 'adapter method not implemented'
191
192     def getNamespace(self, prefix):
193         """returns namespace referenced by prefix.
194         """
195         raise NotImplementedError, 'adapter method not implemented'
196
197     def getTagName(self):
198         """returns tagName of node
199         """
200         raise NotImplementedError, 'adapter method not implemented'
201
202
203     def getParentNode(self):
204         """returns parent element in DOMAdapter or None
205         """
206         raise NotImplementedError, 'adapter method not implemented'
207
208     def loadDocument(self, file):
209         """load a Document from a file object
210            file --
211         """
212         raise NotImplementedError, 'adapter method not implemented'
213
214     def loadFromURL(self, url):
215         """load a Document from an url
216            url -- URL to dereference
217         """
218         raise NotImplementedError, 'adapter method not implemented'
219
220
221 class DOMAdapter(DOMAdapterInterface):
222     """Adapter for ZSI.Utility.DOM
223     """
224     def __init__(self, node=None):
225         """Reset all instance variables.
226            element -- DOM document, node, or None
227         """
228         if hasattr(node, 'documentElement'):
229             self.__node = node.documentElement
230         else:
231             self.__node = node
232         self.__attributes = None
233
234     def getNode(self):
235         return self.__node
236     
237     def hasattr(self, attr, ns=None):
238         """attr -- attribute 
239            ns -- optional namespace, None means unprefixed attribute.
240         """
241         if not self.__attributes:
242             self.setAttributeDictionary()
243         if ns:
244             return self.__attributes.get(ns,{}).has_key(attr)
245         return self.__attributes.has_key(attr)
246
247     def getContentList(self, *contents):
248         nodes = []
249         ELEMENT_NODE = self.__node.ELEMENT_NODE
250         for child in DOM.getElements(self.__node, None):
251             if child.nodeType == ELEMENT_NODE and\
252                SplitQName(child.tagName)[1] in contents:
253                 nodes.append(child)
254         return map(self.__class__, nodes)
255
256     def setAttributeDictionary(self):
257         self.__attributes = {}
258         for v in self.__node._attrs.values():
259             self.__attributes[v.nodeName] = v.nodeValue
260
261     def getAttributeDictionary(self):
262         if not self.__attributes:
263             self.setAttributeDictionary()
264         return self.__attributes
265
266     def getTagName(self):
267         return self.__node.tagName
268
269     def getParentNode(self):
270         if self.__node.parentNode.nodeType == self.__node.ELEMENT_NODE:
271             return DOMAdapter(self.__node.parentNode)
272         return None
273
274     def getNamespace(self, prefix):
275         """prefix -- deference namespace prefix in node's context.
276            Ascends parent nodes until found.
277         """
278         namespace = None
279         if prefix == 'xmlns':
280             namespace = DOM.findDefaultNS(prefix, self.__node)
281         else:
282             try:
283                 namespace = DOM.findNamespaceURI(prefix, self.__node)
284             except DOMException, ex:
285                 if prefix != 'xml':
286                     raise SchemaError, '%s namespace not declared for %s'\
287                         %(prefix, self.__node._get_tagName())
288                 namespace = XMLNS.XML
289         return namespace
290            
291     def loadDocument(self, file):
292         self.__node = DOM.loadDocument(file)
293         if hasattr(self.__node, 'documentElement'):
294             self.__node = self.__node.documentElement
295
296     def loadFromURL(self, url):
297         self.__node = DOM.loadFromURL(url)
298         if hasattr(self.__node, 'documentElement'):
299             self.__node = self.__node.documentElement
300
301  
302 class XMLBase: 
303     """ These class variables are for string indentation.
304     """ 
305     tag = None
306     __indent = 0
307     __rlock = RLock()
308
309     def __str__(self):
310         XMLBase.__rlock.acquire()
311         XMLBase.__indent += 1
312         tmp = "<" + str(self.__class__) + '>\n'
313         for k,v in self.__dict__.items():
314             tmp += "%s* %s = %s\n" %(XMLBase.__indent*'  ', k, v)
315         XMLBase.__indent -= 1 
316         XMLBase.__rlock.release()
317         return tmp
318
319
320 """Marker Interface:  can determine something about an instances properties by using 
321         the provided convenience functions.
322
323 """
324 class DefinitionMarker: 
325     """marker for definitions
326     """
327     pass
328
329 class DeclarationMarker: 
330     """marker for declarations
331     """
332     pass
333
334 class AttributeMarker: 
335     """marker for attributes
336     """
337     pass
338
339 class AttributeGroupMarker: 
340     """marker for attribute groups
341     """
342     pass
343
344 class WildCardMarker: 
345     """marker for wildcards
346     """
347     pass
348
349 class ElementMarker: 
350     """marker for wildcards
351     """
352     pass
353
354 class ReferenceMarker: 
355     """marker for references
356     """
357     pass
358
359 class ModelGroupMarker: 
360     """marker for model groups
361     """
362     pass
363
364 class AllMarker(ModelGroupMarker): 
365     """marker for all model group
366     """
367     pass
368
369 class ChoiceMarker(ModelGroupMarker): 
370     """marker for choice model group
371     """
372     pass
373
374 class SequenceMarker(ModelGroupMarker): 
375     """marker for sequence model group
376     """
377     pass
378
379 class ExtensionMarker: 
380     """marker for extensions
381     """
382     pass
383
384 class RestrictionMarker: 
385     """marker for restrictions
386     """
387     facets = ['enumeration', 'length', 'maxExclusive', 'maxInclusive',\
388         'maxLength', 'minExclusive', 'minInclusive', 'minLength',\
389         'pattern', 'fractionDigits', 'totalDigits', 'whiteSpace']
390
391 class SimpleMarker: 
392     """marker for simple type information
393     """
394     pass
395
396 class ListMarker: 
397     """marker for simple type list
398     """
399     pass
400
401 class UnionMarker: 
402     """marker for simple type Union
403     """
404     pass
405
406
407 class ComplexMarker: 
408     """marker for complex type information
409     """
410     pass
411
412 class LocalMarker: 
413     """marker for complex type information
414     """
415     pass
416
417
418 class MarkerInterface:
419     def isDefinition(self):
420         return isinstance(self, DefinitionMarker)
421
422     def isDeclaration(self):
423         return isinstance(self, DeclarationMarker)
424
425     def isAttribute(self):
426         return isinstance(self, AttributeMarker)
427
428     def isAttributeGroup(self):
429         return isinstance(self, AttributeGroupMarker)
430
431     def isElement(self):
432         return isinstance(self, ElementMarker)
433
434     def isReference(self):
435         return isinstance(self, ReferenceMarker)
436
437     def isWildCard(self):
438         return isinstance(self, WildCardMarker)
439
440     def isModelGroup(self):
441         return isinstance(self, ModelGroupMarker)
442
443     def isAll(self):
444         return isinstance(self, AllMarker)
445
446     def isChoice(self):
447         return isinstance(self, ChoiceMarker)
448
449     def isSequence(self):
450         return isinstance(self, SequenceMarker)
451
452     def isExtension(self):
453         return isinstance(self, ExtensionMarker)
454
455     def isRestriction(self):
456         return isinstance(self, RestrictionMarker)
457
458     def isSimple(self):
459         return isinstance(self, SimpleMarker)
460
461     def isComplex(self):
462         return isinstance(self, ComplexMarker)
463
464     def isLocal(self):
465         return isinstance(self, LocalMarker)
466
467     def isList(self):
468         return isinstance(self, ListMarker)
469
470     def isUnion(self):
471         return isinstance(self, UnionMarker)
472
473
474 ##########################################################
475 # Schema Components
476 #########################################################
477 class XMLSchemaComponent(XMLBase, MarkerInterface):
478     """
479        class variables: 
480            required -- list of required attributes
481            attributes -- dict of default attribute values, including None.
482                Value can be a function for runtime dependencies.
483            contents -- dict of namespace keyed content lists.
484                'xsd' content of xsd namespace.
485            xmlns_key -- key for declared xmlns namespace.
486            xmlns -- xmlns is special prefix for namespace dictionary
487            xml -- special xml prefix for xml namespace.
488     """
489     required = []
490     attributes = {}
491     contents = {}
492     xmlns_key = ''
493     xmlns = 'xmlns'
494     xml = 'xml'
495
496     def __init__(self, parent=None):
497         """parent -- parent instance
498            instance variables:
499                attributes -- dictionary of node's attributes
500         """
501         self.attributes = None
502         self._parent = parent
503         if self._parent:
504             self._parent = weakref.ref(parent)
505
506         if not self.__class__ == XMLSchemaComponent\
507            and not (type(self.__class__.required) == type(XMLSchemaComponent.required)\
508            and type(self.__class__.attributes) == type(XMLSchemaComponent.attributes)\
509            and type(self.__class__.contents) == type(XMLSchemaComponent.contents)):
510             raise RuntimeError, 'Bad type for a class variable in %s' %self.__class__
511
512     def getItemTrace(self):
513         """Returns a node trace up to the <schema> item.
514         """
515         item, path, name, ref = self, [], 'name', 'ref'
516         while not isinstance(item,XMLSchema) and not isinstance(item,WSDLToolsAdapter):
517             attr = item.getAttribute(name)
518             if not attr:
519                 attr = item.getAttribute(ref)
520                 if not attr:
521                     path.append('<%s>' %(item.tag))
522                 else: 
523                     path.append('<%s ref="%s">' %(item.tag, attr))
524             else:
525                 path.append('<%s name="%s">' %(item.tag,attr))
526
527             item = item._parent()
528         try:
529             tns = item.getTargetNamespace()
530         except: 
531             tns = ''
532         path.append('<%s targetNamespace="%s">' %(item.tag, tns))
533         path.reverse()
534         return ''.join(path)
535
536     def getTargetNamespace(self):
537         """return targetNamespace
538         """
539         parent = self
540         targetNamespace = 'targetNamespace'
541         tns = self.attributes.get(targetNamespace)
542         while not tns and parent and parent._parent is not None:
543             parent = parent._parent()
544             tns = parent.attributes.get(targetNamespace)
545         return tns or ''
546
547     def getAttributeDeclaration(self, attribute):
548         """attribute -- attribute with a QName value (eg. type).
549            collection -- check types collection in parent Schema instance
550         """
551         return self.getQNameAttribute(ATTRIBUTES, attribute)
552
553     def getAttributeGroup(self, attribute):
554         """attribute -- attribute with a QName value (eg. type).
555            collection -- check types collection in parent Schema instance
556         """
557         return self.getQNameAttribute(ATTRIBUTE_GROUPS, attribute)
558
559     def getTypeDefinition(self, attribute):
560         """attribute -- attribute with a QName value (eg. type).
561            collection -- check types collection in parent Schema instance
562         """
563         return self.getQNameAttribute(TYPES, attribute)
564
565     def getElementDeclaration(self, attribute):
566         """attribute -- attribute with a QName value (eg. element).
567            collection -- check elements collection in parent Schema instance.
568         """
569         return self.getQNameAttribute(ELEMENTS, attribute)
570
571     def getModelGroup(self, attribute):
572         """attribute -- attribute with a QName value (eg. ref).
573            collection -- check model_group collection in parent Schema instance.
574         """
575         return self.getQNameAttribute(MODEL_GROUPS, attribute)
576
577     def getQNameAttribute(self, collection, attribute):
578         """returns object instance representing QName --> (namespace,name),
579            or if does not exist return None.
580            attribute -- an information item attribute, with a QName value.
581            collection -- collection in parent Schema instance to search.
582         """
583         tdc = self.getAttributeQName(attribute)
584         if not tdc:
585             return
586
587         obj = self.getSchemaItem(collection, tdc.getTargetNamespace(), tdc.getName())
588         if obj: 
589             return obj
590
591 #        raise SchemaError, 'No schema item "%s" in collection %s' %(tdc, collection)
592         return
593
594     def getSchemaItem(self, collection, namespace, name):
595         """returns object instance representing namespace, name,
596            or if does not exist return None if built-in, else
597            raise SchemaError.
598            
599            namespace -- namespace item defined in.
600            name -- name of item.
601            collection -- collection in parent Schema instance to search.
602         """
603         parent = GetSchema(self)
604         if parent.targetNamespace == namespace:
605             try:
606                 obj = getattr(parent, collection)[name]
607             except KeyError, ex:
608                 raise KeyError, 'targetNamespace(%s) collection(%s) has no item(%s)'\
609                     %(namespace, collection, name)
610                     
611             return obj
612         
613         if not parent.imports.has_key(namespace):
614             if namespace in BUILT_IN_NAMESPACES:            
615                 # built-in just return
616                 # WARNING: expecting import if "redefine" or add to built-in namespace.
617                 return
618             
619             raise SchemaError, 'schema "%s" does not import namespace "%s"' %(
620                 parent.targetNamespace, namespace)
621             
622         # Lazy Eval
623         schema = parent.imports[namespace]
624         if not isinstance(schema, XMLSchema):
625             schema = schema.getSchema()    
626             if schema is not None:
627                 parent.imports[namespace] = schema
628             
629         if schema is None:
630             if namespace in BUILT_IN_NAMESPACES:
631                 # built-in just return
632                 return
633             
634             raise SchemaError, 'no schema instance for imported namespace (%s).'\
635                 %(namespace)
636                 
637         if not isinstance(schema, XMLSchema):
638             raise TypeError, 'expecting XMLSchema instance not "%r"' %schema
639                 
640         try:
641             obj = getattr(schema, collection)[name]
642         except KeyError, ex:
643             raise KeyError, 'targetNamespace(%s) collection(%s) has no item(%s)'\
644                 %(namespace, collection, name)
645                     
646         return obj
647
648     def getXMLNS(self, prefix=None):
649         """deference prefix or by default xmlns, returns namespace. 
650         """
651         if prefix == XMLSchemaComponent.xml:
652             return XMLNS.XML
653         parent = self
654         ns = self.attributes[XMLSchemaComponent.xmlns].get(prefix or\
655                 XMLSchemaComponent.xmlns_key)
656         while not ns:
657             parent = parent._parent()
658             ns = parent.attributes[XMLSchemaComponent.xmlns].get(prefix or\
659                     XMLSchemaComponent.xmlns_key)
660             if not ns and isinstance(parent, WSDLToolsAdapter):
661                 if prefix is None:
662                     return ''
663                 raise SchemaError, 'unknown prefix %s' %prefix
664         return ns
665
666     def getAttribute(self, attribute):
667         """return requested attribute value or None
668         """
669         if type(attribute) in (list, tuple):
670             if len(attribute) != 2:
671                 raise LookupError, 'To access attributes must use name or (namespace,name)'
672
673             ns_dict = self.attributes.get(attribute[0])
674             if ns_dict is None:
675                 return None
676
677             return ns_dict.get(attribute[1])
678
679         return self.attributes.get(attribute)
680
681     def getAttributeQName(self, attribute):
682         """return requested attribute value as (namespace,name) or None 
683         """
684         qname = self.getAttribute(attribute)
685         if isinstance(qname, TypeDescriptionComponent) is True:
686             return qname
687         if qname is None:
688             return None
689
690         prefix,ncname = SplitQName(qname)
691         namespace = self.getXMLNS(prefix)
692         return TypeDescriptionComponent((namespace,ncname))
693
694     def getAttributeName(self):
695         """return attribute name or None
696         """
697         return self.getAttribute('name')
698  
699     def setAttributes(self, node):
700         """Sets up attribute dictionary, checks for required attributes and 
701            sets default attribute values. attr is for default attribute values 
702            determined at runtime.
703            
704            structure of attributes dictionary
705                ['xmlns'][xmlns_key] --  xmlns namespace
706                ['xmlns'][prefix] --  declared namespace prefix 
707                [namespace][prefix] -- attributes declared in a namespace
708                [attribute] -- attributes w/o prefix, default namespaces do
709                    not directly apply to attributes, ie Name can't collide 
710                    with QName.
711         """
712         self.attributes = {XMLSchemaComponent.xmlns:{}}
713         for k,v in node.getAttributeDictionary().items():
714             prefix,value = SplitQName(k)
715             if value == XMLSchemaComponent.xmlns:
716                 self.attributes[value][prefix or XMLSchemaComponent.xmlns_key] = v
717             elif prefix:
718                 ns = node.getNamespace(prefix)
719                 if not ns: 
720                     raise SchemaError, 'no namespace for attribute prefix %s'\
721                         %prefix
722                 if not self.attributes.has_key(ns):
723                     self.attributes[ns] = {}
724                 elif self.attributes[ns].has_key(value):
725                     raise SchemaError, 'attribute %s declared multiple times in %s'\
726                         %(value, ns)
727                 self.attributes[ns][value] = v
728             elif not self.attributes.has_key(value):
729                 self.attributes[value] = v
730             else:
731                 raise SchemaError, 'attribute %s declared multiple times' %value
732
733         if not isinstance(self, WSDLToolsAdapter):
734             self.__checkAttributes()
735         self.__setAttributeDefaults()
736
737         #set QNames
738         for k in ['type', 'element', 'base', 'ref', 'substitutionGroup', 'itemType']:
739             if self.attributes.has_key(k):
740                 prefix, value = SplitQName(self.attributes.get(k))
741                 self.attributes[k] = \
742                     TypeDescriptionComponent((self.getXMLNS(prefix), value))
743
744         #Union, memberTypes is a whitespace separated list of QNames 
745         for k in ['memberTypes']:
746             if self.attributes.has_key(k):
747                 qnames = self.attributes[k]
748                 self.attributes[k] = []
749                 for qname in qnames.split():
750                     prefix, value = SplitQName(qname)
751                     self.attributes['memberTypes'].append(\
752                         TypeDescriptionComponent(\
753                             (self.getXMLNS(prefix), value)))
754
755     def getContents(self, node):
756         """retrieve xsd contents
757         """
758         return node.getContentList(*self.__class__.contents['xsd'])
759
760     def __setAttributeDefaults(self):
761         """Looks for default values for unset attributes.  If
762            class variable representing attribute is None, then
763            it must be defined as an instance variable.
764         """
765         for k,v in self.__class__.attributes.items():
766             if v is not None and self.attributes.has_key(k) is False:
767                 if isinstance(v, types.FunctionType):
768                     self.attributes[k] = v(self)
769                 else:
770                     self.attributes[k] = v
771
772     def __checkAttributes(self):
773         """Checks that required attributes have been defined,
774            attributes w/default cannot be required.   Checks
775            all defined attributes are legal, attribute 
776            references are not subject to this test.
777         """
778         for a in self.__class__.required:
779             if not self.attributes.has_key(a):
780                 raise SchemaError,\
781                     'class instance %s, missing required attribute %s'\
782                     %(self.__class__, a)
783         for a,v in self.attributes.items():
784             # attribute #other, ie. not in empty namespace
785             if type(v) is dict:
786                 continue
787             
788             # predefined prefixes xmlns, xml
789             if a in (XMLSchemaComponent.xmlns, XMLNS.XML):
790                 continue
791             
792             if (a not in self.__class__.attributes.keys()) and not\
793                 (self.isAttribute() and self.isReference()):
794                 raise SchemaError, '%s, unknown attribute(%s,%s)' \
795                     %(self.getItemTrace(), a, self.attributes[a])
796
797
798 class WSDLToolsAdapter(XMLSchemaComponent):
799     """WSDL Adapter to grab the attributes from the wsdl document node.
800     """
801     attributes = {'name':None, 'targetNamespace':None}
802     tag = 'definitions'
803
804     def __init__(self, wsdl):
805         XMLSchemaComponent.__init__(self, parent=wsdl)
806         self.setAttributes(DOMAdapter(wsdl.document))
807
808     def getImportSchemas(self):
809         """returns WSDLTools.WSDL types Collection
810         """
811         return self._parent().types
812
813
814 class Notation(XMLSchemaComponent):
815     """<notation>
816        parent:
817            schema
818        attributes:
819            id -- ID
820            name -- NCName, Required
821            public -- token, Required
822            system -- anyURI
823        contents:
824            annotation?
825     """
826     required = ['name', 'public']
827     attributes = {'id':None, 'name':None, 'public':None, 'system':None}
828     contents = {'xsd':('annotation')}
829     tag = 'notation'
830
831     def __init__(self, parent):
832         XMLSchemaComponent.__init__(self, parent)
833         self.annotation = None
834
835     def fromDom(self, node):
836         self.setAttributes(node)
837         contents = self.getContents(node)
838
839         for i in contents:
840             component = SplitQName(i.getTagName())[1]
841             if component == 'annotation' and not self.annotation:
842                 self.annotation = Annotation(self)
843                 self.annotation.fromDom(i)
844             else:
845                 raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
846
847
848 class Annotation(XMLSchemaComponent):
849     """<annotation>
850        parent:
851            all,any,anyAttribute,attribute,attributeGroup,choice,complexContent,
852            complexType,element,extension,field,group,import,include,key,keyref,
853            list,notation,redefine,restriction,schema,selector,simpleContent,
854            simpleType,union,unique
855        attributes:
856            id -- ID
857        contents:
858            (documentation | appinfo)*
859     """
860     attributes = {'id':None}
861     contents = {'xsd':('documentation', 'appinfo')}
862     tag = 'annotation'
863
864     def __init__(self, parent):
865         XMLSchemaComponent.__init__(self, parent)
866         self.content = None
867
868     def fromDom(self, node):
869         self.setAttributes(node)
870         contents = self.getContents(node)
871         content = []
872
873         for i in contents:
874             component = SplitQName(i.getTagName())[1]
875             if component == 'documentation':
876                 #print_debug('class %s, documentation skipped' %self.__class__, 5)
877                 continue
878             elif component == 'appinfo':
879                 #print_debug('class %s, appinfo skipped' %self.__class__, 5)
880                 continue
881             else:
882                 raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
883         self.content = tuple(content)
884
885
886     class Documentation(XMLSchemaComponent):
887         """<documentation>
888            parent:
889                annotation
890            attributes:
891                source, anyURI
892                xml:lang, language
893            contents:
894                mixed, any
895         """
896         attributes = {'source':None, 'xml:lang':None}
897         contents = {'xsd':('mixed', 'any')}
898         tag = 'documentation'
899
900         def __init__(self, parent):
901             XMLSchemaComponent.__init__(self, parent)
902             self.content = None
903
904         def fromDom(self, node):
905             self.setAttributes(node)
906             contents = self.getContents(node)
907             content = []
908
909             for i in contents:
910                 component = SplitQName(i.getTagName())[1]
911                 if component == 'mixed':
912                     #print_debug('class %s, mixed skipped' %self.__class__, 5)
913                     continue
914                 elif component == 'any':
915                     #print_debug('class %s, any skipped' %self.__class__, 5)
916                     continue
917                 else:
918                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
919             self.content = tuple(content)
920
921
922     class Appinfo(XMLSchemaComponent):
923         """<appinfo>
924            parent:
925                annotation
926            attributes:
927                source, anyURI
928            contents:
929                mixed, any
930         """
931         attributes = {'source':None, 'anyURI':None}
932         contents = {'xsd':('mixed', 'any')}
933         tag = 'appinfo'
934
935         def __init__(self, parent):
936             XMLSchemaComponent.__init__(self, parent)
937             self.content = None
938
939         def fromDom(self, node):
940             self.setAttributes(node)
941             contents = self.getContents(node)
942             content = []
943
944             for i in contents:
945                 component = SplitQName(i.getTagName())[1]
946                 if component == 'mixed':
947                     #print_debug('class %s, mixed skipped' %self.__class__, 5)
948                     continue
949                 elif component == 'any':
950                     #print_debug('class %s, any skipped' %self.__class__, 5)
951                     continue
952                 else:
953                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
954             self.content = tuple(content)
955
956
957 class XMLSchemaFake:
958     # This is temporary, for the benefit of WSDL until the real thing works.
959     def __init__(self, element):
960         self.targetNamespace = DOM.getAttr(element, 'targetNamespace')
961         self.element = element
962
963 class XMLSchema(XMLSchemaComponent):
964     """A schema is a collection of schema components derived from one
965        or more schema documents, that is, one or more <schema> element
966        information items. It represents the abstract notion of a schema
967        rather than a single schema document (or other representation).
968
969        <schema>
970        parent:
971            ROOT
972        attributes:
973            id -- ID
974            version -- token
975            xml:lang -- language
976            targetNamespace -- anyURI
977            attributeFormDefault -- 'qualified' | 'unqualified', 'unqualified'
978            elementFormDefault -- 'qualified' | 'unqualified', 'unqualified'
979            blockDefault -- '#all' | list of 
980                ('substitution | 'extension' | 'restriction')
981            finalDefault -- '#all' | list of 
982                ('extension' | 'restriction' | 'list' | 'union')
983         
984        contents:
985            ((include | import | redefine | annotation)*, 
986             (attribute, attributeGroup, complexType, element, group, 
987              notation, simpleType)*, annotation*)*
988
989
990         attributes -- schema attributes
991         imports -- import statements
992         includes -- include statements
993         redefines -- 
994         types    -- global simpleType, complexType definitions
995         elements -- global element declarations
996         attr_decl -- global attribute declarations
997         attr_groups -- attribute Groups
998         model_groups -- model Groups
999         notations -- global notations
1000     """
1001     attributes = {'id':None, 
1002         'version':None, 
1003         'xml:lang':None, 
1004         'targetNamespace':None,
1005         'attributeFormDefault':'unqualified',
1006         'elementFormDefault':'unqualified',
1007         'blockDefault':None,
1008         'finalDefault':None}
1009     contents = {'xsd':('include', 'import', 'redefine', 'annotation',
1010                        'attribute', 'attributeGroup', 'complexType',
1011                        'element', 'group', 'notation', 'simpleType',
1012                        'annotation')}
1013     empty_namespace = ''
1014     tag = 'schema'
1015
1016     def __init__(self, parent=None): 
1017         """parent -- 
1018            instance variables:
1019            targetNamespace -- schema's declared targetNamespace, or empty string.
1020            _imported_schemas -- namespace keyed dict of schema dependencies, if 
1021               a schema is provided instance will not resolve import statement.
1022            _included_schemas -- schemaLocation keyed dict of component schemas, 
1023               if schema is provided instance will not resolve include statement.
1024            _base_url -- needed for relative URLs support, only works with URLs
1025                relative to initial document.
1026            includes -- collection of include statements
1027            imports -- collection of import statements
1028            elements -- collection of global element declarations
1029            types -- collection of global type definitions
1030            attr_decl -- collection of global attribute declarations
1031            attr_groups -- collection of global attribute group definitions
1032            model_groups -- collection of model group definitions
1033            notations -- collection of notations
1034
1035         """
1036         self.__node = None
1037         self.targetNamespace = None
1038         XMLSchemaComponent.__init__(self, parent)
1039         f = lambda k: k.attributes['name']
1040         ns = lambda k: k.attributes['namespace']
1041         sl = lambda k: k.attributes['schemaLocation']
1042         self.includes = Collection(self, key=sl)
1043         self.imports = Collection(self, key=ns)
1044         self.elements = Collection(self, key=f)
1045         self.types = Collection(self, key=f)
1046         self.attr_decl = Collection(self, key=f)
1047         self.attr_groups = Collection(self, key=f)
1048         self.model_groups = Collection(self, key=f)
1049         self.notations = Collection(self, key=f)
1050
1051         self._imported_schemas = {}
1052         self._included_schemas = {}
1053         self._base_url = None
1054
1055     def getNode(self):
1056         """
1057         Interacting with the underlying DOM tree.
1058         """
1059         return self.__node
1060     
1061     def addImportSchema(self, schema):
1062         """for resolving import statements in Schema instance
1063            schema -- schema instance
1064            _imported_schemas 
1065         """
1066         if not isinstance(schema, XMLSchema):
1067             raise TypeError, 'expecting a Schema instance'
1068         if schema.targetNamespace != self.targetNamespace:
1069             self._imported_schemas[schema.targetNamespace] = schema
1070         else:
1071             raise SchemaError, 'import schema bad targetNamespace'
1072
1073     def addIncludeSchema(self, schemaLocation, schema):
1074         """for resolving include statements in Schema instance
1075            schemaLocation -- schema location
1076            schema -- schema instance
1077            _included_schemas 
1078         """
1079         if not isinstance(schema, XMLSchema):
1080             raise TypeError, 'expecting a Schema instance'
1081         if not schema.targetNamespace or\
1082              schema.targetNamespace == self.targetNamespace:
1083             self._included_schemas[schemaLocation] = schema
1084         else:
1085             raise SchemaError, 'include schema bad targetNamespace'
1086         
1087     def setImportSchemas(self, schema_dict):
1088         """set the import schema dictionary, which is used to 
1089            reference depedent schemas.
1090         """
1091         self._imported_schemas = schema_dict
1092
1093     def getImportSchemas(self):
1094         """get the import schema dictionary, which is used to 
1095            reference depedent schemas.
1096         """
1097         return self._imported_schemas
1098
1099     def getSchemaNamespacesToImport(self):
1100         """returns tuple of namespaces the schema instance has declared
1101            itself to be depedent upon.
1102         """
1103         return tuple(self.includes.keys())
1104
1105     def setIncludeSchemas(self, schema_dict):
1106         """set the include schema dictionary, which is keyed with 
1107            schemaLocation (uri).  
1108            This is a means of providing 
1109            schemas to the current schema for content inclusion.
1110         """
1111         self._included_schemas = schema_dict
1112
1113     def getIncludeSchemas(self):
1114         """get the include schema dictionary, which is keyed with 
1115            schemaLocation (uri). 
1116         """
1117         return self._included_schemas
1118
1119     def getBaseUrl(self):
1120         """get base url, used for normalizing all relative uri's 
1121         """
1122         return self._base_url
1123
1124     def setBaseUrl(self, url):
1125         """set base url, used for normalizing all relative uri's 
1126         """
1127         self._base_url = url
1128
1129     def getElementFormDefault(self):
1130         """return elementFormDefault attribute
1131         """
1132         return self.attributes.get('elementFormDefault')
1133
1134     def isElementFormDefaultQualified(self):
1135         return self.attributes.get('elementFormDefault') == 'qualified'
1136
1137     def getAttributeFormDefault(self):
1138         """return attributeFormDefault attribute
1139         """
1140         return self.attributes.get('attributeFormDefault')
1141
1142     def getBlockDefault(self):
1143         """return blockDefault attribute
1144         """
1145         return self.attributes.get('blockDefault')
1146
1147     def getFinalDefault(self):
1148         """return finalDefault attribute 
1149         """
1150         return self.attributes.get('finalDefault')
1151
1152     def load(self, node, location=None):
1153         self.__node = node
1154
1155         pnode = node.getParentNode()
1156         if pnode:
1157             pname = SplitQName(pnode.getTagName())[1]
1158             if pname == 'types':
1159                 attributes = {}
1160                 self.setAttributes(pnode)
1161                 attributes.update(self.attributes)
1162                 self.setAttributes(node)
1163                 for k,v in attributes['xmlns'].items():
1164                     if not self.attributes['xmlns'].has_key(k):
1165                         self.attributes['xmlns'][k] = v
1166             else:
1167                 self.setAttributes(node)
1168         else:
1169             self.setAttributes(node)
1170
1171         self.targetNamespace = self.getTargetNamespace()
1172         for childNode in self.getContents(node):
1173             component = SplitQName(childNode.getTagName())[1]
1174                 
1175             if component == 'include':
1176                 tp = self.__class__.Include(self)
1177                 tp.fromDom(childNode)
1178
1179                 sl = tp.attributes['schemaLocation']
1180                 schema = tp.getSchema()
1181
1182                 if not self.getIncludeSchemas().has_key(sl):
1183                     self.addIncludeSchema(sl, schema)
1184
1185                 self.includes[sl] = tp
1186
1187                 pn = childNode.getParentNode().getNode()
1188                 pn.removeChild(childNode.getNode())
1189                 for child in schema.getNode().getNode().childNodes:
1190                     pn.appendChild(child.cloneNode(1))
1191
1192                 for collection in ['imports','elements','types',
1193                                    'attr_decl','attr_groups','model_groups',
1194                                    'notations']:
1195                     for k,v in getattr(schema,collection).items():
1196                         if not getattr(self,collection).has_key(k):
1197                             v._parent = weakref.ref(self)
1198                             getattr(self,collection)[k] = v
1199                         else:
1200                             warnings.warn("Not keeping schema component.")
1201       
1202             elif component == 'import':
1203                 slocd = SchemaReader.namespaceToSchema
1204                 tp = self.__class__.Import(self)
1205                 tp.fromDom(childNode)
1206                 import_ns = tp.getAttribute('namespace') or\
1207                     self.__class__.empty_namespace
1208                 schema = slocd.get(import_ns)
1209                 if schema is None:
1210                     schema = XMLSchema()
1211                     slocd[import_ns] = schema
1212                     try:
1213                         tp.loadSchema(schema)
1214                     except NoSchemaLocationWarning, ex:
1215                         # Dependency declaration, hopefully implementation
1216                         # is aware of this namespace (eg. SOAP,WSDL,?)
1217                         print "IMPORT: ", import_ns
1218                         print ex
1219                         del slocd[import_ns]
1220                         continue
1221                     except SchemaError, ex:
1222                         #warnings.warn(\
1223                         #    '<import namespace="%s" schemaLocation=?>, %s'\
1224                         #    %(import_ns, 'failed to load schema instance')
1225                         #)
1226                         print ex
1227                         del slocd[import_ns]
1228                         class _LazyEvalImport(str):
1229                             '''Lazy evaluation of import, replace entry in self.imports.'''
1230                             #attributes = dict(namespace=import_ns)
1231                             def getSchema(namespace):
1232                                 schema = slocd.get(namespace)
1233                                 if schema is None:
1234                                     parent = self._parent()
1235                                     wstypes = parent
1236                                     if isinstance(parent, WSDLToolsAdapter):
1237                                         wstypes = parent.getImportSchemas()
1238                                     schema = wstypes.get(namespace)
1239                                 if isinstance(schema, XMLSchema):
1240                                     self.imports[namespace] = schema
1241                                     return schema
1242
1243                                 return None
1244
1245                         self.imports[import_ns] = _LazyEvalImport(import_ns)
1246                         continue
1247                 else:           
1248                     tp._schema = schema
1249             
1250                 if self.getImportSchemas().has_key(import_ns):
1251                     warnings.warn(\
1252                         'Detected multiple imports of the namespace "%s" '\
1253                         %import_ns)
1254             
1255                 self.addImportSchema(schema)
1256                 # spec says can have multiple imports of same namespace
1257                 # but purpose of import is just dependency declaration.
1258                 self.imports[import_ns] = tp
1259                 
1260             elif component == 'redefine':
1261                 warnings.warn('redefine is ignored')
1262             elif component == 'annotation':
1263                 warnings.warn('annotation is ignored')
1264             elif component == 'attribute':
1265                 tp = AttributeDeclaration(self)
1266                 tp.fromDom(childNode)
1267                 self.attr_decl[tp.getAttribute('name')] = tp
1268             elif component == 'attributeGroup':
1269                 tp = AttributeGroupDefinition(self)
1270                 tp.fromDom(childNode)
1271                 self.attr_groups[tp.getAttribute('name')] = tp
1272             elif component == 'element':
1273                 tp = ElementDeclaration(self)
1274                 tp.fromDom(childNode)
1275                 self.elements[tp.getAttribute('name')] = tp
1276             elif component == 'group':
1277                 tp = ModelGroupDefinition(self)
1278                 tp.fromDom(childNode)
1279                 self.model_groups[tp.getAttribute('name')] = tp
1280             elif component == 'notation':
1281                 tp = Notation(self)
1282                 tp.fromDom(childNode)
1283                 self.notations[tp.getAttribute('name')] = tp
1284             elif component == 'complexType':
1285                 tp = ComplexType(self)
1286                 tp.fromDom(childNode)
1287                 self.types[tp.getAttribute('name')] = tp
1288             elif component == 'simpleType':
1289                 tp = SimpleType(self)
1290                 tp.fromDom(childNode)
1291                 self.types[tp.getAttribute('name')] = tp
1292             else:
1293                 break
1294
1295     class Import(XMLSchemaComponent):
1296         """<import> 
1297            parent:
1298                schema
1299            attributes:
1300                id -- ID
1301                namespace -- anyURI
1302                schemaLocation -- anyURI
1303            contents:
1304                annotation?
1305         """
1306         attributes = {'id':None,
1307                       'namespace':None,
1308                       'schemaLocation':None}
1309         contents = {'xsd':['annotation']}
1310         tag = 'import'
1311
1312         def __init__(self, parent):
1313             XMLSchemaComponent.__init__(self, parent)
1314             self.annotation = None
1315             self._schema = None
1316
1317         def fromDom(self, node):
1318             self.setAttributes(node)
1319             contents = self.getContents(node)
1320
1321             if self.attributes['namespace'] == self.getTargetNamespace():
1322                 raise SchemaError, 'namespace of schema and import match'
1323
1324             for i in contents:
1325                 component = SplitQName(i.getTagName())[1]
1326                 if component == 'annotation' and not self.annotation:
1327                     self.annotation = Annotation(self)
1328                     self.annotation.fromDom(i)
1329                 else:
1330                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
1331
1332         def getSchema(self):
1333             """if schema is not defined, first look for a Schema class instance
1334                in parent Schema.  Else if not defined resolve schemaLocation
1335                and create a new Schema class instance, and keep a hard reference. 
1336             """
1337             if not self._schema:
1338                 ns = self.attributes['namespace']
1339                 schema = self._parent().getImportSchemas().get(ns)
1340                 if not schema and self._parent()._parent:
1341                     schema = self._parent()._parent().getImportSchemas().get(ns)
1342
1343                 if not schema:
1344                     url = self.attributes.get('schemaLocation')
1345                     if not url:
1346                         raise SchemaError, 'namespace(%s) is unknown' %ns
1347                     base_url = self._parent().getBaseUrl()
1348                     reader = SchemaReader(base_url=base_url)
1349                     reader._imports = self._parent().getImportSchemas()
1350                     reader._includes = self._parent().getIncludeSchemas()
1351                     self._schema = reader.loadFromURL(url)
1352             return self._schema or schema
1353             
1354         def loadSchema(self, schema):
1355             """
1356             """
1357             base_url = self._parent().getBaseUrl()
1358             reader = SchemaReader(base_url=base_url)
1359             reader._imports = self._parent().getImportSchemas()
1360             reader._includes = self._parent().getIncludeSchemas()
1361             self._schema = schema
1362
1363             if not self.attributes.has_key('schemaLocation'):
1364                 raise NoSchemaLocationWarning('no schemaLocation attribute in import')
1365
1366             reader.loadFromURL(self.attributes.get('schemaLocation'), schema)
1367
1368
1369     class Include(XMLSchemaComponent):
1370         """<include schemaLocation>
1371            parent:
1372                schema
1373            attributes:
1374                id -- ID
1375                schemaLocation -- anyURI, required
1376            contents:
1377                annotation?
1378         """
1379         required = ['schemaLocation']
1380         attributes = {'id':None,
1381             'schemaLocation':None}
1382         contents = {'xsd':['annotation']}
1383         tag = 'include'
1384
1385         def __init__(self, parent):
1386             XMLSchemaComponent.__init__(self, parent)
1387             self.annotation = None
1388             self._schema = None
1389
1390         def fromDom(self, node):
1391             self.setAttributes(node)
1392             contents = self.getContents(node)
1393
1394             for i in contents:
1395                 component = SplitQName(i.getTagName())[1]
1396                 if component == 'annotation' and not self.annotation:
1397                     self.annotation = Annotation(self)
1398                     self.annotation.fromDom(i)
1399                 else:
1400                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
1401
1402         def getSchema(self):
1403             """if schema is not defined, first look for a Schema class instance
1404                in parent Schema.  Else if not defined resolve schemaLocation
1405                and create a new Schema class instance.  
1406             """
1407             if not self._schema:
1408                 schema = self._parent()
1409                 self._schema = schema.getIncludeSchemas().get(\
1410                                    self.attributes['schemaLocation']
1411                                    )
1412                 if not self._schema:
1413                     url = self.attributes['schemaLocation']
1414                     reader = SchemaReader(base_url=schema.getBaseUrl())
1415                     reader._imports = schema.getImportSchemas()
1416                     reader._includes = schema.getIncludeSchemas()
1417                     
1418                     # create schema before loading so chameleon include 
1419                     # will evalute targetNamespace correctly.
1420                     self._schema = XMLSchema(schema)
1421                     reader.loadFromURL(url, self._schema)
1422
1423             return self._schema
1424
1425
1426 class AttributeDeclaration(XMLSchemaComponent,\
1427                            AttributeMarker,\
1428                            DeclarationMarker):
1429     """<attribute name>
1430        parent: 
1431            schema
1432        attributes:
1433            id -- ID
1434            name -- NCName, required
1435            type -- QName
1436            default -- string
1437            fixed -- string
1438        contents:
1439            annotation?, simpleType?
1440     """
1441     required = ['name']
1442     attributes = {'id':None,
1443         'name':None,
1444         'type':None,
1445         'default':None,
1446         'fixed':None}
1447     contents = {'xsd':['annotation','simpleType']}
1448     tag = 'attribute'
1449
1450     def __init__(self, parent):
1451         XMLSchemaComponent.__init__(self, parent)
1452         self.annotation = None
1453         self.content = None
1454
1455     def fromDom(self, node):
1456         """ No list or union support
1457         """
1458         self.setAttributes(node)
1459         contents = self.getContents(node)
1460
1461         for i in contents:
1462             component = SplitQName(i.getTagName())[1]
1463             if component == 'annotation' and not self.annotation:
1464                 self.annotation = Annotation(self)
1465                 self.annotation.fromDom(i)
1466             elif component == 'simpleType':
1467                 self.content = AnonymousSimpleType(self)
1468                 self.content.fromDom(i)
1469             else:
1470                 raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
1471
1472
1473 class LocalAttributeDeclaration(AttributeDeclaration,\
1474                                 AttributeMarker,\
1475                                 LocalMarker,\
1476                                 DeclarationMarker):
1477     """<attribute name>
1478        parent: 
1479            complexType, restriction, extension, attributeGroup
1480        attributes:
1481            id -- ID
1482            name -- NCName,  required
1483            type -- QName
1484            form -- ('qualified' | 'unqualified'), schema.attributeFormDefault
1485            use -- ('optional' | 'prohibited' | 'required'), optional
1486            default -- string
1487            fixed -- string
1488        contents:
1489            annotation?, simpleType?
1490     """
1491     required = ['name']
1492     attributes = {'id':None, 
1493         'name':None,
1494         'type':None,
1495         'form':lambda self: GetSchema(self).getAttributeFormDefault(),
1496         'use':'optional',
1497         'default':None,
1498         'fixed':None}
1499     contents = {'xsd':['annotation','simpleType']}
1500
1501     def __init__(self, parent):
1502         AttributeDeclaration.__init__(self, parent)
1503         self.annotation = None
1504         self.content = None
1505
1506     def fromDom(self, node):
1507         self.setAttributes(node)
1508         contents = self.getContents(node)
1509
1510         for i in contents:
1511             component = SplitQName(i.getTagName())[1]
1512             if component == 'annotation' and not self.annotation:
1513                 self.annotation = Annotation(self)
1514                 self.annotation.fromDom(i)
1515             elif component == 'simpleType':
1516                 self.content = AnonymousSimpleType(self)
1517                 self.content.fromDom(i)
1518             else:
1519                 raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
1520
1521
1522 class AttributeWildCard(XMLSchemaComponent,\
1523                         AttributeMarker,\
1524                         DeclarationMarker,\
1525                         WildCardMarker):
1526     """<anyAttribute>
1527        parents: 
1528            complexType, restriction, extension, attributeGroup
1529        attributes:
1530            id -- ID
1531            namespace -- '##any' | '##other' | 
1532                         (anyURI* | '##targetNamespace' | '##local'), ##any
1533            processContents -- 'lax' | 'skip' | 'strict', strict
1534        contents:
1535            annotation?
1536     """
1537     attributes = {'id':None, 
1538         'namespace':'##any',
1539         'processContents':'strict'}
1540     contents = {'xsd':['annotation']}
1541     tag = 'anyAttribute'
1542
1543     def __init__(self, parent):
1544         XMLSchemaComponent.__init__(self, parent)
1545         self.annotation = None
1546
1547     def fromDom(self, node):
1548         self.setAttributes(node)
1549         contents = self.getContents(node)
1550
1551         for i in contents:
1552             component = SplitQName(i.getTagName())[1]
1553             if component == 'annotation' and not self.annotation:
1554                 self.annotation = Annotation(self)
1555                 self.annotation.fromDom(i)
1556             else:
1557                 raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
1558
1559
1560 class AttributeReference(XMLSchemaComponent,\
1561                          AttributeMarker,\
1562                          ReferenceMarker):
1563     """<attribute ref>
1564        parents: 
1565            complexType, restriction, extension, attributeGroup
1566        attributes:
1567            id -- ID
1568            ref -- QName, required
1569            use -- ('optional' | 'prohibited' | 'required'), optional
1570            default -- string
1571            fixed -- string
1572        contents:
1573            annotation?
1574     """
1575     required = ['ref']
1576     attributes = {'id':None, 
1577         'ref':None,
1578         'use':'optional',
1579         'default':None,
1580         'fixed':None}
1581     contents = {'xsd':['annotation']}
1582     tag = 'attribute'
1583
1584     def __init__(self, parent):
1585         XMLSchemaComponent.__init__(self, parent)
1586         self.annotation = None
1587
1588     def getAttributeDeclaration(self, attribute='ref'):
1589         return XMLSchemaComponent.getAttributeDeclaration(self, attribute)
1590
1591     def fromDom(self, node):
1592         self.setAttributes(node)
1593         contents = self.getContents(node)
1594
1595         for i in contents:
1596             component = SplitQName(i.getTagName())[1]
1597             if component == 'annotation' and not self.annotation:
1598                 self.annotation = Annotation(self)
1599                 self.annotation.fromDom(i)
1600             else:
1601                 raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
1602
1603
1604 class AttributeGroupDefinition(XMLSchemaComponent,\
1605                                AttributeGroupMarker,\
1606                                DefinitionMarker):
1607     """<attributeGroup name>
1608        parents: 
1609            schema, redefine
1610        attributes:
1611            id -- ID
1612            name -- NCName,  required
1613        contents:
1614            annotation?, (attribute | attributeGroup)*, anyAttribute?
1615     """
1616     required = ['name']
1617     attributes = {'id':None, 
1618         'name':None}
1619     contents = {'xsd':['annotation', 'attribute', 'attributeGroup', 'anyAttribute']}
1620     tag = 'attributeGroup'
1621
1622     def __init__(self, parent):
1623         XMLSchemaComponent.__init__(self, parent)
1624         self.annotation = None
1625         self.attr_content = None
1626
1627     def getAttributeContent(self):
1628         return self.attr_content
1629
1630     def fromDom(self, node):
1631         self.setAttributes(node)
1632         contents = self.getContents(node)
1633         content = []
1634
1635         for indx in range(len(contents)):
1636             component = SplitQName(contents[indx].getTagName())[1]
1637             if (component == 'annotation') and (not indx):
1638                 self.annotation = Annotation(self)
1639                 self.annotation.fromDom(contents[indx])
1640             elif component == 'attribute':
1641                 if contents[indx].hasattr('name'):
1642                     content.append(LocalAttributeDeclaration(self))
1643                 elif contents[indx].hasattr('ref'):
1644                     content.append(AttributeReference(self))
1645                 else:
1646                     raise SchemaError, 'Unknown attribute type'
1647                 content[-1].fromDom(contents[indx])
1648             elif component == 'attributeGroup':
1649                 content.append(AttributeGroupReference(self))
1650                 content[-1].fromDom(contents[indx])
1651             elif component == 'anyAttribute':
1652                 if len(contents) != indx+1: 
1653                     raise SchemaError, 'anyAttribute is out of order in %s' %self.getItemTrace()
1654                 content.append(AttributeWildCard(self))
1655                 content[-1].fromDom(contents[indx])
1656             else:
1657                 raise SchemaError, 'Unknown component (%s)' %(contents[indx].getTagName())
1658
1659         self.attr_content = tuple(content)
1660
1661 class AttributeGroupReference(XMLSchemaComponent,\
1662                               AttributeGroupMarker,\
1663                               ReferenceMarker):
1664     """<attributeGroup ref>
1665        parents: 
1666            complexType, restriction, extension, attributeGroup
1667        attributes:
1668            id -- ID
1669            ref -- QName, required
1670        contents:
1671            annotation?
1672     """
1673     required = ['ref']
1674     attributes = {'id':None, 
1675         'ref':None}
1676     contents = {'xsd':['annotation']}
1677     tag = 'attributeGroup'
1678
1679     def __init__(self, parent):
1680         XMLSchemaComponent.__init__(self, parent)
1681         self.annotation = None
1682
1683     def getAttributeGroup(self, attribute='ref'):
1684         """attribute -- attribute with a QName value (eg. type).
1685            collection -- check types collection in parent Schema instance
1686         """
1687         return XMLSchemaComponent.getAttributeGroup(self, attribute)
1688
1689     def fromDom(self, node):
1690         self.setAttributes(node)
1691         contents = self.getContents(node)
1692
1693         for i in contents:
1694             component = SplitQName(i.getTagName())[1]
1695             if component == 'annotation' and not self.annotation:
1696                 self.annotation = Annotation(self)
1697                 self.annotation.fromDom(i)
1698             else:
1699                 raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
1700
1701
1702
1703 ######################################################
1704 # Elements
1705 #####################################################
1706 class IdentityConstrants(XMLSchemaComponent):
1707     """Allow one to uniquely identify nodes in a document and ensure the 
1708        integrity of references between them.
1709
1710        attributes -- dictionary of attributes
1711        selector -- XPath to selected nodes
1712        fields -- list of XPath to key field
1713     """
1714     def __init__(self, parent):
1715         XMLSchemaComponent.__init__(self, parent)
1716         self.selector = None
1717         self.fields = None
1718         self.annotation = None
1719
1720     def fromDom(self, node):
1721         self.setAttributes(node)
1722         contents = self.getContents(node)
1723         fields = []
1724
1725         for i in contents:
1726             component = SplitQName(i.getTagName())[1]
1727             if component in self.__class__.contents['xsd']:
1728                 if component == 'annotation' and not self.annotation:
1729                     self.annotation = Annotation(self)
1730                     self.annotation.fromDom(i)
1731                 elif component == 'selector':
1732                     self.selector = self.Selector(self)
1733                     self.selector.fromDom(i)
1734                     continue
1735                 elif component == 'field':
1736                     fields.append(self.Field(self))
1737                     fields[-1].fromDom(i)
1738                     continue
1739                 else:
1740                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
1741             else:
1742                 raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
1743             self.fields = tuple(fields)
1744
1745
1746     class Constraint(XMLSchemaComponent):
1747         def __init__(self, parent):
1748             XMLSchemaComponent.__init__(self, parent)
1749             self.annotation = None
1750
1751         def fromDom(self, node):
1752             self.setAttributes(node)
1753             contents = self.getContents(node)
1754
1755             for i in contents:
1756                 component = SplitQName(i.getTagName())[1]
1757                 if component in self.__class__.contents['xsd']:
1758                     if component == 'annotation' and not self.annotation:
1759                         self.annotation = Annotation(self)
1760                         self.annotation.fromDom(i)
1761                     else:
1762                         raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
1763                 else:
1764                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
1765
1766     class Selector(Constraint):
1767         """<selector xpath>
1768            parent: 
1769                unique, key, keyref
1770            attributes:
1771                id -- ID
1772                xpath -- XPath subset,  required
1773            contents:
1774                annotation?
1775         """
1776         required = ['xpath']
1777         attributes = {'id':None, 
1778             'xpath':None}
1779         contents = {'xsd':['annotation']}
1780         tag = 'selector'
1781
1782     class Field(Constraint): 
1783         """<field xpath>
1784            parent: 
1785                unique, key, keyref
1786            attributes:
1787                id -- ID
1788                xpath -- XPath subset,  required
1789            contents:
1790                annotation?
1791         """
1792         required = ['xpath']
1793         attributes = {'id':None, 
1794             'xpath':None}
1795         contents = {'xsd':['annotation']}
1796         tag = 'field'
1797
1798
1799 class Unique(IdentityConstrants):
1800     """<unique name> Enforce fields are unique w/i a specified scope.
1801
1802        parent: 
1803            element
1804        attributes:
1805            id -- ID
1806            name -- NCName,  required
1807        contents:
1808            annotation?, selector, field+
1809     """
1810     required = ['name']
1811     attributes = {'id':None, 
1812         'name':None}
1813     contents = {'xsd':['annotation', 'selector', 'field']}
1814     tag = 'unique'
1815
1816
1817 class Key(IdentityConstrants):
1818     """<key name> Enforce fields are unique w/i a specified scope, and all
1819            field values are present w/i document.  Fields cannot
1820            be nillable.
1821
1822        parent: 
1823            element
1824        attributes:
1825            id -- ID
1826            name -- NCName,  required
1827        contents:
1828            annotation?, selector, field+
1829     """
1830     required = ['name']
1831     attributes = {'id':None, 
1832         'name':None}
1833     contents = {'xsd':['annotation', 'selector', 'field']}
1834     tag = 'key'
1835
1836
1837 class KeyRef(IdentityConstrants):
1838     """<keyref name refer> Ensure a match between two sets of values in an 
1839            instance.
1840        parent: 
1841            element
1842        attributes:
1843            id -- ID
1844            name -- NCName,  required
1845            refer -- QName,  required
1846        contents:
1847            annotation?, selector, field+
1848     """
1849     required = ['name', 'refer']
1850     attributes = {'id':None, 
1851         'name':None,
1852         'refer':None}
1853     contents = {'xsd':['annotation', 'selector', 'field']}
1854     tag = 'keyref'
1855
1856
1857 class ElementDeclaration(XMLSchemaComponent,\
1858                          ElementMarker,\
1859                          DeclarationMarker):
1860     """<element name>
1861        parents:
1862            schema
1863        attributes:
1864            id -- ID
1865            name -- NCName,  required
1866            type -- QName
1867            default -- string
1868            fixed -- string
1869            nillable -- boolean,  false
1870            abstract -- boolean,  false
1871            substitutionGroup -- QName
1872            block -- ('#all' | ('substition' | 'extension' | 'restriction')*), 
1873                schema.blockDefault 
1874            final -- ('#all' | ('extension' | 'restriction')*), 
1875                schema.finalDefault 
1876        contents:
1877            annotation?, (simpleType,complexType)?, (key | keyref | unique)*
1878            
1879     """
1880     required = ['name']
1881     attributes = {'id':None, 
1882         'name':None,
1883         'type':None,
1884         'default':None,
1885         'fixed':None,
1886         'nillable':0,
1887         'abstract':0,
1888         'substitutionGroup':None,
1889         'block':lambda self: self._parent().getBlockDefault(),
1890         'final':lambda self: self._parent().getFinalDefault()}
1891     contents = {'xsd':['annotation', 'simpleType', 'complexType', 'key',\
1892         'keyref', 'unique']}
1893     tag = 'element'
1894
1895     def __init__(self, parent):
1896         XMLSchemaComponent.__init__(self, parent)
1897         self.annotation = None
1898         self.content = None
1899         self.constraints = ()
1900
1901     def isQualified(self):
1902         """Global elements are always qualified.
1903         """
1904         return True
1905     
1906     def getAttribute(self, attribute):
1907         """return attribute.
1908         If attribute is type and it's None, and no simple or complex content, 
1909         return the default type "xsd:anyType"
1910         """
1911         value = XMLSchemaComponent.getAttribute(self, attribute)
1912         if attribute != 'type' or value is not None:
1913             return value
1914         
1915         if self.content is not None:
1916             return None
1917         
1918         parent = self
1919         while 1:
1920             nsdict = parent.attributes[XMLSchemaComponent.xmlns]
1921             for k,v in nsdict.items():
1922                 if v not in SCHEMA.XSD_LIST: continue
1923                 return TypeDescriptionComponent((v, 'anyType'))
1924             
1925             if isinstance(parent, WSDLToolsAdapter)\
1926                 or not hasattr(parent, '_parent'):
1927                 break
1928             
1929             parent = parent._parent()
1930             
1931         raise SchemaError, 'failed to locate the XSD namespace'
1932     
1933     def getElementDeclaration(self, attribute):
1934         raise Warning, 'invalid operation for <%s>' %self.tag
1935
1936     def getTypeDefinition(self, attribute=None):
1937         """If attribute is None, "type" is assumed, return the corresponding
1938         representation of the global type definition (TypeDefinition),
1939         or the local definition if don't find "type".  To maintain backwards
1940         compat, if attribute is provided call base class method.
1941         """
1942         if attribute:
1943             return XMLSchemaComponent.getTypeDefinition(self, attribute)
1944         gt = XMLSchemaComponent.getTypeDefinition(self, 'type')
1945         if gt:
1946             return gt
1947         return self.content
1948
1949     def getConstraints(self):
1950         return self._constraints
1951     def setConstraints(self, constraints):
1952         self._constraints = tuple(constraints)
1953     constraints = property(getConstraints, setConstraints, None, "tuple of key, keyref, unique constraints")
1954
1955     def fromDom(self, node):
1956         self.setAttributes(node)
1957         contents = self.getContents(node)
1958         constraints = []
1959         for i in contents:
1960             component = SplitQName(i.getTagName())[1]
1961             if component in self.__class__.contents['xsd']:
1962                 if component == 'annotation' and not self.annotation:
1963                     self.annotation = Annotation(self)
1964                     self.annotation.fromDom(i)
1965                 elif component == 'simpleType' and not self.content:
1966                     self.content = AnonymousSimpleType(self)
1967                     self.content.fromDom(i)
1968                 elif component == 'complexType' and not self.content:
1969                     self.content = LocalComplexType(self)
1970                     self.content.fromDom(i)
1971                 elif component == 'key':
1972                     constraints.append(Key(self))
1973                     constraints[-1].fromDom(i)
1974                 elif component == 'keyref':
1975                     constraints.append(KeyRef(self))
1976                     constraints[-1].fromDom(i)
1977                 elif component == 'unique':
1978                     constraints.append(Unique(self))
1979                     constraints[-1].fromDom(i)
1980                 else:
1981                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
1982             else:
1983                 raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
1984
1985         self.constraints = constraints
1986
1987
1988 class LocalElementDeclaration(ElementDeclaration,\
1989                               LocalMarker):
1990     """<element>
1991        parents:
1992            all, choice, sequence
1993        attributes:
1994            id -- ID
1995            name -- NCName,  required
1996            form -- ('qualified' | 'unqualified'), schema.elementFormDefault
1997            type -- QName
1998            minOccurs -- Whole Number, 1
1999            maxOccurs -- (Whole Number | 'unbounded'), 1
2000            default -- string
2001            fixed -- string
2002            nillable -- boolean,  false
2003            block -- ('#all' | ('extension' | 'restriction')*), schema.blockDefault 
2004        contents:
2005            annotation?, (simpleType,complexType)?, (key | keyref | unique)*
2006     """
2007     required = ['name']
2008     attributes = {'id':None, 
2009         'name':None,
2010         'form':lambda self: GetSchema(self).getElementFormDefault(),
2011         'type':None,
2012         'minOccurs':'1',
2013         'maxOccurs':'1',
2014         'default':None,
2015         'fixed':None,
2016         'nillable':0,
2017         'abstract':0,
2018         'block':lambda self: GetSchema(self).getBlockDefault()}
2019     contents = {'xsd':['annotation', 'simpleType', 'complexType', 'key',\
2020         'keyref', 'unique']}
2021
2022     def isQualified(self):
2023         """
2024 Local elements can be qualified or unqualifed according
2025         to the attribute form, or the elementFormDefault.  By default
2026         local elements are unqualified.
2027         """
2028         form = self.getAttribute('form')
2029         if form == 'qualified':
2030             return True
2031         if form == 'unqualified':
2032             return False
2033         raise SchemaError, 'Bad form (%s) for element: %s' %(form, self.getItemTrace())
2034
2035
2036 class ElementReference(XMLSchemaComponent,\
2037                        ElementMarker,\
2038                        ReferenceMarker):
2039     """<element ref>
2040        parents: 
2041            all, choice, sequence
2042        attributes:
2043            id -- ID
2044            ref -- QName, required
2045            minOccurs -- Whole Number, 1
2046            maxOccurs -- (Whole Number | 'unbounded'), 1
2047        contents:
2048            annotation?
2049     """
2050     required = ['ref']
2051     attributes = {'id':None, 
2052         'ref':None,
2053         'minOccurs':'1',
2054         'maxOccurs':'1'}
2055     contents = {'xsd':['annotation']}
2056     tag = 'element'
2057
2058     def __init__(self, parent):
2059         XMLSchemaComponent.__init__(self, parent)
2060         self.annotation = None
2061
2062     def getElementDeclaration(self, attribute=None):
2063         """If attribute is None, "ref" is assumed, return the corresponding
2064         representation of the global element declaration (ElementDeclaration),
2065         To maintain backwards compat, if attribute is provided call base class method.
2066         """
2067         if attribute:
2068             return XMLSchemaComponent.getElementDeclaration(self, attribute)
2069         return XMLSchemaComponent.getElementDeclaration(self, 'ref')
2070  
2071     def fromDom(self, node):
2072         self.annotation = None
2073         self.setAttributes(node)
2074         for i in self.getContents(node):
2075             component = SplitQName(i.getTagName())[1]
2076             if component in self.__class__.contents['xsd']:
2077                 if component == 'annotation' and not self.annotation:
2078                     self.annotation = Annotation(self)
2079                     self.annotation.fromDom(i)
2080                 else:
2081                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
2082
2083
2084 class ElementWildCard(LocalElementDeclaration, WildCardMarker):
2085     """<any>
2086        parents: 
2087            choice, sequence
2088        attributes:
2089            id -- ID
2090            minOccurs -- Whole Number, 1
2091            maxOccurs -- (Whole Number | 'unbounded'), 1
2092            namespace -- '##any' | '##other' | 
2093                         (anyURI* | '##targetNamespace' | '##local'), ##any
2094            processContents -- 'lax' | 'skip' | 'strict', strict
2095        contents:
2096            annotation?
2097     """
2098     required = []
2099     attributes = {'id':None, 
2100         'minOccurs':'1',
2101         'maxOccurs':'1',
2102         'namespace':'##any',
2103         'processContents':'strict'}
2104     contents = {'xsd':['annotation']}
2105     tag = 'any'
2106
2107     def __init__(self, parent):
2108         XMLSchemaComponent.__init__(self, parent)
2109         self.annotation = None
2110
2111     def isQualified(self):
2112         """
2113         Global elements are always qualified, but if processContents
2114         are not strict could have dynamically generated local elements.
2115         """
2116         return GetSchema(self).isElementFormDefaultQualified()
2117
2118     def getAttribute(self, attribute):
2119         """return attribute.
2120         """
2121         return XMLSchemaComponent.getAttribute(self, attribute)
2122
2123     def getTypeDefinition(self, attribute):
2124         raise Warning, 'invalid operation for <%s>' % self.tag
2125
2126     def fromDom(self, node):
2127         self.annotation = None
2128         self.setAttributes(node)
2129         for i in self.getContents(node):
2130             component = SplitQName(i.getTagName())[1]
2131             if component in self.__class__.contents['xsd']:
2132                 if component == 'annotation' and not self.annotation:
2133                     self.annotation = Annotation(self)
2134                     self.annotation.fromDom(i)
2135                 else:
2136                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
2137
2138
2139 ######################################################
2140 # Model Groups
2141 #####################################################
2142 class Sequence(XMLSchemaComponent,\
2143                SequenceMarker):
2144     """<sequence>
2145        parents: 
2146            complexType, extension, restriction, group, choice, sequence
2147        attributes:
2148            id -- ID
2149            minOccurs -- Whole Number, 1
2150            maxOccurs -- (Whole Number | 'unbounded'), 1
2151
2152        contents:
2153            annotation?, (element | group | choice | sequence | any)*
2154     """
2155     attributes = {'id':None, 
2156         'minOccurs':'1',
2157         'maxOccurs':'1'}
2158     contents = {'xsd':['annotation', 'element', 'group', 'choice', 'sequence',\
2159          'any']}
2160     tag = 'sequence'
2161
2162     def __init__(self, parent):
2163         XMLSchemaComponent.__init__(self, parent)
2164         self.annotation = None
2165         self.content = None
2166
2167     def fromDom(self, node):
2168         self.setAttributes(node)
2169         contents = self.getContents(node)
2170         content = []
2171
2172         for i in contents:
2173             component = SplitQName(i.getTagName())[1]
2174             if component in self.__class__.contents['xsd']:
2175                 if component == 'annotation' and not self.annotation:
2176                     self.annotation = Annotation(self)
2177                     self.annotation.fromDom(i)
2178                     continue
2179                 elif component == 'element':
2180                     if i.hasattr('ref'):
2181                         content.append(ElementReference(self))
2182                     else:
2183                         content.append(LocalElementDeclaration(self))
2184                 elif component == 'group':
2185                     content.append(ModelGroupReference(self))
2186                 elif component == 'choice':
2187                     content.append(Choice(self))
2188                 elif component == 'sequence':
2189                     content.append(Sequence(self))
2190                 elif component == 'any':
2191                     content.append(ElementWildCard(self))
2192                 else:
2193                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
2194                 content[-1].fromDom(i)
2195             else:
2196                 raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
2197         self.content = tuple(content)
2198
2199
2200 class All(XMLSchemaComponent,\
2201           AllMarker):
2202     """<all>
2203        parents: 
2204            complexType, extension, restriction, group
2205        attributes:
2206            id -- ID
2207            minOccurs -- '0' | '1', 1
2208            maxOccurs -- '1', 1
2209
2210        contents:
2211            annotation?, element*
2212     """
2213     attributes = {'id':None, 
2214         'minOccurs':'1',
2215         'maxOccurs':'1'}
2216     contents = {'xsd':['annotation', 'element']}
2217     tag = 'all'
2218
2219     def __init__(self, parent):
2220         XMLSchemaComponent.__init__(self, parent)
2221         self.annotation = None
2222         self.content = None
2223
2224     def fromDom(self, node):
2225         self.setAttributes(node)
2226         contents = self.getContents(node)
2227         content = []
2228
2229         for i in contents:
2230             component = SplitQName(i.getTagName())[1]
2231             if component in self.__class__.contents['xsd']:
2232                 if component == 'annotation' and not self.annotation:
2233                     self.annotation = Annotation(self)
2234                     self.annotation.fromDom(i)
2235                     continue
2236                 elif component == 'element':
2237                     if i.hasattr('ref'):
2238                         content.append(ElementReference(self))
2239                     else:
2240                         content.append(LocalElementDeclaration(self))
2241                 else:
2242                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
2243                 content[-1].fromDom(i)
2244             else:
2245                 raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
2246         self.content = tuple(content)
2247
2248
2249 class Choice(XMLSchemaComponent,\
2250              ChoiceMarker):
2251     """<choice>
2252        parents: 
2253            complexType, extension, restriction, group, choice, sequence
2254        attributes:
2255            id -- ID
2256            minOccurs -- Whole Number, 1
2257            maxOccurs -- (Whole Number | 'unbounded'), 1
2258
2259        contents:
2260            annotation?, (element | group | choice | sequence | any)*
2261     """
2262     attributes = {'id':None, 
2263         'minOccurs':'1',
2264         'maxOccurs':'1'}
2265     contents = {'xsd':['annotation', 'element', 'group', 'choice', 'sequence',\
2266          'any']}
2267     tag = 'choice'
2268
2269     def __init__(self, parent):
2270         XMLSchemaComponent.__init__(self, parent)
2271         self.annotation = None
2272         self.content = None
2273
2274     def fromDom(self, node):
2275         self.setAttributes(node)
2276         contents = self.getContents(node)
2277         content = []
2278
2279         for i in contents:
2280             component = SplitQName(i.getTagName())[1]
2281             if component in self.__class__.contents['xsd']:
2282                 if component == 'annotation' and not self.annotation:
2283                     self.annotation = Annotation(self)
2284                     self.annotation.fromDom(i)
2285                     continue
2286                 elif component == 'element':
2287                     if i.hasattr('ref'):
2288                         content.append(ElementReference(self))
2289                     else:
2290                         content.append(LocalElementDeclaration(self))
2291                 elif component == 'group':
2292                     content.append(ModelGroupReference(self))
2293                 elif component == 'choice':
2294                     content.append(Choice(self))
2295                 elif component == 'sequence':
2296                     content.append(Sequence(self))
2297                 elif component == 'any':
2298                     content.append(ElementWildCard(self))
2299                 else:
2300                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
2301                 content[-1].fromDom(i)
2302             else:
2303                 raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
2304         self.content = tuple(content)
2305
2306
2307 class ModelGroupDefinition(XMLSchemaComponent,\
2308                            ModelGroupMarker,\
2309                            DefinitionMarker):
2310     """<group name>
2311        parents:
2312            redefine, schema
2313        attributes:
2314            id -- ID
2315            name -- NCName,  required
2316
2317        contents:
2318            annotation?, (all | choice | sequence)?
2319     """
2320     required = ['name']
2321     attributes = {'id':None, 
2322         'name':None}
2323     contents = {'xsd':['annotation', 'all', 'choice', 'sequence']}
2324     tag = 'group'
2325
2326     def __init__(self, parent):
2327         XMLSchemaComponent.__init__(self, parent)
2328         self.annotation = None
2329         self.content = None
2330
2331     def fromDom(self, node):
2332         self.setAttributes(node)
2333         contents = self.getContents(node)
2334
2335         for i in contents:
2336             component = SplitQName(i.getTagName())[1]
2337             if component in self.__class__.contents['xsd']:
2338                 if component == 'annotation' and not self.annotation:
2339                     self.annotation = Annotation(self)
2340                     self.annotation.fromDom(i)
2341                     continue
2342                 elif component == 'all' and not self.content:
2343                     self.content = All(self)
2344                 elif component == 'choice' and not self.content:
2345                     self.content = Choice(self)
2346                 elif component == 'sequence' and not self.content:
2347                     self.content = Sequence(self)
2348                 else:
2349                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
2350                 self.content.fromDom(i)
2351             else:
2352                 raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
2353
2354
2355 class ModelGroupReference(XMLSchemaComponent,\
2356                           ModelGroupMarker,\
2357                           ReferenceMarker):
2358     """<group ref>
2359        parents:
2360            choice, complexType, extension, restriction, sequence
2361        attributes:
2362            id -- ID
2363            ref -- NCName,  required
2364            minOccurs -- Whole Number, 1
2365            maxOccurs -- (Whole Number | 'unbounded'), 1
2366
2367        contents:
2368            annotation?
2369     """
2370     required = ['ref']
2371     attributes = {'id':None, 
2372         'ref':None,
2373         'minOccurs':'1',
2374         'maxOccurs':'1'}
2375     contents = {'xsd':['annotation']}
2376     tag = 'group'
2377
2378     def __init__(self, parent):
2379         XMLSchemaComponent.__init__(self, parent)
2380         self.annotation = None
2381
2382     def getModelGroupReference(self):
2383         return self.getModelGroup('ref')
2384
2385     def fromDom(self, node):
2386         self.setAttributes(node)
2387         contents = self.getContents(node)
2388
2389         for i in contents:
2390             component = SplitQName(i.getTagName())[1]
2391             if component in self.__class__.contents['xsd']:
2392                 if component == 'annotation' and not self.annotation:
2393                     self.annotation = Annotation(self)
2394                     self.annotation.fromDom(i)
2395                 else:
2396                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
2397             else:
2398                 raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
2399
2400
2401
2402 class ComplexType(XMLSchemaComponent,\
2403                   DefinitionMarker,\
2404                   ComplexMarker):
2405     """<complexType name>
2406        parents:
2407            redefine, schema
2408        attributes:
2409            id -- ID
2410            name -- NCName,  required
2411            mixed -- boolean, false
2412            abstract -- boolean,  false
2413            block -- ('#all' | ('extension' | 'restriction')*), schema.blockDefault 
2414            final -- ('#all' | ('extension' | 'restriction')*), schema.finalDefault 
2415
2416        contents:
2417            annotation?, (simpleContent | complexContent | 
2418            ((group | all | choice | sequence)?, (attribute | attributeGroup)*, anyAttribute?))
2419     """
2420     required = ['name']
2421     attributes = {'id':None, 
2422         'name':None,
2423         'mixed':0,
2424         'abstract':0,
2425         'block':lambda self: self._parent().getBlockDefault(),
2426         'final':lambda self: self._parent().getFinalDefault()}
2427     contents = {'xsd':['annotation', 'simpleContent', 'complexContent',\
2428         'group', 'all', 'choice', 'sequence', 'attribute', 'attributeGroup',\
2429         'anyAttribute', 'any']}
2430     tag = 'complexType'
2431
2432     def __init__(self, parent):
2433         XMLSchemaComponent.__init__(self, parent)
2434         self.annotation = None
2435         self.content = None
2436         self.attr_content = None
2437
2438     def isMixed(self):
2439         m = self.getAttribute('mixed')
2440         if m == 0 or m == False:
2441             return False
2442         if isinstance(m, basestring) is True:
2443             if m in ('false', '0'):
2444                 return False
2445             if m in ('true', '1'):
2446                 return True
2447
2448         raise SchemaError, 'invalid value for attribute mixed(%s): %s'\
2449             %(m, self.getItemTrace())
2450
2451     def getAttributeContent(self):
2452         return self.attr_content
2453
2454     def getElementDeclaration(self, attribute):
2455         raise Warning, 'invalid operation for <%s>' %self.tag
2456
2457     def getTypeDefinition(self, attribute):
2458         raise Warning, 'invalid operation for <%s>' %self.tag
2459
2460     def fromDom(self, node):
2461         self.setAttributes(node)
2462         contents = self.getContents(node)
2463       
2464         indx = 0
2465         num = len(contents)
2466         if not num:
2467             return
2468
2469         component = SplitQName(contents[indx].getTagName())[1]
2470         if component == 'annotation':
2471             self.annotation = Annotation(self)
2472             self.annotation.fromDom(contents[indx])
2473             indx += 1
2474             if indx < num:
2475                 component = SplitQName(contents[indx].getTagName())[1]
2476
2477         self.content = None
2478         if component == 'simpleContent':
2479             self.content = self.__class__.SimpleContent(self)
2480             self.content.fromDom(contents[indx])
2481         elif component == 'complexContent':
2482             self.content = self.__class__.ComplexContent(self)
2483             self.content.fromDom(contents[indx])
2484         else:
2485             if component == 'all':
2486                 self.content = All(self)
2487             elif component == 'choice':
2488                 self.content = Choice(self)
2489             elif component == 'sequence':
2490                 self.content = Sequence(self)
2491             elif component == 'group':
2492                 self.content = ModelGroupReference(self)
2493
2494             if self.content:
2495                 self.content.fromDom(contents[indx])
2496                 indx += 1
2497
2498             self.attr_content = []
2499             while indx < num:
2500                 component = SplitQName(contents[indx].getTagName())[1]
2501                 if component == 'attribute':
2502                     if contents[indx].hasattr('ref'):
2503                         self.attr_content.append(AttributeReference(self))
2504                     else:
2505                         self.attr_content.append(LocalAttributeDeclaration(self))
2506                 elif component == 'attributeGroup':
2507                     self.attr_content.append(AttributeGroupReference(self))
2508                 elif component == 'anyAttribute':
2509                     self.attr_content.append(AttributeWildCard(self))
2510                 else:
2511                     raise SchemaError, 'Unknown component (%s): %s' \
2512                         %(contents[indx].getTagName(),self.getItemTrace())
2513                 self.attr_content[-1].fromDom(contents[indx])
2514                 indx += 1
2515
2516     class _DerivedType(XMLSchemaComponent):
2517         def __init__(self, parent):
2518             XMLSchemaComponent.__init__(self, parent)
2519             self.annotation = None
2520             # XXX remove attribute derivation, inconsistent
2521             self.derivation = None
2522             self.content = None
2523
2524         def fromDom(self, node):
2525             self.setAttributes(node)
2526             contents = self.getContents(node)
2527
2528             for i in contents:
2529                 component = SplitQName(i.getTagName())[1]
2530                 if component in self.__class__.contents['xsd']:
2531                     if component == 'annotation' and not self.annotation:
2532                         self.annotation = Annotation(self)
2533                         self.annotation.fromDom(i)
2534                         continue
2535                     elif component == 'restriction' and not self.derivation:
2536                         self.derivation = self.__class__.Restriction(self)
2537                     elif component == 'extension' and not self.derivation:
2538                         self.derivation = self.__class__.Extension(self)
2539                     else:
2540                         raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
2541                 else:
2542                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
2543                 self.derivation.fromDom(i)
2544             self.content = self.derivation
2545
2546     class ComplexContent(_DerivedType,\
2547                          ComplexMarker):
2548         """<complexContent>
2549            parents:
2550                complexType
2551            attributes:
2552                id -- ID
2553                mixed -- boolean, false
2554
2555            contents:
2556                annotation?, (restriction | extension)
2557         """
2558         attributes = {'id':None, 
2559             'mixed':0}
2560         contents = {'xsd':['annotation', 'restriction', 'extension']}
2561         tag = 'complexContent'
2562
2563         def isMixed(self):
2564             m = self.getAttribute('mixed')
2565             if m == 0 or m == False:
2566                 return False
2567             if isinstance(m, basestring) is True:
2568                 if m in ('false', '0'):
2569                     return False
2570                 if m in ('true', '1'):
2571                     return True
2572             raise SchemaError, 'invalid value for attribute mixed(%s): %s'\
2573                 %(m, self.getItemTrace())
2574
2575         class _DerivationBase(XMLSchemaComponent):
2576             """<extension>,<restriction>
2577                parents:
2578                    complexContent
2579                attributes:
2580                    id -- ID
2581                    base -- QName, required
2582
2583                contents:
2584                    annotation?, (group | all | choice | sequence)?, 
2585                        (attribute | attributeGroup)*, anyAttribute?
2586             """
2587             required = ['base']
2588             attributes = {'id':None, 
2589                 'base':None }
2590             contents = {'xsd':['annotation', 'group', 'all', 'choice',\
2591                 'sequence', 'attribute', 'attributeGroup', 'anyAttribute']}
2592
2593             def __init__(self, parent):
2594                 XMLSchemaComponent.__init__(self, parent)
2595                 self.annotation = None
2596                 self.content = None
2597                 self.attr_content = None
2598
2599             def getAttributeContent(self):
2600                 return self.attr_content
2601
2602             def fromDom(self, node):
2603                 self.setAttributes(node)
2604                 contents = self.getContents(node)
2605
2606                 indx = 0
2607                 num = len(contents)
2608                 #XXX ugly
2609                 if not num:
2610                     return
2611                 component = SplitQName(contents[indx].getTagName())[1]
2612                 if component == 'annotation':
2613                     self.annotation = Annotation(self)
2614                     self.annotation.fromDom(contents[indx])
2615                     indx += 1
2616                     component = SplitQName(contents[indx].getTagName())[1]
2617
2618                 if component == 'all':
2619                     self.content = All(self)
2620                     self.content.fromDom(contents[indx])
2621                     indx += 1
2622                 elif component == 'choice':
2623                     self.content = Choice(self)
2624                     self.content.fromDom(contents[indx])
2625                     indx += 1
2626                 elif component == 'sequence':
2627                     self.content = Sequence(self)
2628                     self.content.fromDom(contents[indx])
2629                     indx += 1
2630                 elif component == 'group':
2631                     self.content = ModelGroupReference(self)
2632                     self.content.fromDom(contents[indx])
2633                     indx += 1
2634                 else:
2635                     self.content = None
2636
2637                 self.attr_content = []
2638                 while indx < num:
2639                     component = SplitQName(contents[indx].getTagName())[1]
2640                     if component == 'attribute':
2641                         if contents[indx].hasattr('ref'):
2642                             self.attr_content.append(AttributeReference(self))
2643                         else:
2644                             self.attr_content.append(LocalAttributeDeclaration(self))
2645                     elif component == 'attributeGroup':
2646                         if contents[indx].hasattr('ref'):
2647                             self.attr_content.append(AttributeGroupReference(self))
2648                         else:
2649                             self.attr_content.append(AttributeGroupDefinition(self))
2650                     elif component == 'anyAttribute':
2651                         self.attr_content.append(AttributeWildCard(self))
2652                     else:
2653                         raise SchemaError, 'Unknown component (%s)' %(contents[indx].getTagName())
2654                     self.attr_content[-1].fromDom(contents[indx])
2655                     indx += 1
2656
2657         class Extension(_DerivationBase, 
2658                         ExtensionMarker):
2659             """<extension base>
2660                parents:
2661                    complexContent
2662                attributes:
2663                    id -- ID
2664                    base -- QName, required
2665
2666                contents:
2667                    annotation?, (group | all | choice | sequence)?, 
2668                        (attribute | attributeGroup)*, anyAttribute?
2669             """
2670             tag = 'extension'
2671
2672         class Restriction(_DerivationBase,\
2673                           RestrictionMarker):
2674             """<restriction base>
2675                parents:
2676                    complexContent
2677                attributes:
2678                    id -- ID
2679                    base -- QName, required
2680
2681                contents:
2682                    annotation?, (group | all | choice | sequence)?, 
2683                        (attribute | attributeGroup)*, anyAttribute?
2684             """
2685             tag = 'restriction'
2686
2687
2688     class SimpleContent(_DerivedType,\
2689                         SimpleMarker):
2690         """<simpleContent>
2691            parents:
2692                complexType
2693            attributes:
2694                id -- ID
2695
2696            contents:
2697                annotation?, (restriction | extension)
2698         """
2699         attributes = {'id':None}
2700         contents = {'xsd':['annotation', 'restriction', 'extension']}
2701         tag = 'simpleContent'
2702
2703         class Extension(XMLSchemaComponent,\
2704                         ExtensionMarker):
2705             """<extension base>
2706                parents:
2707                    simpleContent
2708                attributes:
2709                    id -- ID
2710                    base -- QName, required
2711
2712                contents:
2713                    annotation?, (attribute | attributeGroup)*, anyAttribute?
2714             """
2715             required = ['base']
2716             attributes = {'id':None, 
2717                 'base':None }
2718             contents = {'xsd':['annotation', 'attribute', 'attributeGroup', 
2719                 'anyAttribute']}
2720             tag = 'extension'
2721
2722             def __init__(self, parent):
2723                 XMLSchemaComponent.__init__(self, parent)
2724                 self.annotation = None
2725                 self.attr_content = None
2726  
2727             def getAttributeContent(self):
2728                 return self.attr_content
2729
2730             def fromDom(self, node):
2731                 self.setAttributes(node)
2732                 contents = self.getContents(node)
2733
2734                 indx = 0
2735                 num = len(contents)
2736
2737                 if num:
2738                     component = SplitQName(contents[indx].getTagName())[1]
2739                     if component == 'annotation':
2740                         self.annotation = Annotation(self)
2741                         self.annotation.fromDom(contents[indx])
2742                         indx += 1
2743                         component = SplitQName(contents[indx].getTagName())[1]
2744     
2745                 content = []
2746                 while indx < num:
2747                     component = SplitQName(contents[indx].getTagName())[1]
2748                     if component == 'attribute':
2749                         if contents[indx].hasattr('ref'):
2750                             content.append(AttributeReference(self))
2751                         else:
2752                             content.append(LocalAttributeDeclaration(self))
2753                     elif component == 'attributeGroup':
2754                         content.append(AttributeGroupReference(self))
2755                     elif component == 'anyAttribute':
2756                         content.append(AttributeWildCard(self))
2757                     else:
2758                         raise SchemaError, 'Unknown component (%s)'\
2759                             %(contents[indx].getTagName())
2760                     content[-1].fromDom(contents[indx])
2761                     indx += 1
2762                 self.attr_content = tuple(content)
2763
2764
2765         class Restriction(XMLSchemaComponent,\
2766                           RestrictionMarker):
2767             """<restriction base>
2768                parents:
2769                    simpleContent
2770                attributes:
2771                    id -- ID
2772                    base -- QName, required
2773
2774                contents:
2775                    annotation?, simpleType?, (enumeration | length | 
2776                    maxExclusive | maxInclusive | maxLength | minExclusive | 
2777                    minInclusive | minLength | pattern | fractionDigits | 
2778                    totalDigits | whiteSpace)*, (attribute | attributeGroup)*, 
2779                    anyAttribute?
2780             """
2781             required = ['base']
2782             attributes = {'id':None, 
2783                 'base':None }
2784             contents = {'xsd':['annotation', 'simpleType', 'attribute',\
2785                 'attributeGroup', 'anyAttribute'] + RestrictionMarker.facets}
2786             tag = 'restriction'
2787
2788             def __init__(self, parent):
2789                 XMLSchemaComponent.__init__(self, parent)
2790                 self.annotation = None
2791                 self.content = None
2792                 self.attr_content = None
2793  
2794             def getAttributeContent(self):
2795                 return self.attr_content
2796
2797             def fromDom(self, node):
2798                 self.content = []
2799                 self.setAttributes(node)
2800                 contents = self.getContents(node)
2801
2802                 indx = 0
2803                 num = len(contents)
2804                 component = SplitQName(contents[indx].getTagName())[1]
2805                 if component == 'annotation':
2806                     self.annotation = Annotation(self)
2807                     self.annotation.fromDom(contents[indx])
2808                     indx += 1
2809                     component = SplitQName(contents[indx].getTagName())[1]
2810
2811                 content = []
2812                 while indx < num:
2813                     component = SplitQName(contents[indx].getTagName())[1]
2814                     if component == 'attribute':
2815                         if contents[indx].hasattr('ref'):
2816                             content.append(AttributeReference(self))
2817                         else:
2818                             content.append(LocalAttributeDeclaration(self))
2819                     elif component == 'attributeGroup':
2820                         content.append(AttributeGroupReference(self))
2821                     elif component == 'anyAttribute':
2822                         content.append(AttributeWildCard(self))
2823                     elif component == 'simpleType':
2824                         self.content.append(AnonymousSimpleType(self))
2825                         self.content[-1].fromDom(contents[indx])
2826                     else:
2827                         raise SchemaError, 'Unknown component (%s)'\
2828                             %(contents[indx].getTagName())
2829                     content[-1].fromDom(contents[indx])
2830                     indx += 1
2831                 self.attr_content = tuple(content)
2832
2833
2834 class LocalComplexType(ComplexType,\
2835                        LocalMarker):
2836     """<complexType>
2837        parents:
2838            element
2839        attributes:
2840            id -- ID
2841            mixed -- boolean, false
2842
2843        contents:
2844            annotation?, (simpleContent | complexContent | 
2845            ((group | all | choice | sequence)?, (attribute | attributeGroup)*, anyAttribute?))
2846     """
2847     required = []
2848     attributes = {'id':None, 
2849         'mixed':0}
2850     tag = 'complexType'
2851     
2852
2853 class SimpleType(XMLSchemaComponent,\
2854                  DefinitionMarker,\
2855                  SimpleMarker):
2856     """<simpleType name>
2857        parents:
2858            redefine, schema
2859        attributes:
2860            id -- ID
2861            name -- NCName, required
2862            final -- ('#all' | ('extension' | 'restriction' | 'list' | 'union')*), 
2863                schema.finalDefault 
2864
2865        contents:
2866            annotation?, (restriction | list | union)
2867     """
2868     required = ['name']
2869     attributes = {'id':None,
2870         'name':None,
2871         'final':lambda self: self._parent().getFinalDefault()}
2872     contents = {'xsd':['annotation', 'restriction', 'list', 'union']}
2873     tag = 'simpleType'
2874
2875     def __init__(self, parent):
2876         XMLSchemaComponent.__init__(self, parent)
2877         self.annotation = None
2878         self.content = None
2879
2880     def getElementDeclaration(self, attribute):
2881         raise Warning, 'invalid operation for <%s>' %self.tag
2882
2883     def getTypeDefinition(self, attribute):
2884         raise Warning, 'invalid operation for <%s>' %self.tag
2885
2886     def fromDom(self, node):
2887         self.setAttributes(node)
2888         contents = self.getContents(node)
2889         for child in contents:
2890             component = SplitQName(child.getTagName())[1]
2891             if component == 'annotation':
2892                 self.annotation = Annotation(self)
2893                 self.annotation.fromDom(child)
2894                 continue
2895             break
2896         else:
2897             return
2898         if component == 'restriction':
2899             self.content = self.__class__.Restriction(self)
2900         elif component == 'list':
2901             self.content = self.__class__.List(self)
2902         elif component == 'union':
2903             self.content = self.__class__.Union(self)
2904         else:
2905             raise SchemaError, 'Unknown component (%s)' %(component)
2906         self.content.fromDom(child)
2907
2908     class Restriction(XMLSchemaComponent,\
2909                       RestrictionMarker):
2910         """<restriction base>
2911            parents:
2912                simpleType
2913            attributes:
2914                id -- ID
2915                base -- QName, required or simpleType child
2916
2917            contents:
2918                annotation?, simpleType?, (enumeration | length | 
2919                maxExclusive | maxInclusive | maxLength | minExclusive | 
2920                minInclusive | minLength | pattern | fractionDigits | 
2921                totalDigits | whiteSpace)*
2922         """
2923         attributes = {'id':None, 
2924             'base':None }
2925         contents = {'xsd':['annotation', 'simpleType']+RestrictionMarker.facets}
2926         tag = 'restriction'
2927
2928         def __init__(self, parent):
2929             XMLSchemaComponent.__init__(self, parent)
2930             self.annotation = None
2931             self.content = None
2932             self.facets = None
2933
2934         def getAttributeBase(self):
2935             return XMLSchemaComponent.getAttribute(self, 'base')
2936
2937         def getTypeDefinition(self, attribute='base'):
2938             return XMLSchemaComponent.getTypeDefinition(self, attribute)
2939
2940         def getSimpleTypeContent(self):
2941             for el in self.content:
2942                 if el.isSimple(): return el
2943             return None
2944
2945         def fromDom(self, node):
2946             self.facets = []
2947             self.setAttributes(node)
2948             contents = self.getContents(node)
2949             content = []
2950
2951             for indx in range(len(contents)):
2952                 component = SplitQName(contents[indx].getTagName())[1]
2953                 if (component == 'annotation') and (not indx):
2954                     self.annotation = Annotation(self)
2955                     self.annotation.fromDom(contents[indx])
2956                     continue
2957                 elif (component == 'simpleType') and (not indx or indx == 1):
2958                     content.append(AnonymousSimpleType(self))
2959                     content[-1].fromDom(contents[indx])
2960                 elif component in RestrictionMarker.facets:
2961                     self.facets.append(contents[indx])
2962                 else:
2963                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
2964             self.content = tuple(content)
2965
2966
2967     class Union(XMLSchemaComponent,
2968                 UnionMarker):
2969         """<union>
2970            parents:
2971                simpleType
2972            attributes:
2973                id -- ID
2974                memberTypes -- list of QNames, required or simpleType child.
2975
2976            contents:
2977                annotation?, simpleType*
2978         """
2979         attributes = {'id':None, 
2980             'memberTypes':None }
2981         contents = {'xsd':['annotation', 'simpleType']}
2982         tag = 'union'
2983
2984         def __init__(self, parent):
2985             XMLSchemaComponent.__init__(self, parent)
2986             self.annotation = None
2987             self.content = None
2988
2989         def fromDom(self, node):
2990             self.setAttributes(node)
2991             contents = self.getContents(node)
2992             content = []
2993
2994             for indx in range(len(contents)):
2995                 component = SplitQName(contents[indx].getTagName())[1]
2996                 if (component == 'annotation') and (not indx):
2997                     self.annotation = Annotation(self)
2998                     self.annotation.fromDom(contents[indx])
2999                 elif (component == 'simpleType'):
3000                     content.append(AnonymousSimpleType(self))
3001                     content[-1].fromDom(contents[indx])
3002                 else:
3003                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
3004             self.content = tuple(content)
3005
3006     class List(XMLSchemaComponent, 
3007                ListMarker):
3008         """<list>
3009            parents:
3010                simpleType
3011            attributes:
3012                id -- ID
3013                itemType -- QName, required or simpleType child.
3014
3015            contents:
3016                annotation?, simpleType?
3017         """
3018         attributes = {'id':None, 
3019             'itemType':None }
3020         contents = {'xsd':['annotation', 'simpleType']}
3021         tag = 'list'
3022
3023         def __init__(self, parent):
3024             XMLSchemaComponent.__init__(self, parent)
3025             self.annotation = None
3026             self.content = None
3027
3028         def getItemType(self):
3029             return self.attributes.get('itemType')
3030
3031         def getTypeDefinition(self, attribute='itemType'):
3032             """
3033             return the type refered to by itemType attribute or
3034             the simpleType content.  If returns None, then the 
3035             type refered to by itemType is primitive.
3036             """
3037             tp = XMLSchemaComponent.getTypeDefinition(self, attribute)
3038             return tp or self.content
3039
3040         def fromDom(self, node):
3041             self.annotation = None
3042             self.content = None
3043             self.setAttributes(node)
3044             contents = self.getContents(node)
3045             for indx in range(len(contents)):
3046                 component = SplitQName(contents[indx].getTagName())[1]
3047                 if (component == 'annotation') and (not indx):
3048                     self.annotation = Annotation(self)
3049                     self.annotation.fromDom(contents[indx])
3050                 elif (component == 'simpleType'):
3051                     self.content = AnonymousSimpleType(self)
3052                     self.content.fromDom(contents[indx])
3053                     break
3054                 else:
3055                     raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
3056
3057                  
3058 class AnonymousSimpleType(SimpleType,\
3059                           SimpleMarker,\
3060                           LocalMarker):
3061     """<simpleType>
3062        parents:
3063            attribute, element, list, restriction, union
3064        attributes:
3065            id -- ID
3066
3067        contents:
3068            annotation?, (restriction | list | union)
3069     """
3070     required = []
3071     attributes = {'id':None}
3072     tag = 'simpleType'
3073
3074
3075 class Redefine:
3076     """<redefine>
3077        parents:
3078        attributes:
3079
3080        contents:
3081     """
3082     tag = 'redefine'
3083
3084
3085 ###########################
3086 ###########################
3087
3088
3089 if sys.version_info[:2] >= (2, 2):
3090     tupleClass = tuple
3091 else:
3092     import UserTuple
3093     tupleClass = UserTuple.UserTuple
3094
3095 class TypeDescriptionComponent(tupleClass):
3096     """Tuple of length 2, consisting of
3097        a namespace and unprefixed name.
3098     """
3099     def __init__(self, args):
3100         """args -- (namespace, name)
3101            Remove the name's prefix, irrelevant.
3102         """
3103         if len(args) != 2:
3104             raise TypeError, 'expecting tuple (namespace, name), got %s' %args
3105         elif args[1].find(':') >= 0:
3106             args = (args[0], SplitQName(args[1])[1])
3107         tuple.__init__(self, args)
3108         return
3109
3110     def getTargetNamespace(self):
3111         return self[0]
3112
3113     def getName(self):
3114         return self[1]
3115
3116