--- generateDS.py	2007-10-08 15:57:42.000000000 +0100
+++ generateDS_my.py	2007-10-09 14:43:45.000000000 +0100
@@ -66,7 +66,11 @@
 import urllib2
 from xml.sax import handler, make_parser
 import xml.sax.xmlreader
+import logging
 
+# Default logger configuration
+#logging.basicConfig(level=logging.DEBUG,
+#                    format='%(asctime)s %(levelname)s %(message)s')
 
 ##from IPython.Shell import IPShellEmbed
 ##args = ''
@@ -125,7 +129,7 @@
         ComplexContentType, ExtensionType, \
         IDType, IDREFType, IDREFSType, \
         AnyAttributeType, SimpleTypeType, RestrictionType, \
-        WhiteSpaceType
+        WhiteSpaceType, ListType, EnumerationType, UnionType
     AttributeGroupType = nameSpace + 'attributeGroup'
     AttributeType = nameSpace + 'attribute'
     BooleanType = nameSpace + 'boolean'
@@ -142,8 +146,8 @@
         nameSpace + 'unsignedShort',
         nameSpace + 'short',
         nameSpace + 'long',
-		nameSpace + 'int',
-		nameSpace + 'short',
+        nameSpace + 'int',
+        nameSpace + 'short',
         )
     #ShortType = nameSpace + 'short'
     #LongType = nameSpace + 'long'
@@ -167,6 +171,9 @@
         nameSpace + 'normalizedString',
         )
     TokenType = nameSpace + 'token'
+    ListType = nameSpace + 'list'
+    EnumerationType = nameSpace + 'enumeration'
+    UnionType = nameSpace + 'union'
 
 
 
@@ -206,10 +213,33 @@
         self.name = name
         self.base = None
         self.collapseWhiteSpace = 0
+        # Attribute definitions for the current attributeGroup, if there is one.
+        self.attributeGroup = None
+        # Attribute definitions for the currect element.
+        self.attributeDefs = {}
+        self.complexType = 0
+        # Enumeration values for the current element.
+        self.values = list()
+        # The other simple types this is a union of.
+        self.unionOf = list()
     def setName(self, name): self.name = name
     def getName(self): return self.name
     def setBase(self, base): self.base = base
     def getBase(self): return self.base
+    def setSimpleType(self, simpleType): self.simpleType = simpleType
+    def getSimpleType(self): return self.simpleType
+    def getAttributeGroups(self): return self.attributeGroups
+    def setAttributeGroup(self, attributeGroup): self.attributeGroup = attributeGroup
+    def getAttributeGroup(self): return self.attributeGroup
+    def __str__(self):
+        s1 = '<"%s" SimpleTypeElement instance at 0x%x>' % \
+            (self.getName(), id(self))
+        return s1
+
+    def __repr__(self):
+        s1 = '<"%s" SimpleTypeElement instance at 0x%x>' % \
+            (self.getName(), id(self))
+        return s1
 
 
 class XschemaElement(XschemaElementBase):
@@ -241,6 +271,7 @@
         self.name = name_val
         self.children = []
         self.optional = False
+        self.minOccurs = 1
         self.maxOccurs = 1
         self.complex = 0
         self.complexType = 0
@@ -262,6 +293,10 @@
         self.anyAttribute = 0
         self.explicit_define = 0
         self.simpleType = None
+        # Enumeration values for the current element.
+        self.values = list()
+        # The parent choice for the current element.
+        self.choice = None
 
     def addChild(self, element):
         self.children.append(element)
@@ -272,6 +307,7 @@
     def setName(self, name): self.name = name
     def getAttrs(self): return self.attrs
     def setAttrs(self, attrs): self.attrs = attrs
+    def getMinOccurs(self): return self.minOccurs
     def getMaxOccurs(self): return self.maxOccurs
     def getOptional(self): return self.optional
     def getRawType(self): return self.type
@@ -322,8 +358,8 @@
         showLevel(outfile, level)
         outfile.write('Name: %s  Type: %s\n' % (self.name, self.getType()))
         showLevel(outfile, level)
-        outfile.write('  - Complex: %d  MaxOccurs: %d\n' % \
-            (self.complex, self.maxOccurs))
+        outfile.write('  - Complex: %d  MaxOccurs: %d  MinOccurs: %d\n' % \
+            (self.complex, self.maxOccurs, self.minOccurs))
         showLevel(outfile, level)
         outfile.write('  - Attrs: %s\n' % self.attrs)
         showLevel(outfile, level)
@@ -387,8 +423,44 @@
         type_val = self.resolve_type_1()
         if type_val:
             if type_val in ElementDict:
-                element = ElementDict[type_val]
-                type_val1 = element.resolve_type_1()
+                type_val1 = type_val
+                # The following loop handles the case where an Element's 
+                # reference element has no sub-elements and whose type is
+                # another simpleType (potentially of the same name). Its
+                # fundamental function is to avoid the incorrect 
+                # categorization of "complex" to Elements which are not and 
+                # correctly resolve the Element's type. It also handles cases 
+                # where the Element's "simpleType" is so-called "top level" 
+                # and is only available through the global SimpleTypeDict.
+                i = 0
+                while True:
+                    element = ElementDict[type_val1]
+                    t = element.resolve_type_1()
+                    # If the type is available in the SimpleTypeDict, we
+                    # know we've gone far enough in the Element hierarchy
+                    # and can return the correct base type.
+                    if t in SimpleTypeDict:
+                        type_val1 = SimpleTypeDict[t].getBase()
+                        break
+                    # If the type name is the same as the previous type name
+                    # then we know we've fully resolved the Element hierarchy
+                    # and the Element is well and truely "complex". There is
+                    # also a need to handle cases where the Element name and
+                    # its type name are the same (ie. this is our first time
+                    # through the loop). For example:
+                    #   <xsd:element name="ReallyCool" type="ReallyCool"/>
+                    #   <xsd:simpleType name="ReallyCool">
+                    #     <xsd:restriction base="xsd:string">
+                    #       <xsd:enumeration value="MyThing"/>
+                    #     </xsd:restriction>
+                    #   </xsd:simpleType>
+                    if t == type_val1 and i != 0:
+                        break
+                    if t not in ElementDict:
+                        type_val1 = t
+                        break
+                    type_val1 = t
+                    i += 1
                 if type_val1 in StringType or \
                     type_val1 == TokenType or \
                     type_val1 == DateTimeType or \
@@ -461,25 +533,44 @@
         self.cleanName = mapName(self.unmappedCleanName)
         SaxElementDict[self.cleanName] = self
         self.replace_attributeGroup_names()
+        
+        # Resolve "maxOccurs" attribute
         if 'maxOccurs' in self.attrs.keys():
             maxOccurs = self.attrs['maxOccurs']
-            if maxOccurs == 'unbounded':
-                maxOccurs = 99999
-            else:
-                try:
-                    maxOccurs = int(self.attrs['maxOccurs'])
-                except ValueError:
-                    sys.stderr.write('*** %s  maxOccurs must be integer or "unbounded".' % \
-                        (self.getName(), )
-                        )
-                    sys.exit(-1)
+        elif self.choice and 'maxOccurs' in self.choice.attrs.keys():
+            maxOccurs = self.choice.attrs['maxOccurs']
         else:
             maxOccurs = 1
+            
+        # Resolve "minOccurs" attribute
         if 'minOccurs' in self.attrs.keys():
             minOccurs = self.attrs['minOccurs']
-            if (minOccurs == '0'):
+        elif self.choice and 'minOccurs' in self.choice.attrs.keys():
+            minOccurs = self.choice.attrs['minOccurs']
+        else:
+            minOccurs = 1
+            
+        # Cleanup "minOccurs" and "maxOccurs" attributes
+        try:
+            minOccurs = int(minOccurs)
+            if minOccurs == 0:
                 self.optional = True
+        except ValueError:
+            sys.stderr.write('*** %s  minOccurs must be integer.' % \
+                self.getName())
+            sys.exit(-1)
+        try:
+            if maxOccurs == 'unbounded':
+                maxOccurs = 99999
+            else:
+                maxOccurs = int(maxOccurs)
+        except ValueError:
+            sys.stderr.write('*** %s  maxOccurs must be integer or "unbounded".' % \
+                self.getName())
+            sys.exit(-1)
+        self.minOccurs = minOccurs
         self.maxOccurs = maxOccurs
+        
         # If it does not have a type, then make the type the same as the name.
         if self.type == 'NoneType' and self.name:
             self.type = self.name
@@ -607,6 +698,8 @@
         self.name = name
         self.data_type = data_type
         self.use = use
+        # Enumeration values for the attribute.
+        self.values = list()
     def setName(self, name): self.name = name
     def getName(self): return self.name
     def setData_type(self, data_type): self.data_type = data_type
@@ -632,6 +725,13 @@
         self.inAttribute = 0
         self.inAttributeGroup = 0
         self.inSimpleType = 0
+        # The last attribute we processed.
+        self.lastAttribute = None
+        # Simple types that exist in the global context and may be used to
+        # qualify the type of many elements and/or attributes.
+        self.topLevelSimpleTypes = list()
+        # The current choice type we're in
+        self.currentChoice = None
 ##        self.dbgcount = 1
 ##        self.dbgnames = []
 
@@ -643,6 +743,8 @@
         sys.exit(-1)
 
     def startElement(self, name, attrs):
+        logging.debug("Start element: %s %s" % (name, repr(attrs.items())))
+
         if name == SchemaType:
             self.inSchema = 1
             element = XschemaElement(attrs)
@@ -673,6 +775,8 @@
                 SubstitutionGroups[headName].append(substituteName)
             if name == ComplexTypeType:
                 element.complexType = 1
+            if self.inChoice and self.currentChoice:
+                element.choice = self.currentChoice
             self.stack.append(element)
         elif name == ComplexTypeType:
             # If it have any attributes and there is something on the stack,
@@ -685,6 +789,7 @@
         elif name == SequenceType:
             self.inSequence = 1
         elif name == ChoiceType:
+            self.currentChoice = XschemaElement(attrs)
             self.inChoice = 1
         elif name == AttributeType:
             self.inAttribute = 1
@@ -710,6 +815,7 @@
                 # Add this attribute to the element/complexType.
                 attribute = XschemaAttribute(name, data_type, use)
                 self.stack[-1].attributeDefs[name] = attribute
+            self.lastAttribute = attribute
         elif name == AttributeGroupType:
             self.inAttributeGroup = 1
             # If it has attribute 'name', then it's a definition.
@@ -770,17 +876,57 @@
             if self.inSimpleType and 'base' in attrs.keys():
                 self.stack[-1].setBase(attrs['base'])
             self.inRestrictionType = 1
+        elif name == EnumerationType:
+            if self.inAttribute and attrs.has_key('value'):
+                # We know that the restriction is on an attribute and the
+                # attributes of the current element are un-ordered so the
+                # instance variable "lastAttribute" will have our attribute.
+                self.lastAttribute.values.append(attrs['value'])
+            elif self.inElement and attrs.has_key('value'):
+                # We're not in an attribute so the restriction must have
+                # been placed on an element and that element will still be
+                # in the stack. We search backwards through the stack to
+                # find the last element.
+                element = None
+                for entry in list(stack).reverse():
+                    if type(entry) == XschemaElement:
+                        element = entry
+                if element is None:
+                    sys.stderr.write(
+                        'Cannot find element to attach enumeration: %s' % \
+                            value)
+                    sys.exit(-1)
+                element.values.append(attrs['value'])
+            elif self.inSimpleType and attrs.has_key('value'):
+                # We've been defined as a simpleType on our own.
+                self.stack[-1].values.append(attrs['value'])
+        elif name == UnionType:
+            # Union types are only used with a parent simpleType and we want
+            # the parent to know what it's a union of.
+            if attrs.has_key('memberTypes'):
+                for member in attrs['memberTypes'].split(" "):
+                    self.stack[-1].unionOf.append(member)
         elif name == WhiteSpaceType and self.inRestrictionType:
             if attrs.has_key('value'):
                 if attrs.getValue('value') == 'collapse':
                     self.stack[-1].collapseWhiteSpace = 1
+        elif name == ListType:
+            self.inListType = 1
             #ipshell('Parsing simpleType -- Entering ipshell.\nHit Ctrl-D to exit')
             #import pdb; pdb.set_trace()
+        logging.debug("Start element stack: %d" % len(self.stack))
 
     def endElement(self, name):
+        logging.debug("End element: %s" % (name))
+        logging.debug("End element stack: %d" % (len(self.stack)))
         if name == SimpleTypeType and self.inSimpleType:
             self.inSimpleType = 0
-            self.stack.pop()
+            # If the simpleType is directly off the root, it may be used to 
+            # qualify the type of many elements and/or attributes so we 
+            # don't want to loose it entirely.
+            simpleType = self.stack.pop()
+            if len(self.stack) == 1:
+                self.topLevelSimpleTypes.append(simpleType)
         elif name == RestrictionType and self.inRestrictionType:
             self.inRestrictionType = 0
         elif name == ElementType or (name == ComplexTypeType and self.stack[-1].complexType):
@@ -793,6 +939,7 @@
         elif name == SequenceType:
             self.inSequence = 0
         elif name == ChoiceType:
+            self.currentChoice = None
             self.inChoice = 0
         elif name == AttributeType:
             self.inAttribute = 0
@@ -818,11 +965,20 @@
             if len(self.stack) != 1:
                 print '*** error stack.  len(self.stack): %d' % len(self.stack)
                 sys.exit(-1)
+            logging.debug("Previous root:", self.root)
             self.root = self.stack[0]
+            logging.debug("New root:", self.root)
         elif name == ComplexContentType:
             pass
         elif name == ExtensionType:
             pass
+        elif name == ListType:
+            # List types are only used with a parent simpleType and can have a
+            # simpleType child. So, if we're in a list type we have to be
+            # careful to reset the inSimpleType flag otherwise the handler's
+            # internal stack will not be unrolled correctly.
+            self.inSimpleType = 1
+            self.inListType = 0
 
     def characters(self, chrs):
         if self.inElement:
@@ -890,8 +1046,7 @@
 def generateExportFn_2(outfile, child, name, fill):
     cleanName = cleanupName(name)
     mappedName = mapName(cleanName)
-    s1 = "%s    for %s_ in self.get%s():\n" % (
-        fill, cleanName, make_gs_name(cleanName))
+    s1 = "%s    for %s_ in self.get%s():\n" % (fill, cleanName, make_gs_name(cleanName))
     outfile.write(s1)
     if child.getType() in StringType or \
         child.getType() == TokenType or \
@@ -984,7 +1139,7 @@
             s1 = "%s                self.%s.export(outfile, level, name_='%s')\n" % \
                 (fill, mappedName, name)
         outfile.write(s1)
-		
+
 
 def generateExportAttributes(outfile, element, hasAttributes):
     if len(element.getAttributeDefs()) > 0:
@@ -1027,10 +1182,10 @@
                 if child.getMaxOccurs() > 1:
                     generateExportFn_2(outfile, child, name, '    ')
                 else:
-					if (child.getOptional()):
-						generateExportFn_3(outfile, child, name, '')
-					else:
-						generateExportFn_1(outfile, child, name, '')
+                    if (child.getOptional()):
+                        generateExportFn_3(outfile, child, name, '')
+                    else:
+                        generateExportFn_1(outfile, child, name, '')
 ##    base = element.getBase()
 ##    if base and base in ElementDict:
 ##        parent = ElementDict[base]
@@ -2025,6 +2180,7 @@
         attrDef = attrDefs[key]
         mappedName = cleanupName(attrDef.getName())
         mappedName = mapName(mappedName)
+        logging.debug("Constructor attribute: %s" % mappedName)
         s1 = '        self.%s = %s\n' % (mappedName, mappedName)
         outfile.write(s1)
         member = 1
@@ -2036,6 +2192,8 @@
         nestedElements = 0
         for child in element.getChildren():
             name = cleanupName(child.getCleanName())
+            logging.debug("Constructor child: %s" % name)
+            logging.debug("Dump: %s" % child.__dict__)
             if child.getMaxOccurs() > 1:
                 s1 = '        if %s is None:\n' % (name, )
                 outfile.write(s1)
@@ -2225,11 +2383,14 @@
 
 
 def generateClasses(outfile, prefix, element, delayed):
+    logging.debug("Generating class for: %s" % element)
     base = element.getBase()
+    logging.debug("Element base: %s" % base)
     wrt = outfile.write
 ##    if (not element.getChildren()) and (not element.getAttributeDefs()):
 ##        return
     if not element.isExplicitDefine():
+        logging.debug("Not an explicit define, returning.")
         return
     # If this element is an extension (has a base) and the base has
     #   not been generated, then postpone it.
