xmlclass/xmlclass.py
changeset 592 89ff2738ef20
parent 565 94c11207aa6f
child 593 34c3569042db
--- a/xmlclass/xmlclass.py	Fri Nov 18 17:40:40 2011 +0100
+++ b/xmlclass/xmlclass.py	Wed Nov 23 00:19:27 2011 +0100
@@ -22,7 +22,7 @@
 #License along with this library; if not, write to the Free Software
 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
-import sys
+import os, sys
 import re
 import datetime
 from types import *
@@ -92,8 +92,8 @@
         return ZERO
 
 [SYNTAXELEMENT, SYNTAXATTRIBUTE, SIMPLETYPE, COMPLEXTYPE, COMPILEDCOMPLEXTYPE, 
- ATTRIBUTESGROUP, ELEMENTSGROUP, ATTRIBUTE, ELEMENT, CHOICE, ANY, TAG
-] = range(12)
+ ATTRIBUTESGROUP, ELEMENTSGROUP, ATTRIBUTE, ELEMENT, CHOICE, ANY, TAG, CONSTRAINT,
+] = range(13)
 
 def NotSupportedYet(type):
     """
@@ -126,13 +126,13 @@
     if not extract:
         return attr
     if len(attr.childNodes) == 1:
-        return unescape(attr.childNodes[0].data.encode())
+        return unescape(attr.childNodes[0].data.encode("utf-8"))
     else:
         # content is a CDATA
         text = ""
         for node in attr.childNodes:
             if node.nodeName != "#text":
-                text += node.data.encode()
+                text += node.data.encode("utf-8")
         return text
 
 
@@ -532,23 +532,29 @@
         return values
     return GetModelNameList
 
-def GenerateAnyInfos():
+def GenerateAnyInfos(infos):
     def ExtractAny(tree):
-        return tree.data.encode("utf-8")
+        if tree.nodeName == "#cdata-section":
+            return tree.data.encode("utf-8")
+        else:
+            return tree
     
     def GenerateAny(value, name=None, indent=0):
-        try:
-            value = value.decode("utf-8")
-        except:
-            pass
-        return u'<![CDATA[%s]]>\n' % value
+        if isinstance(value, (StringType, UnicodeType)):
+            try:
+                value = value.decode("utf-8")
+            except:
+                pass
+            return u'<![CDATA[%s]]>\n' % value
+        else:
+            return value.toprettyxml(indent=" "*indent, encoding="utf-8")
         
     return {
         "type": COMPLEXTYPE, 
         "extract": ExtractAny,
         "generate": GenerateAny,
         "initial": lambda: "",
-        "check": lambda x: isinstance(x, (StringType, UnicodeType))
+        "check": lambda x: isinstance(x, (StringType, UnicodeType, minidom.Node))
     }
 
 def GenerateTagInfos(name):
@@ -573,80 +579,239 @@
         "initial": lambda: None,
         "check": lambda x: x == None
     }
+
+def FindTypeInfos(factory, infos):
+    if isinstance(infos, (UnicodeType, StringType)):
+        namespace, name = DecomposeQualifiedName(infos)
+        return factory.GetQualifiedNameInfos(name, namespace)
+    return infos
     
-def GenerateContentInfos(factory, choices):
+def GetElementInitialValue(factory, infos):
+    infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
+    if infos["minOccurs"] == 0 and infos["maxOccurs"] == 1:
+        if infos.has_key("default"):
+            return infos["elmt_type"]["extract"](infos["default"], False)
+        else:
+            return None
+    elif infos["minOccurs"] == 1 and infos["maxOccurs"] == 1:
+        return infos["elmt_type"]["initial"]()
+    else:
+        return [infos["elmt_type"]["initial"]() for i in xrange(infos["minOccurs"])]
+
+def HandleError(message, raise_exception):
+    if raise_exception:
+        raise ValueError(message)
+    return False
+
+def CheckElementValue(factory, name, infos, value, raise_exception=True):
+    infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
+    if value is None and raise_exception:
+        if not (infos["minOccurs"] == 0 and infos["maxOccurs"] == 1):
+            return HandleError("Attribute '%s' isn't optional." % name, raise_exception)
+    elif infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1:
+        if not isinstance(value, ListType):
+            return HandleError("Attribute '%s' must be a list." % name, raise_exception)
+        if len(value) < infos["minOccurs"] or infos["maxOccurs"] != "unbounded" and len(value) > infos["maxOccurs"]:
+            return HandleError("List out of bounds for attribute '%s'." % name, raise_exception)
+        if not reduce(lambda x, y: x and y, map(infos["elmt_type"]["check"], value), True):
+            return HandleError("Attribute '%s' must be a list of valid elements." % name, raise_exception)
+    elif infos.has_key("fixed") and value != infos["fixed"]:
+        return HandleError("Value of attribute '%s' can only be '%s'." % (name, str(infos["fixed"])), raise_exception)
+    else:
+        return infos["elmt_type"]["check"](value)
+    return True
+
+def GetContentInfos(name, choices):
+    for choice_infos in choices:
+        if choices_infos["type"] == "sequence":
+            for element_infos in choices_infos["elements"]:
+                if element_infos["type"] == CHOICE:
+                    if GetContentInfos(name, element_infos["choices"]):
+                        return choices_infos
+                elif element_infos["name"] == name:
+                    return choices_infos
+        elif choice_infos["name"] == name:
+            return choices_infos
+    return None
+
+def ComputeContentChoices(factory, name, infos):
+    choices = []
+    for choice in infos["choices"]:
+        if choice["type"] == "sequence":
+            choice["name"] = "sequence"
+            for sequence_element in choice["elements"]:
+                if sequence_element["type"] != CHOICE:
+                    element_infos = factory.ExtractTypeInfos(sequence_element["name"], name, sequence_element["elmt_type"])
+                    if element_infos is not None:
+                        sequence_element["elmt_type"] = element_infos
+        elif choice["elmt_type"] == "tag":
+            choice["elmt_type"] = GenerateTagInfos(choice["name"])
+        else:
+            choice_infos = factory.ExtractTypeInfos(choice["name"], name, choice["elmt_type"])
+            if choice_infos is not None:
+                choice["elmt_type"] = choice_infos
+        choices.append((choice["name"], choice))
+    return choices
+
+def ExtractContentElement(factory, tree, infos, content):
+    infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
+    if infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1:
+        if isinstance(content, ListType) and len(content) > 0 and \
+           content[-1]["name"] == tree.nodeName:
+            content_item = content.pop(-1)
+            content_item["value"].append(infos["elmt_type"]["extract"](tree))
+            return content_item
+        elif not isinstance(content, ListType) and \
+             content is not None and \
+             content["name"] == tree.nodeName:
+            return {"name": tree.nodeName, 
+                    "value": content["value"] + [infos["elmt_type"]["extract"](tree)]}
+        else:
+            return {"name": tree.nodeName, 
+                    "value": [infos["elmt_type"]["extract"](tree)]}
+    else:
+        return {"name": tree.nodeName, 
+                "value": infos["elmt_type"]["extract"](tree)}
+
+def GenerateContentInfos(factory, name, choices):
+    choices_dict = {}
+    for choice_name, infos in choices:
+        if choice_name == "sequence":
+            for element in infos["elements"]:
+                if element["type"] == CHOICE:
+                    element["elmt_type"] = GenerateContentInfos(factory, name, ComputeContentChoices(factory, name, element))
+                elif choices_dict.has_key(element["name"]):
+                    raise ValueError("'%s' element defined two times in choice" % choice_name)
+                else:
+                    choices_dict[element["name"]] = infos
+        else:
+            if choices_dict.has_key(choice_name):
+                raise ValueError("'%s' element defined two times in choice" % choice_name)
+            choices_dict[choice_name] = infos
+    
     def GetContentInitial():
         content_name, infos = choices[0]
-        if isinstance(infos["elmt_type"], (UnicodeType, StringType)):
-            namespace, name = DecomposeQualifiedName(infos["elmt_type"])
-            infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
-        if infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1:
-            return {"name": content_name, 
-                    "value": map(infos["elmt_type"]["initial"], 
-                                 range(infos["minOccurs"]))}
-        else:
-            return {"name": content_name, 
-                    "value": infos["elmt_type"]["initial"]()}
+        if content_name == "sequence":
+            content_value = []
+            for i in xrange(infos["minOccurs"]):
+                for element_infos in infos["elements"]:
+                    value = GetElementInitialValue(factory, element_infos)
+                    if value is not None:
+                        if element_infos["type"] == CHOICE:
+                            content_value.append(value)
+                        else:
+                            content_value.append({"name": element_infos["name"], "value": value})
+        else:
+            content_value = GetElementInitialValue(factory, infos)
+        return {"name": content_name, "value": content_value}
+        
+    def CheckContent(value):
+        if value["name"] != "sequence":
+            infos = choices_dict.get(value["name"], None)
+            if infos is not None:
+                return CheckElementValue(factory, value["name"], infos, value["value"], False)
+        elif len(value["value"]) > 0:
+            infos = choices_dict.get(value["value"][0]["name"], None)
+            if infos is None:
+                for choice_name, infos in choices:
+                    if infos["type"] == "sequence":
+                        for element_infos in infos["elements"]:
+                            if element_infos["type"] == CHOICE:
+                                infos = GetContentInfos(value["value"][0]["name"], element_infos["choices"])
+            if infos is not None:
+                sequence_number = 0
+                element_idx = 0
+                while element_idx < len(value["value"]):
+                    for element_infos in infos["elements"]:
+                        if element_infos["name"] == value["value"][element_idx]["name"]:
+                            element_value = value["value"][element_idx]["value"]
+                            element_idx += 1
+                        else:
+                            element_value = None
+                        if not CheckElementValue(factory, element_infos["name"], element_infos, element_value, False):
+                            raise ValueError("Invalid sequence value in attribute 'content'")
+                    sequence_number += 1
+                if sequence_number < infos["minOccurs"] or infos["maxOccurs"] != "unbounded" and sequence_number > infos["maxOccurs"]:
+                    raise ValueError("Invalid sequence value in attribute 'content'")
+                return True
+        else:
+            for element_name, infos in choices:
+                if element_name == "sequence":
+                    required = 0
+                    for element in infos["elements"]:
+                        if element["minOccurs"] > 0:
+                            required += 1
+                    if required == 0:
+                        return True
+        return False
     
-    def CheckContent(value):
-        for content_name, infos in choices:
-            if content_name == value["name"]:
-                if isinstance(infos["elmt_type"], (UnicodeType, StringType)):
-                    namespace, name = DecomposeQualifiedName(infos["elmt_type"])
-                    infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
-                if infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1:
-                    if isinstance(value["value"], ListType) and \
-                       infos["minOccurs"] <= len(value["value"]) <= infos["maxOccurs"]:
-                        return reduce(lambda x, y: x and y, 
-                                      map(infos["elmt_type"]["check"], 
-                                          value["value"]), 
-                                      True)
-                else:
-                    return infos["elmt_type"]["check"](value["value"])
-        return False
-        
     def ExtractContent(tree, content):
-        for content_name, infos in choices:
-            if content_name == tree.nodeName:
-                if isinstance(infos["elmt_type"], (UnicodeType, StringType)):
-                    namespace, name = DecomposeQualifiedName(infos["elmt_type"])
-                    infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
-                if infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1:
-                    if isinstance(content, ListType) and len(content) > 0 and \
-                       content[-1]["name"] == content_name:
-                        content_item = content.pop(-1)
-                        content_item["value"].append(infos["elmt_type"]["extract"](tree))
-                        return content_item
-                    elif not isinstance(content, ListType) and \
-                         content is not None and \
-                         content["name"] == content_name:
-                        return {"name": content_name, 
-                                "value": content["value"] + \
-                                         [infos["elmt_type"]["extract"](tree)]}
-                    else:
-                        return {"name": content_name, 
-                                "value": [infos["elmt_type"]["extract"](tree)]}
-                else:
-                    return {"name": content_name, 
-                            "value": infos["elmt_type"]["extract"](tree)}
+        infos = choices_dict.get(tree.nodeName, None)
+        if infos is not None:
+            if infos["name"] == "sequence":
+                sequence_dict = dict([(element_infos["name"], element_infos) for element_infos in infos["elements"] if element_infos["type"] != CHOICE])
+                element_infos = sequence_dict.get(tree.nodeName)
+                if content is not None and \
+                   content["name"] == "sequence" and \
+                   len(content["value"]) > 0 and \
+                   choices_dict.get(content["value"][-1]["name"]) == infos:
+                    return {"name": "sequence",
+                            "value": content["value"] + [ExtractContentElement(factory, tree, element_infos, content["value"][-1])]}
+                else:
+                    return {"name": "sequence",
+                            "value": [ExtractContentElement(factory, tree, element_infos, None)]}
+            else:
+                return ExtractContentElement(factory, tree, infos, content)
+        else:
+            for choice_name, infos in choices:
+                if infos["type"] == "sequence":
+                    for element_infos in infos["elements"]:
+                        if element_infos["type"] == CHOICE:
+                            try:
+                                if content is not None and \
+                                    content["name"] == "sequence" and \
+                                    len(content["value"]) > 0:
+                                    return {"name": "sequence",
+                                            "value": content["value"] + [element_infos["elmt_type"]["extract"](tree, content["value"][-1])]}
+                                else:
+                                    return {"name": "sequence",
+                                            "value": [element_infos["elmt_type"]["extract"](tree, None)]}
+                            except:
+                                pass
         raise ValueError("Invalid element \"%s\" for content!" % tree.nodeName)
     
     def GenerateContent(value, name=None, indent=0):
-        for content_name, infos in choices:
-            if content_name == value["name"]:
-                if isinstance(infos["elmt_type"], (UnicodeType, StringType)):
-                    namespace, name = DecomposeQualifiedName(infos["elmt_type"])
-                    infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
+        text = ""
+        if value["name"] != "sequence":
+            infos = choices_dict.get(value["name"], None)
+            if infos is not None:
+                infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
                 if infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1:
-                    text = ""
                     for item in value["value"]:
-                        text += infos["elmt_type"]["generate"](item, content_name, indent)
-                    return text
-                else:
-                    return infos["elmt_type"]["generate"](value["value"], content_name, indent)
-        return ""
+                        text += infos["elmt_type"]["generate"](item, value["name"], indent)
+                else:
+                    text += infos["elmt_type"]["generate"](value["value"], value["name"], indent)
+        elif len(value["value"]) > 0:
+            infos = choices_dict.get(value["value"][0]["name"], None)
+            if infos is None:
+                for choice_name, infos in choices:
+                    if infos["type"] == "sequence":
+                        for element_infos in infos["elements"]:
+                            if element_infos["type"] == CHOICE:
+                                infos = GetContentInfos(value["value"][0]["name"], element_infos["choices"])
+            if infos is not None:
+                sequence_dict = dict([(element_infos["name"], element_infos) for element_infos in infos["elements"]]) 
+                for element_value in value["value"]:
+                    element_infos = sequence_dict.get(element_value["name"])
+                    if element_infos["maxOccurs"] == "unbounded" or element_infos["maxOccurs"] > 1:
+                        for item in element_value["value"]:
+                            text += element_infos["elmt_type"]["generate"](item, element_value["name"], indent)
+                    else:
+                        text += element_infos["elmt_type"]["generate"](element_value["value"], element_infos["name"], indent)
+        return text
         
     return {
+        "type": COMPLEXTYPE,
         "initial": GetContentInitial,
         "check": CheckContent,
         "extract": ExtractContent,
@@ -707,8 +872,12 @@
 """
 class ClassFactory:
 
-    def __init__(self, document, debug=False):
+    def __init__(self, document, filepath=None, debug=False):
         self.Document = document
+        if filepath is not None:
+            self.BaseFolder, self.FileName = os.path.split(filepath)
+        else:
+            self.BaseFolder = self.FileName = None
         self.Debug = debug
         
         # Dictionary for stocking Classes and Types definitions created from
@@ -724,7 +893,10 @@
         
         # Dictionaries for stocking Classes and Types generated
         self.ComputeAfter = []
-        self.ComputedClasses = {}
+        if self.FileName is not None:
+            self.ComputedClasses = {self.FileName: {}}
+        else:
+            self.ComputedClasses = {}
         self.ComputedClassesInfos = {}
         self.AlreadyComputed = {}
 
@@ -732,7 +904,7 @@
         if namespace is None:
             if self.Namespaces[self.SchemaNamespace].has_key(name):
                 return self.Namespaces[self.SchemaNamespace][name]
-            for space, elements in self.Namespaces.items():
+            for space, elements in self.Namespaces.iteritems():
                 if space != self.SchemaNamespace and elements.has_key(name):
                     return elements[name]
             parts = name.split("_", 1)
@@ -846,15 +1018,18 @@
     def ReduceElements(self, elements, schema=False):
         result = []
         for child_infos in elements:
-            if child_infos[1].has_key("name") and schema:
-                self.CurrentCompilations.append(child_infos[1]["name"])
-            namespace, name = DecomposeQualifiedName(child_infos[0])
-            infos = self.GetQualifiedNameInfos(name, namespace)
-            if infos["type"] != SYNTAXELEMENT:
-                raise ValueError("\"%s\" can't be a member child!" % name)
-            result.append(infos["reduce"](self, child_infos[1], child_infos[2]))
-            if child_infos[1].has_key("name") and schema:
-                self.CurrentCompilations.pop(-1)
+            if child_infos is not None:
+                if child_infos[1].has_key("name") and schema:
+                    self.CurrentCompilations.append(child_infos[1]["name"])
+                namespace, name = DecomposeQualifiedName(child_infos[0])
+                infos = self.GetQualifiedNameInfos(name, namespace)
+                if infos["type"] != SYNTAXELEMENT:
+                    raise ValueError("\"%s\" can't be a member child!" % name)
+                element = infos["reduce"](self, child_infos[1], child_infos[2])
+                if element is not None:
+                    result.append(element)
+                if child_infos[1].has_key("name") and schema:
+                    self.CurrentCompilations.pop(-1)
         annotations = []
         children = []
         for element in result:
@@ -948,10 +1123,11 @@
         
         # If base classes haven't been generated
         bases = []
-        if classinfos.has_key("base"):
-            result = self.ExtractTypeInfos("base", name, classinfos["base"])
+        base_infos = classinfos.get("base", None)
+        if base_infos is not None:
+            result = self.ExtractTypeInfos("base", name, base_infos)
             if result is None:
-                namespace, base_name = DecomposeQualifiedName(classinfos["base"])                
+                namespace, base_name = DecomposeQualifiedName(base_infos)                
                 if self.AlreadyComputed.get(base_name, False):
                     self.ComputeAfter.append((name, parent, classinfos))
                     if self.TargetNamespace is not None:
@@ -959,8 +1135,19 @@
                     else:
                         return classname
             elif result is not None:
-                classinfos["base"] = self.ComputedClasses[result["name"]]
-                bases.append(self.ComputedClasses[result["name"]])
+                if self.FileName is not None:
+                    classinfos["base"] = self.ComputedClasses[self.FileName].get(result["name"], None)
+                    if classinfos["base"] is None:
+                        for filename, classes in self.ComputedClasses.iteritems():
+                            if filename != self.FileName:
+                                classinfos["base"] = classes.get(result["name"], None)
+                                if classinfos["base"] is not None:
+                                    break
+                else:
+                    classinfos["base"] = self.ComputedClasses.get(result["name"], None)
+                if classinfos["base"] is None:
+                    raise ValueError("No class found for base type")
+                bases.append(classinfos["base"])
         bases.append(object)
         bases = tuple(bases)
         classmembers = {"__doc__": classinfos.get("doc", ""), "IsBaseClass": baseclass}
@@ -984,30 +1171,22 @@
             else:
                 raise ValueError("\"%s\" type unrecognized!" % attribute["attr_type"])
             attribute["attr_type"] = infos
-            
+        
         for element in classinfos["elements"]:
             if element["type"] == CHOICE:
                 elmtname = element["name"]
-                choices = []
-                for choice in element["choices"]:
-                    if choice["elmt_type"] == "tag":
-                        choice["elmt_type"] = GenerateTagInfos(choice["name"])
-                    else:
-                        infos = self.ExtractTypeInfos(choice["name"], name, choice["elmt_type"])
-                        if infos is not None:
-                            choice["elmt_type"] = infos
-                    choices.append((choice["name"], choice))
+                choices = ComputeContentChoices(self, name, element)
                 classmembers["get%schoices"%elmtname] = generateGetChoicesMethod(element["choices"])
                 if element["maxOccurs"] == "unbounded" or element["maxOccurs"] > 1:
                     classmembers["append%sbytype" % elmtname] = generateAppendChoiceByTypeMethod(element["maxOccurs"], self, element["choices"])
                     classmembers["insert%sbytype" % elmtname] = generateInsertChoiceByTypeMethod(element["maxOccurs"], self, element["choices"])
                 else:
                     classmembers["set%sbytype" % elmtname] = generateSetChoiceByTypeMethod(self, element["choices"])
-                infos = GenerateContentInfos(self, choices)
+                infos = GenerateContentInfos(self, name, choices)
             elif element["type"] == ANY:
                 elmtname = element["name"] = "text"
                 element["minOccurs"] = element["maxOccurs"] = 1
-                infos = GenerateAnyInfos()
+                infos = GenerateAnyInfos(element)
             else:
                 elmtname = element["name"]
                 infos = self.ExtractTypeInfos(element["name"], name, element["elmt_type"])
@@ -1050,7 +1229,10 @@
                 "extract": generateClassExtractFunction(class_definition),
                 "generate": class_definition.generateXMLText}
         
-        self.ComputedClasses[classname] = class_definition
+        if self.FileName is not None:
+            self.ComputedClasses[self.FileName][classname] = class_definition
+        else:
+            self.ComputedClasses[classname] = class_definition
         self.ComputedClassesInfos[classname] = class_infos
         
         return class_infos
@@ -1061,8 +1243,16 @@
     def PrintClasses(self):
         items = self.ComputedClasses.items()
         items.sort()
-        for classname, xmlclass in items:
-            print "%s : %s" % (classname, str(xmlclass))
+        if self.FileName is not None:
+            for filename, classes in items:
+                print "File '%s':" % filename
+                class_items = classes.items()
+                class_items.sort()
+                for classname, xmlclass in class_items:
+                    print "%s: %s" % (classname, str(xmlclass))
+        else:
+            for classname, xmlclass in items:
+                print "%s: %s" % (classname, str(xmlclass))
         
     def PrintClassNames(self):
         classnames = self.XMLClassDefinitions.keys()
@@ -1107,9 +1297,7 @@
     
     def setattrMethod(self, name, value):
         if attributes.has_key(name):
-            if isinstance(attributes[name]["attr_type"], (UnicodeType, StringType)):
-                namespace, name = DecomposeQualifiedName(infos)
-                attributes[name]["attr_type"] = factory.GetQualifiedNameInfos(name, namespace)
+            attributes[name]["attr_type"] = FindTypeInfos(factory, attributes[name]["attr_type"])
             if value is None:
                 if optional_attributes.get(name, False):
                     return object.__setattr__(self, name, None)
@@ -1122,22 +1310,7 @@
             else:
                 raise ValueError("Invalid value for attribute '%s'." % (name))
         elif elements.has_key(name):
-            if isinstance(elements[name]["elmt_type"], (UnicodeType, StringType)):
-                namespace, name = DecomposeQualifiedName(infos)
-                elements[name]["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
-            if value is None:
-                if elements[name]["minOccurs"] == 0 and elements[name]["maxOccurs"] == 1:
-                    return object.__setattr__(self, name, None)
-                else:
-                    raise ValueError("Attribute '%s' isn't optional." % name)
-            elif elements[name]["maxOccurs"] == "unbounded" or elements[name]["maxOccurs"] > 1:
-                if isinstance(value, ListType) and elements[name]["minOccurs"] <= len(value) <= elements[name]["maxOccurs"]:
-                    if reduce(lambda x, y: x and y, map(elements[name]["elmt_type"]["check"], value), True):
-                        return object.__setattr__(self, name, value)
-                raise ValueError, "Attribute '%s' must be a list of valid elements."%name
-            elif elements[name].has_key("fixed") and value != elements[name]["fixed"]:
-                raise ValueError("Value of attribute '%s' can only be '%s'." % (name, str(elements[name]["fixed"])))
-            elif elements[name]["elmt_type"]["check"](value):
+            if CheckElementValue(factory, name, elements[name], value):
                 return object.__setattr__(self, name, value)
             else:
                 raise ValueError("Invalid value for attribute '%s'." % (name))
@@ -1166,7 +1339,7 @@
         if infos["maxOccurs"] == "unbounded":
             return "(?:%s)+" % name
         elif infos["maxOccurs"] == 1:
-            return name
+            return "(?:%s)" % name
         else:
             return "(?:%s){1,%d}" % (name, infos["maxOccurs"])
     else:
@@ -1176,23 +1349,32 @@
             return "(?:%s){%d,%d}" % (name, infos["minOccurs"], 
                                        infos["maxOccurs"])
 
-def generateStructureMethod(classinfos):
+def GetStructure(classinfos):
     elements = []
     for element in classinfos["elements"]:
         if element["type"] == ANY:
-            elements.append(ComputeMultiplicity("(?:#cdata-section )?", element))
+            elements.append(ComputeMultiplicity("#cdata-section |\w* ", element))
         elif element["type"] == CHOICE:
-            elements.append(ComputeMultiplicity(
-                "|".join([ComputeMultiplicity("%s " % infos["name"], infos) for infos in element["choices"]]), 
-                element))
+            choices = []
+            for infos in element["choices"]:
+                if infos["type"] == "sequence":
+                    structure = "(?:%s)" % GetStructure(infos)
+                else:
+                    structure = "%s " % infos["name"]
+                choices.append(ComputeMultiplicity(structure, infos))
+            elements.append(ComputeMultiplicity("|".join(choices), element))
+        elif element["name"] == "content" and element["elmt_type"]["type"] == SIMPLETYPE:
+            elements.append("(?:#cdata-section )?")
         else:
             elements.append(ComputeMultiplicity("%s " % element["name"], element))
     if classinfos.get("order", True) or len(elements) == 0:
-        structure = "".join(elements)
+        return "".join(elements)
     else:
         raise ValueError("XSD structure not yet supported!")
-    
+
+def generateStructureMethod(classinfos):
     def getStructureMethod(self):
+        structure = GetStructure(classinfos)
         if classinfos.has_key("base"):
             return classinfos["base"].getStructure(self) + structure
         return structure
@@ -1213,20 +1395,20 @@
             for node in tree.childNodes:
                 if node.nodeName not in ["#comment", "#text"]:
                     children_structure += "%s " % node.nodeName
-            structure_model = re.compile("(%s)$" % self.getStructure())
-            result = structure_model.match(children_structure)
-            if not result:
-                raise ValueError("Invalid structure for \"%s\" children!." % tree.nodeName)
+            structure_pattern = self.getStructure()
+            if structure_pattern != "":
+                structure_model = re.compile("(%s)$" % structure_pattern)
+                result = structure_model.match(children_structure)
+                if not result:
+                    raise ValueError("Invalid structure for \"%s\" children!." % tree.nodeName)
         required_attributes = dict([(attr["name"], True) for attr in classinfos["attributes"] if attr["use"] == "required"])
         if classinfos.has_key("base"):
             extras.extend([attr["name"] for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
             classinfos["base"].loadXMLTree(self, tree, extras, True)
         for attrname, attr in tree._attrs.iteritems():
             if attributes.has_key(attrname):
-                if isinstance(attributes[attrname]["attr_type"], (UnicodeType, StringType)):
-                    namespace, name = DecomposeQualifiedName(infos)
-                    attributes[attrname]["attr_type"] = factory.GetQualifiedNameInfos(name, namespace)
-                setattr(self, attrname, attributes[attrname]["attr_type"]["extract"](attr))
+                attributes[attrname]["attr_type"] = FindTypeInfos(factory, attributes[attrname]["attr_type"])
+                object.__setattr__(self, attrname, attributes[attrname]["attr_type"]["extract"](attr))
             elif not classinfos.has_key("base") and attrname not in extras:
                 raise ValueError("Invalid attribute \"%s\" for \"%s\" element!" % (attrname, tree.nodeName))
             required_attributes.pop(attrname, None)
@@ -1237,37 +1419,39 @@
             name = node.nodeName
             if name in ["#text", "#comment"]:
                 continue
-            if elements.has_key(name):
-                if isinstance(elements[name]["elmt_type"], (UnicodeType, StringType)):
-                    namespace, name = DecomposeQualifiedName(infos)
-                    elements[name]["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
+            elif elements.has_key(name):
+                elements[name]["elmt_type"] = FindTypeInfos(factory, elements[name]["elmt_type"])
                 if elements[name]["maxOccurs"] == "unbounded" or elements[name]["maxOccurs"] > 1:
                     if first.get(name, True):
-                        setattr(self, name, [elements[name]["elmt_type"]["extract"](node)])
+                        object.__setattr__(self, name, [elements[name]["elmt_type"]["extract"](node)])
                         first[name] = False
                     else:
                         getattr(self, name).append(elements[name]["elmt_type"]["extract"](node))
                 else:
-                    setattr(self, name, elements[name]["elmt_type"]["extract"](node))
-            elif name == "#cdata-section" and elements.has_key("text"):
+                    object.__setattr__(self, name, elements[name]["elmt_type"]["extract"](node))
+            elif elements.has_key("text"):
                 if elements["text"]["maxOccurs"] == "unbounded" or elements["text"]["maxOccurs"] > 1:
                     if first.get("text", True):
-                        setattr(self, "text", [elements["text"]["elmt_type"]["extract"](node)])
+                        object.__setattr__(self, "text", [elements["text"]["elmt_type"]["extract"](node)])
                         first["text"] = False
                     else:
                         getattr(self, "text").append(elements["text"]["elmt_type"]["extract"](node))
                 else:
-                    setattr(self, "text", elements["text"]["elmt_type"]["extract"](node))
+                    object.__setattr__(self, "text", elements["text"]["elmt_type"]["extract"](node))
             elif elements.has_key("content"):
-                content = getattr(self, "content")
-                if elements["content"]["maxOccurs"] == "unbounded" or elements["content"]["maxOccurs"] > 1:
-                    if first.get("content", True):
-                        setattr(self, "content", [elements["content"]["elmt_type"]["extract"](node, None)])
-                        first["content"] = False
+                if name == "#cdata-section":
+                    if elements["content"]["elmt_type"]["type"] == SIMPLETYPE:
+                        object.__setattr__(self, "content", elements["content"]["elmt_type"]["extract"](node.data, False))
+                else:
+                    content = getattr(self, "content")
+                    if elements["content"]["maxOccurs"] == "unbounded" or elements["content"]["maxOccurs"] > 1:
+                        if first.get("content", True):
+                            object.__setattr__(self, "content", [elements["content"]["elmt_type"]["extract"](node, None)])
+                            first["content"] = False
+                        else:
+                            content.append(elements["content"]["elmt_type"]["extract"](node, content))
                     else:
-                        content.append(elements["content"]["elmt_type"]["extract"](node, content))
-                else:
-                    setattr(self, "content", elements["content"]["elmt_type"]["extract"](node, content))
+                        object.__setattr__(self, "content", elements["content"]["elmt_type"]["extract"](node, content))
     return loadXMLTreeMethod
         
 
@@ -1293,9 +1477,7 @@
             extras.clear()
         for attr in classinfos["attributes"]:
             if attr["use"] != "prohibited":
-                if isinstance(attr["attr_type"], (UnicodeType, StringType)):
-                    namespace, name = DecomposeQualifiedName(infos)
-                    attr["attr_type"] = factory.GetQualifiedNameInfos(name, namespace)
+                attr["attr_type"] = FindTypeInfos(factory, attr["attr_type"])
                 value = getattr(self, attr["name"], None)
                 if value != None:
                     computed_value = attr["attr_type"]["generate"](value)
@@ -1316,9 +1498,7 @@
         else:
             first = True
         for element in classinfos["elements"]:
-            if isinstance(element["elmt_type"], (UnicodeType, StringType)):
-                namespace, name = DecomposeQualifiedName(infos)
-                element["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
+            element["elmt_type"] = FindTypeInfos(factory, element["elmt_type"])
             value = getattr(self, element["name"], None)
             if element["minOccurs"] == 0 and element["maxOccurs"] == 1:
                 if value is not None:
@@ -1330,7 +1510,10 @@
                 if first:
                     text += u'>\n'
                     first = False
-                text += element["elmt_type"]["generate"](value, element["name"], indent + 1)
+                if element["name"] == "content" and element["elmt_type"]["type"] == SIMPLETYPE:
+                    text += element["elmt_type"]["generate"](value)
+                else:
+                    text += element["elmt_type"]["generate"](value, element["name"], indent + 1)
             else:
                 if first and len(value) > 0:
                     text += u'>\n'
@@ -1422,14 +1605,20 @@
             for element_name, element in elements.items():
                 if element["minOccurs"] == 0:
                     use = "optional"
-                if element_name == "content":
+                if element_name == "content" and element["type"] == CHOICE:
                     attr_type = [(choice["name"], None) for choice in element["choices"]]
                     if self.content is None:
                         value = ""
                     else:
                         value = self.content["name"]
                         if self.content["value"] is not None:
-                            children.extend(self.content["value"].getElementInfos(self.content["name"])["children"])
+                            if self.content["name"] == "sequence":
+                                choices_dict = dict([(choice["name"], choice) for choice in element["choices"]])
+                                sequence_infos = choices_dict.get("sequence", None)
+                                if sequence_infos is not None:
+                                    children.extend([item.getElementInfos(infos["name"]) for item, infos in zip(self.content["value"], sequence_infos["elements"])])
+                            else:
+                                children.extend(self.content["value"].getElementInfos(self.content["name"])["children"])
                 elif element["elmt_type"]["type"] == SIMPLETYPE:
                     children.append({"name": element_name, "require": element["minOccurs"] != 0, 
                         "type": gettypeinfos(element["elmt_type"]["basename"], 
@@ -1495,9 +1684,7 @@
         if classinfos.has_key("base"):
             classinfos["base"].__init__(self)
         for attribute in classinfos["attributes"]:
-            if isinstance(attribute["attr_type"], (UnicodeType, StringType)):
-                namespace, name = DecomposeQualifiedName(attribute["attr_type"])
-                attribute["attr_type"] = factory.GetQualifiedNameInfos(name, namespace)
+            attribute["attr_type"] = FindTypeInfos(factory, attribute["attr_type"])
             if attribute["use"] == "required":
                 setattr(self, attribute["name"], attribute["attr_type"]["initial"]())
             elif attribute["use"] == "optional":
@@ -1506,21 +1693,7 @@
                 else:
                     setattr(self, attribute["name"], None)
         for element in classinfos["elements"]:
-            if isinstance(element["elmt_type"], (UnicodeType, StringType)):
-                namespace, name = DecomposeQualifiedName(element["elmt_type"])
-                element["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
-            if element["minOccurs"] == 0 and element["maxOccurs"] == 1:
-                if "default" in element:
-                    setattr(self, element["name"], element["elmt_type"]["extract"](element["default"], False))
-                else:
-                    setattr(self, element["name"], None)
-            elif element["minOccurs"] == 1 and element["maxOccurs"] == 1:
-                setattr(self, element["name"], element["elmt_type"]["initial"]())
-            else:
-                value = []
-                for i in xrange(element["minOccurs"]):
-                    value.append(element["elmt_type"]["initial"]())
-                setattr(self, element["name"], value)
+            setattr(self, element["name"], GetElementInitialValue(factory, element))
     return initMethod
 
 def generateSetMethod(attr):
@@ -1536,15 +1709,11 @@
 def generateAddMethod(attr, factory, infos):
     def addMethod(self):
         if infos["type"] == ATTRIBUTE:
-            if isinstance(infos["attr_type"], (UnicodeType, StringType)):
-                namespace, name = DecomposeQualifiedName(infos)
-                infos["attr_type"] = factory.GetQualifiedNameInfos(name, namespace)
+            infos["attr_type"] = FindTypeInfos(factory, infos["attr_type"])
             initial = infos["attr_type"]["initial"]
             extract = infos["attr_type"]["extract"]
         elif infos["type"] == ELEMENT:
-            if isinstance(infos["elmt_type"], (UnicodeType, StringType)):
-                namespace, name = DecomposeQualifiedName(infos)
-                infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
+            infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
             initial = infos["elmt_type"]["initial"]
             extract = infos["elmt_type"]["extract"]
         else:
@@ -1562,9 +1731,7 @@
 
 def generateAppendMethod(attr, maxOccurs, factory, infos):
     def appendMethod(self, value):
-        if isinstance(infos["elmt_type"], (UnicodeType, StringType)):
-            namespace, name = DecomposeQualifiedName(infos)
-            infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
+        infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
         attr_list = getattr(self, attr)
         if maxOccurs == "unbounded" or len(attr_list) < maxOccurs:
             if infos["elmt_type"]["check"](value):
@@ -1577,9 +1744,7 @@
 
 def generateInsertMethod(attr, maxOccurs, factory, infos):
     def insertMethod(self, index, value):
-        if isinstance(infos["elmt_type"], (UnicodeType, StringType)):
-            namespace, name = DecomposeQualifiedName(infos)
-            infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
+        infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
         attr_list = getattr(self, attr)
         if maxOccurs == "unbounded" or len(attr_list) < maxOccurs:
             if infos["elmt_type"]["check"](value):
@@ -1600,9 +1765,7 @@
     def setChoiceMethod(self, type):
         if not choices.has_key(type):
             raise ValueError("Unknown \"%s\" choice type for \"content\"!" % type)
-        if isinstance(choices[type]["elmt_type"], (UnicodeType, StringType)):
-            namespace, name = DecomposeQualifiedName(choices[type]["elmt_type"])
-            choices[name]["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
+        choices[type]["elmt_type"] = FindTypeInfos(factory, choices[type]["elmt_type"])
         new_element = choices[type]["elmt_type"]["initial"]()
         self.content = {"name": type, "value": new_element}
         return new_element
@@ -1613,9 +1776,7 @@
     def appendChoiceMethod(self, type):
         if not choices.has_key(type):
             raise ValueError("Unknown \"%s\" choice type for \"content\"!" % type)
-        if isinstance(choices[type]["elmt_type"], (UnicodeType, StringType)):
-            namespace, name = DecomposeQualifiedName(choices[type]["elmt_type"])
-            choices[type]["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
+        choices[type]["elmt_type"] = FindTypeInfos(factory, choices[type]["elmt_type"])
         if maxOccurs == "unbounded" or len(self.content) < maxOccurs:
             new_element = choices[type]["elmt_type"]["initial"]()
             self.content.append({"name": type, "value": new_element})
@@ -1629,9 +1790,7 @@
     def insertChoiceMethod(self, index, type):
         if not choices.has_key(type):
             raise ValueError("Unknown \"%s\" choice type for \"content\"!" % type)
-        if isinstance(choices[type]["elmt_type"], (UnicodeType, StringType)):
-            namespace, name = DecomposeQualifiedName(choices[type]["elmt_type"])
-            choices[name]["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
+        choices[type]["elmt_type"] = FindTypeInfos(factory, choices[type]["elmt_type"])
         if maxOccurs == "unbounded" or len(self.content) < maxOccurs:
             new_element = choices[type]["elmt_type"]["initial"]()
             self.content.insert(index, {"name" : type, "value" : new_element})
@@ -1665,6 +1824,10 @@
             sys._getframe(1).f_locals[ClassName] = Class
         for TypeName, Type in pluginTypes.items():
             sys._getframe(1).f_locals[TypeName] = Type
-    globals().update(ComputedClasses)
-    return ComputedClasses
-
+    if factory.FileName is not None and len(ComputedClasses) == 1:
+        globals().update(ComputedClasses[factory.FileName])
+        return ComputedClasses[factory.FileName]
+    else:
+        globals().update(ComputedClasses)
+        return ComputedClasses
+