xmlclass/xmlclass.py
changeset 818 1d1bdf6e75bf
parent 814 5743cbdff669
child 1017 2925d6e49893
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xmlclass/xmlclass.py	Sun Sep 09 23:05:01 2012 +0200
@@ -0,0 +1,1856 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor
+#based on the plcopen standard. 
+#
+#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
+#
+#See COPYING file for copyrights details.
+#
+#This library is free software; you can redistribute it and/or
+#modify it under the terms of the GNU General Public
+#License as published by the Free Software Foundation; either
+#version 2.1 of the License, or (at your option) any later version.
+#
+#This library is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#General Public License for more details.
+#
+#You should have received a copy of the GNU General Public
+#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 os, sys
+import re
+import datetime
+from types import *
+from xml.dom import minidom
+from xml.sax.saxutils import escape, unescape, quoteattr
+from new import classobj
+
+def CreateNode(name):
+    node = minidom.Node()
+    node.nodeName = name
+    node._attrs = {}
+    node.childNodes = []
+    return node
+
+def NodeRenameAttr(node, old_name, new_name):
+    node._attrs[new_name] = node._attrs.pop(old_name)
+
+def NodeSetAttr(node, name, value):
+    attr = minidom.Attr(name)
+    text = minidom.Text()
+    text.data = value
+    attr.childNodes[0] = text
+    node._attrs[name] = attr
+
+"""
+Regular expression models for checking all kind of string values defined in XML
+standard
+"""
+Name_model = re.compile('([a-zA-Z_\:][\w\.\-\:]*)$')
+Names_model = re.compile('([a-zA-Z_\:][\w\.\-\:]*(?: [a-zA-Z_\:][\w\.\-\:]*)*)$')
+NMToken_model = re.compile('([\w\.\-\:]*)$')
+NMTokens_model = re.compile('([\w\.\-\:]*(?: [\w\.\-\:]*)*)$')
+QName_model = re.compile('((?:[a-zA-Z_][\w]*:)?[a-zA-Z_][\w]*)$')
+QNames_model = re.compile('((?:[a-zA-Z_][\w]*:)?[a-zA-Z_][\w]*(?: (?:[a-zA-Z_][\w]*:)?[a-zA-Z_][\w]*)*)$')
+NCName_model = re.compile('([a-zA-Z_][\w]*)$')
+URI_model = re.compile('((?:http://|/)?(?:[\w.-]*/?)*)$')
+LANGUAGE_model = re.compile('([a-zA-Z]{1,8}(?:-[a-zA-Z0-9]{1,8})*)$')
+
+ONLY_ANNOTATION = re.compile("((?:annotation )?)")
+
+"""
+Regular expression models for extracting dates and times from a string
+"""
+time_model = re.compile('([0-9]{2}):([0-9]{2}):([0-9]{2}(?:\.[0-9]*)?)(?:Z)?$')
+date_model = re.compile('([0-9]{4})-([0-9]{2})-([0-9]{2})((?:[\-\+][0-9]{2}:[0-9]{2})|Z)?$')
+datetime_model = re.compile('([0-9]{4})-([0-9]{2})-([0-9]{2})[ T]([0-9]{2}):([0-9]{2}):([0-9]{2}(?:\.[0-9]*)?)((?:[\-\+][0-9]{2}:[0-9]{2})|Z)?$')
+
+class xml_timezone(datetime.tzinfo):
+
+    def SetOffset(self, offset):
+        if offset == "Z":
+            self.__offset = timedelta(minutes = 0)
+            self.__name = "UTC"
+        else:
+            sign = {"-" : -1, "+" : 1}[offset[0]]
+            hours, minutes = [int(val) for val in offset[1:].split(":")]
+            self.__offset = timedelta(minutes=sign * (hours * 60 + minutes))
+            self.__name = ""
+
+    def utcoffset(self, dt):
+        return self.__offset
+
+    def tzname(self, dt):
+        return self.__name
+
+    def dst(self, dt):
+        return ZERO
+
+[SYNTAXELEMENT, SYNTAXATTRIBUTE, SIMPLETYPE, COMPLEXTYPE, COMPILEDCOMPLEXTYPE, 
+ ATTRIBUTESGROUP, ELEMENTSGROUP, ATTRIBUTE, ELEMENT, CHOICE, ANY, TAG, CONSTRAINT,
+] = range(13)
+
+def NotSupportedYet(type):
+    """
+    Function that generates a function that point out to user that datatype
+    used is not supported by xmlclass yet
+    @param type: data type
+    @return: function generated
+    """
+    def GetUnknownValue(attr):
+        raise ValueError("\"%s\" type isn't supported by \"xmlclass\" yet!" % \
+                         type)
+    return GetUnknownValue
+
+"""
+This function calculates the number of whitespace for indentation
+"""
+def getIndent(indent, balise):
+    first = indent * 2
+    second = first + len(balise) + 1
+    return u'\t'.expandtabs(first), u'\t'.expandtabs(second)
+
+
+def GetAttributeValue(attr, extract=True):
+    """
+    Function that extracts data from a tree node
+    @param attr: tree node containing data to extract
+    @param extract: attr is a tree node or not
+    @return: data extracted as string
+    """
+    if not extract:
+        return attr
+    if len(attr.childNodes) == 1:
+        return unicode(unescape(attr.childNodes[0].data))
+    else:
+        # content is a CDATA
+        text = u''
+        for node in attr.childNodes:
+            if not (node.nodeName == "#text" and node.data.strip() == u''):
+                text += unicode(unescape(node.data))
+        return text
+
+
+def GetNormalizedString(attr, extract=True):
+    """
+    Function that normalizes a string according to XML 1.0. Replace  
+    tabulations, line feed and carriage return by white space
+    @param attr: tree node containing data to extract or data to normalize
+    @param extract: attr is a tree node or not
+    @return: data normalized as string
+    """
+    if extract:
+        value = GetAttributeValue(attr)
+    else:
+        value = attr
+    return value.replace("\t", " ").replace("\r", " ").replace("\n", " ")
+
+
+def GetToken(attr, extract=True):
+    """
+    Function that tokenizes a string according to XML 1.0. Remove any leading  
+    and trailing white space and replace internal sequence of two or more 
+    spaces by only one white space
+    @param attr: tree node containing data to extract or data to tokenize
+    @param extract: attr is a tree node or not
+    @return: data tokenized as string
+    """
+    return " ".join([part for part in 
+                     GetNormalizedString(attr, extract).split(" ")
+                     if part])
+
+
+def GetHexInteger(attr, extract=True):
+    """
+    Function that extracts an hexadecimal integer from a tree node or a string
+    @param attr: tree node containing data to extract or data as a string
+    @param extract: attr is a tree node or not
+    @return: data as an integer
+    """
+    if extract:
+        value = GetAttributeValue(attr)
+    else:
+        value = attr
+    if len(value) % 2 != 0:
+        raise ValueError("\"%s\" isn't a valid hexadecimal integer!" % value)
+    try:
+        return int(value, 16)
+    except:
+        raise ValueError("\"%s\" isn't a valid hexadecimal integer!" % value)
+
+
+def GenerateIntegerExtraction(minInclusive=None, maxInclusive=None, 
+                              minExclusive=None, maxExclusive=None):
+    """
+    Function that generates an extraction function for integer defining min and
+    max of integer value
+    @param minInclusive: inclusive minimum
+    @param maxInclusive: inclusive maximum
+    @param minExclusive: exclusive minimum
+    @param maxExclusive: exclusive maximum
+    @return: function generated
+    """
+    def GetInteger(attr, extract=True):
+        """
+        Function that extracts an integer from a tree node or a string
+        @param attr: tree node containing data to extract or data as a string
+        @param extract: attr is a tree node or not
+        @return: data as an integer
+        """
+
+        if extract:
+            value = GetAttributeValue(attr)
+        else:
+            value = attr
+        try:
+            # TODO: permit to write value like 1E2
+            value = int(value)
+        except:
+            raise ValueError("\"%s\" isn't a valid integer!" % value)
+        if minInclusive is not None and value < minInclusive:
+            raise ValueError("\"%d\" isn't greater or equal to %d!" % \
+                             (value, minInclusive))
+        if maxInclusive is not None and value > maxInclusive:
+            raise ValueError("\"%d\" isn't lesser or equal to %d!" % \
+                             (value, maxInclusive))
+        if minExclusive is not None and value <= minExclusive:
+            raise ValueError("\"%d\" isn't greater than %d!" % \
+                             (value, minExclusive))
+        if maxExclusive is not None and value >= maxExclusive:
+            raise ValueError("\"%d\" isn't lesser than %d!" % \
+                             (value, maxExclusive))
+        return value
+    return GetInteger
+
+
+def GenerateFloatExtraction(type, extra_values=[]):
+    """
+    Function that generates an extraction function for float
+    @param type: name of the type of float
+    @return: function generated
+    """
+    def GetFloat(attr, extract = True):
+        """
+        Function that extracts a float from a tree node or a string
+        @param attr: tree node containing data to extract or data as a string
+        @param extract: attr is a tree node or not
+        @return: data as a float
+        """
+        if extract:
+            value = GetAttributeValue(attr)
+        else:
+            value = attr
+        if value in extra_values:
+            return value
+        try:
+            return float(value)
+        except:
+            raise ValueError("\"%s\" isn't a valid %s!" % (value, type))
+    return GetFloat
+
+
+def GetBoolean(attr, extract=True):
+    """
+    Function that extracts a boolean from a tree node or a string
+    @param attr: tree node containing data to extract or data as a string
+    @param extract: attr is a tree node or not
+    @return: data as a boolean
+    """
+    if extract:
+        value = GetAttributeValue(attr)
+    else:
+        value = attr
+    if value == "true" or value == "1":
+        return True
+    elif value == "false" or value == "0":
+        return False
+    else:
+        raise ValueError("\"%s\" isn't a valid boolean!" % value)
+
+
+def GetTime(attr, extract=True):
+    """
+    Function that extracts a time from a tree node or a string
+    @param attr: tree node containing data to extract or data as a string
+    @param extract: attr is a tree node or not
+    @return: data as a time
+    """
+    if extract:
+        value = GetAttributeValue(attr)
+    else:
+        value = attr
+    result = time_model.match(value)
+    if result:
+        values = result.groups()
+        time_values = [int(v) for v in values[:2]]
+        seconds = float(values[2])
+        time_values.extend([int(seconds), int((seconds % 1) * 1000000)])
+        return datetime.time(*time_values)
+    else:
+        raise ValueError("\"%s\" isn't a valid time!" % value)
+
+
+def GetDate(attr, extract=True):
+    """
+    Function that extracts a date from a tree node or a string
+    @param attr: tree node containing data to extract or data as a string
+    @param extract: attr is a tree node or not
+    @return: data as a date
+    """
+    if extract:
+        value = GetAttributeValue(attr)
+    else:
+        value = attr
+    result = date_model.match(value)
+    if result:
+        values = result.groups()
+        date_values = [int(v) for v in values[:3]]
+        if values[3] is not None:
+            tz = xml_timezone()
+            tz.SetOffset(values[3])
+            date_values.append(tz)
+        return datetime.date(*date_values)
+    else:
+        raise ValueError("\"%s\" isn't a valid date!" % value)
+
+
+def GetDateTime(attr, extract=True):
+    """
+    Function that extracts date and time from a tree node or a string
+    @param attr: tree node containing data to extract or data as a string
+    @param extract: attr is a tree node or not
+    @return: data as date and time
+    """
+    if extract:
+        value = GetAttributeValue(attr)
+    else:
+        value = attr
+    result = datetime_model.match(value)
+    if result:
+        values = result.groups()
+        datetime_values = [int(v) for v in values[:5]]
+        seconds = float(values[5])
+        datetime_values.extend([int(seconds), int((seconds % 1) * 1000000)])
+        if values[6] is not None:
+            tz = xml_timezone()
+            tz.SetOffset(values[6])
+            datetime_values.append(tz)
+        return datetime.datetime(*datetime_values)
+    else:
+        raise ValueError("\"%s\" isn't a valid datetime!" % value)
+
+
+def GenerateModelNameExtraction(type, model):
+    """
+    Function that generates an extraction function for string matching a model
+    @param type: name of the data type
+    @param model: model that data must match
+    @return: function generated
+    """
+    def GetModelName(attr, extract=True):
+        """
+        Function that extracts a string from a tree node or not and check that
+        string extracted or given match the model
+        @param attr: tree node containing data to extract or data as a string
+        @param extract: attr is a tree node or not
+        @return: data as a string if matching
+        """
+        if extract:
+            value = GetAttributeValue(attr)
+        else:
+            value = attr
+        result = model.match(value)
+        if not result:
+            raise ValueError("\"%s\" isn't a valid %s!" % (value, type))
+        return value
+    return GetModelName
+
+
+def GenerateLimitExtraction(min=None, max=None, unbounded=True):
+    """
+    Function that generates an extraction function for integer defining min and
+    max of integer value
+    @param min: minimum limit value
+    @param max: maximum limit value
+    @param unbounded: value can be "unbounded" or not
+    @return: function generated
+    """
+    def GetLimit(attr, extract=True):
+        """
+        Function that extracts a string from a tree node or not and check that
+        string extracted or given is in a list of values
+        @param attr: tree node containing data to extract or data as a string
+        @param extract: attr is a tree node or not
+        @return: data as a string
+        """
+        if extract:
+            value = GetAttributeValue(attr)
+        else:
+            value = attr
+        if value == "unbounded":
+            if unbounded:
+                return value
+            else:
+                raise ValueError("Member limit can't be defined to \"unbounded\"!")
+        try:
+            limit = int(value)
+        except:
+            raise ValueError("\"%s\" isn't a valid value for this member limit!" % value)
+        if limit < 0:
+            raise ValueError("Member limit can't be negative!")
+        elif min is not None and limit < min:
+            raise ValueError("Member limit can't be lower than \"%d\"!" % min)
+        elif max is not None and limit > max:
+            raise ValueError("Member limit can't be upper than \"%d\"!" % max)
+        return limit
+    return GetLimit
+
+
+def GenerateEnumeratedExtraction(type, list):
+    """
+    Function that generates an extraction function for enumerated values
+    @param type: name of the data type
+    @param list: list of possible values
+    @return: function generated
+    """
+    def GetEnumerated(attr, extract=True):
+        """
+        Function that extracts a string from a tree node or not and check that
+        string extracted or given is in a list of values
+        @param attr: tree node containing data to extract or data as a string
+        @param extract: attr is a tree node or not
+        @return: data as a string
+        """
+        if extract:
+            value = GetAttributeValue(attr)
+        else:
+            value = attr
+        if value in list:
+            return value
+        else:
+            raise ValueError("\"%s\" isn't a valid value for %s!" % \
+                             (value, type))
+    return GetEnumerated
+
+
+def GetNamespaces(attr, extract=True):
+    """
+    Function that extracts a list of namespaces from a tree node or a string
+    @param attr: tree node containing data to extract or data as a string
+    @param extract: attr is a tree node or not
+    @return: list of namespaces
+    """
+    if extract:
+        value = GetAttributeValue(attr)
+    else:
+        value = attr
+    if value == "":
+        return []
+    elif value == "##any" or value == "##other":
+        namespaces = [value]
+    else:
+        namespaces = []
+        for item in value.split(" "):
+            if item == "##targetNamespace" or item == "##local":
+                namespaces.append(item)
+            else:
+                result = URI_model.match(item)
+                if result is not None:
+                    namespaces.append(item)
+                else:
+                    raise ValueError("\"%s\" isn't a valid value for namespace!" % value)
+    return namespaces
+
+
+def GenerateGetList(type, list):
+    """
+    Function that generates an extraction function for a list of values
+    @param type: name of the data type
+    @param list: list of possible values
+    @return: function generated
+    """
+    def GetLists(attr, extract=True):
+        """
+        Function that extracts a list of values from a tree node or a string
+        @param attr: tree node containing data to extract or data as a string
+        @param extract: attr is a tree node or not
+        @return: list of values
+        """
+        if extract:
+            value = GetAttributeValue(attr)
+        else:
+            value = attr
+        if value == "":
+            return []
+        elif value == "#all":
+            return [value]
+        else:
+            values = []
+            for item in value.split(" "):
+                if item in list:
+                    values.append(item)
+                else:
+                    raise ValueError("\"%s\" isn't a valid value for %s!" % \
+                                     (value, type))
+            return values
+    return GetLists
+
+
+def GenerateModelNameListExtraction(type, model):
+    """
+    Function that generates an extraction function for list of string matching
+    a model
+    @param type: name of the data type
+    @param model: model that list elements must match
+    @return: function generated
+    """
+    def GetModelNameList(attr, extract=True):
+        """
+        Function that extracts a list of string from a tree node or not and
+        check that all extracted items match the model
+        @param attr: tree node containing data to extract or data as a string
+        @param extract: attr is a tree node or not
+        @return: data as a list of string if matching 
+        """
+        if extract:
+            value = GetAttributeValue(attr)
+        else:
+            value = attr
+        values = []
+        for item in value.split(" "):
+            result = model.match(item)
+            if result is not None:
+                values.append(item)
+            else:
+                raise ValueError("\"%s\" isn't a valid value for %s!" % \
+                                 (value, type))
+        return values
+    return GetModelNameList
+
+def GenerateAnyInfos(infos):
+    def ExtractAny(tree):
+        if tree.nodeName in ["#text", "#cdata-section"]:
+            return unicode(unescape(tree.data))
+        else:
+            return tree
+    
+    def GenerateAny(value, name=None, indent=0):
+        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, minidom.Node))
+    }
+
+def GenerateTagInfos(infos):
+    def ExtractTag(tree):
+        if len(tree._attrs) > 0:
+            raise ValueError("\"%s\" musn't have attributes!" % infos["name"])
+        if len(tree.childNodes) > 0:
+            raise ValueError("\"%s\" musn't have children!" % infos["name"])
+        if infos["minOccurs"] == 0:
+            return True
+        else:
+            return None
+    
+    def GenerateTag(value, name=None, indent=0):
+        if name is not None and not (infos["minOccurs"] == 0 and value is None):
+            ind1, ind2 = getIndent(indent, name)
+            return ind1 + "<%s/>\n" % name
+        else:
+            return ""
+    
+    return {
+        "type": TAG, 
+        "extract": ExtractTag,
+        "generate": GenerateTag,
+        "initial": lambda: None,
+        "check": lambda x: x == None or infos["minOccurs"] == 0 and value == True
+    }
+
+def FindTypeInfos(factory, infos):
+    if isinstance(infos, (UnicodeType, StringType)):
+        namespace, name = DecomposeQualifiedName(infos)
+        return factory.GetQualifiedNameInfos(name, namespace)
+    return infos
+    
+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)
+        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 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"]:
+                        element_value = None
+                        if element_infos["type"] == CHOICE:
+                            choice_infos = None
+                            if element_idx < len(value["value"]):
+                                for choice in element_infos["choices"]:
+                                    if choice["name"] == value["value"][element_idx]["name"]:
+                                        choice_infos = choice
+                                        element_value = value["value"][element_idx]["value"]
+                                        element_idx += 1
+                                        break
+                            if ((choice_infos is not None and 
+                                 not CheckElementValue(factory, choice_infos["name"], choice_infos, element_value, False)) or
+                                (choice_infos is None and element_infos["minOccurs"] > 0)):
+                                raise ValueError("Invalid sequence value in attribute 'content'")
+                        else:
+                            if element_idx < len(value["value"]) and element_infos["name"] == value["value"][element_idx]["name"]:
+                                element_value = value["value"][element_idx]["value"]
+                                element_idx += 1
+                            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 ExtractContent(tree, content):
+        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):
+        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:
+                    for item in value["value"]:
+                        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,
+        "generate": GenerateContent
+    }
+
+#-------------------------------------------------------------------------------
+#                           Structure extraction functions
+#-------------------------------------------------------------------------------
+
+
+def DecomposeQualifiedName(name):
+    result = QName_model.match(name)
+    if not result:
+        raise ValueError("\"%s\" isn't a valid QName value!" % name) 
+    parts = result.groups()[0].split(':')
+    if len(parts) == 1:
+        return None, parts[0]
+    return parts
+    
+def GenerateElement(element_name, attributes, elements_model, 
+                    accept_text=False):
+    def ExtractElement(factory, node):
+        attrs = factory.ExtractNodeAttrs(element_name, node, attributes)
+        children_structure = ""
+        children_infos = []
+        children = []
+        for child in node.childNodes:
+            if child.nodeName not in ["#comment", "#text"]:
+                namespace, childname = DecomposeQualifiedName(child.nodeName)
+                children_structure += "%s "%childname
+        result = elements_model.match(children_structure)
+        if not result:
+            raise ValueError("Invalid structure for \"%s\" children!. First element invalid." % node.nodeName)
+        valid = result.groups()[0]
+        if len(valid) < len(children_structure):
+            raise ValueError("Invalid structure for \"%s\" children!. Element number %d invalid." % (node.nodeName, len(valid.split(" ")) - 1))
+        for child in node.childNodes:
+            if child.nodeName != "#comment" and \
+               (accept_text or child.nodeName != "#text"):
+                if child.nodeName == "#text":
+                    children.append(GetAttributeValue(node))
+                else:
+                    namespace, childname = DecomposeQualifiedName(child.nodeName)
+                    infos = factory.GetQualifiedNameInfos(childname, namespace)
+                    if infos["type"] != SYNTAXELEMENT:
+                        raise ValueError("\"%s\" can't be a member child!" % name)
+                    if infos["extract"].has_key(element_name):
+                        children.append(infos["extract"][element_name](factory, child))
+                    else:
+                        children.append(infos["extract"]["default"](factory, child))
+        return node.nodeName, attrs, children
+    return ExtractElement
+
+
+"""
+Class that generate class from an XML Tree
+"""
+class ClassFactory:
+
+    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
+        # the XML tree
+        self.XMLClassDefinitions = {}
+        
+        self.DefinedNamespaces = {}
+        self.Namespaces = {}
+        self.SchemaNamespace = None
+        self.TargetNamespace = None
+        
+        self.CurrentCompilations = []
+        
+        # Dictionaries for stocking Classes and Types generated
+        self.ComputeAfter = []
+        if self.FileName is not None:
+            self.ComputedClasses = {self.FileName: {}}
+        else:
+            self.ComputedClasses = {}
+        self.ComputedClassesInfos = {}
+        self.AlreadyComputed = {}
+
+    def GetQualifiedNameInfos(self, name, namespace=None, canbenone=False):
+        if namespace is None:
+            if self.Namespaces[self.SchemaNamespace].has_key(name):
+                return self.Namespaces[self.SchemaNamespace][name]
+            for space, elements in self.Namespaces.iteritems():
+                if space != self.SchemaNamespace and elements.has_key(name):
+                    return elements[name]
+            parts = name.split("_", 1)
+            if len(parts) > 1:
+                group = self.GetQualifiedNameInfos(parts[0], namespace)
+                if group is not None and group["type"] == ELEMENTSGROUP:
+                    elements = []
+                    if group.has_key("elements"):
+                        elements = group["elements"]
+                    elif group.has_key("choices"):
+                        elements = group["choices"]
+                    for element in elements:
+                        if element["name"] == parts[1]:
+                            return element
+            if not canbenone:
+                raise ValueError("Unknown element \"%s\" for any defined namespaces!" % name)
+        elif self.Namespaces.has_key(namespace):
+            if self.Namespaces[namespace].has_key(name):
+                return self.Namespaces[namespace][name]
+            parts = name.split("_", 1)
+            if len(parts) > 1:
+                group = self.GetQualifiedNameInfos(parts[0], namespace)
+                if group is not None and group["type"] == ELEMENTSGROUP:
+                    elements = []
+                    if group.has_key("elements"):
+                        elements = group["elements"]
+                    elif group.has_key("choices"):
+                        elements = group["choices"]
+                    for element in elements:
+                        if element["name"] == parts[1]:
+                            return element
+            if not canbenone:
+                raise ValueError("Unknown element \"%s\" for namespace \"%s\"!" % (name, namespace))
+        elif not canbenone:
+            raise ValueError("Unknown namespace \"%s\"!" % namespace)
+        return None
+
+    def SplitQualifiedName(self, name, namespace=None, canbenone=False):
+        if namespace is None:
+            if self.Namespaces[self.SchemaNamespace].has_key(name):
+                return name, None
+            for space, elements in self.Namespaces.items():
+                if space != self.SchemaNamespace and elements.has_key(name):
+                    return name, None
+            parts = name.split("_", 1)
+            if len(parts) > 1:
+                group = self.GetQualifiedNameInfos(parts[0], namespace)
+                if group is not None and group["type"] == ELEMENTSGROUP:
+                    elements = []
+                    if group.has_key("elements"):
+                        elements = group["elements"]
+                    elif group.has_key("choices"):
+                        elements = group["choices"]
+                    for element in elements:
+                        if element["name"] == parts[1]:
+                            return part[1], part[0]
+            if not canbenone:
+                raise ValueError("Unknown element \"%s\" for any defined namespaces!" % name)
+        elif self.Namespaces.has_key(namespace):
+            if self.Namespaces[namespace].has_key(name):
+                return name, None
+            parts = name.split("_", 1)
+            if len(parts) > 1:
+                group = self.GetQualifiedNameInfos(parts[0], namespace)
+                if group is not None and group["type"] == ELEMENTSGROUP:
+                    elements = []
+                    if group.has_key("elements"):
+                        elements = group["elements"]
+                    elif group.has_key("choices"):
+                        elements = group["choices"]
+                    for element in elements:
+                        if element["name"] == parts[1]:
+                            return parts[1], parts[0]
+            if not canbenone:
+                raise ValueError("Unknown element \"%s\" for namespace \"%s\"!" % (name, namespace))
+        elif not canbenone:
+            raise ValueError("Unknown namespace \"%s\"!" % namespace)
+        return None, None
+
+    def ExtractNodeAttrs(self, element_name, node, valid_attrs):
+        attrs = {}
+        for qualified_name, attr in node._attrs.items():
+            namespace, name =  DecomposeQualifiedName(qualified_name)
+            if name in valid_attrs:
+                infos = self.GetQualifiedNameInfos(name, namespace)
+                if infos["type"] != SYNTAXATTRIBUTE:
+                    raise ValueError("\"%s\" can't be a member attribute!" % name)
+                elif name in attrs:
+                    raise ValueError("\"%s\" attribute has been twice!" % name)
+                elif element_name in infos["extract"]:
+                    attrs[name] = infos["extract"][element_name](attr)
+                else:
+                    attrs[name] = infos["extract"]["default"](attr)
+            elif namespace == "xmlns":
+                infos = self.GetQualifiedNameInfos("anyURI", self.SchemaNamespace)
+                self.DefinedNamespaces[infos["extract"](attr)] = name
+            else:
+                raise ValueError("Invalid attribute \"%s\" for member \"%s\"!" % (qualified_name, node.nodeName))
+        for attr in valid_attrs:
+            if attr not in attrs and \
+               self.Namespaces[self.SchemaNamespace].has_key(attr) and \
+               self.Namespaces[self.SchemaNamespace][attr].has_key("default"):
+                if self.Namespaces[self.SchemaNamespace][attr]["default"].has_key(element_name):
+                    default = self.Namespaces[self.SchemaNamespace][attr]["default"][element_name]
+                else:
+                    default = self.Namespaces[self.SchemaNamespace][attr]["default"]["default"]
+                if default is not None:
+                    attrs[attr] = default
+        return attrs
+
+    def ReduceElements(self, elements, schema=False):
+        result = []
+        for child_infos in elements:
+            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:
+            if element["type"] == "annotation":
+                annotations.append(element)
+            else:
+                children.append(element)
+        return annotations, children
+
+    def AddComplexType(self, typename, infos):
+        if not self.XMLClassDefinitions.has_key(typename):
+            self.XMLClassDefinitions[typename] = infos
+        else:
+            raise ValueError("\"%s\" class already defined. Choose another name!" % typename)
+
+    def ParseSchema(self):
+        pass
+
+    def ExtractTypeInfos(self, name, parent, typeinfos):
+        if isinstance(typeinfos, (StringType, UnicodeType)):
+            namespace, name = DecomposeQualifiedName(typeinfos)
+            infos = self.GetQualifiedNameInfos(name, namespace)
+            if infos["type"] == COMPLEXTYPE:
+                name, parent = self.SplitQualifiedName(name, namespace)
+                result = self.CreateClass(name, parent, infos)
+                if result is not None and not isinstance(result, (UnicodeType, StringType)):
+                    self.Namespaces[self.TargetNamespace][result["name"]] = result
+                return result
+            elif infos["type"] == ELEMENT and infos["elmt_type"]["type"] == COMPLEXTYPE:
+                name, parent = self.SplitQualifiedName(name, namespace)
+                result = self.CreateClass(name, parent, infos["elmt_type"])
+                if result is not None and not isinstance(result, (UnicodeType, StringType)):
+                    self.Namespaces[self.TargetNamespace][result["name"]] = result
+                return result
+            else:
+                return infos
+        elif typeinfos["type"] == COMPLEXTYPE:
+            return self.CreateClass(name, parent, typeinfos)
+        elif typeinfos["type"] == SIMPLETYPE:
+            return typeinfos
+            
+    """
+    Methods that generates the classes
+    """
+    def CreateClasses(self):
+        self.ParseSchema()
+        for name, infos in self.Namespaces[self.TargetNamespace].items():
+            if infos["type"] == ELEMENT:
+                if not isinstance(infos["elmt_type"], (UnicodeType, StringType)) and \
+                   infos["elmt_type"]["type"] == COMPLEXTYPE:
+                    self.ComputeAfter.append((name, None, infos["elmt_type"], True))
+                    while len(self.ComputeAfter) > 0:
+                        result = self.CreateClass(*self.ComputeAfter.pop(0))
+                        if result is not None and not isinstance(result, (UnicodeType, StringType)):
+                            self.Namespaces[self.TargetNamespace][result["name"]] = result
+            elif infos["type"] == COMPLEXTYPE:
+                self.ComputeAfter.append((name, None, infos))
+                while len(self.ComputeAfter) > 0:
+                    result = self.CreateClass(*self.ComputeAfter.pop(0))
+                    if result is not None and \
+                       not isinstance(result, (UnicodeType, StringType)):
+                        self.Namespaces[self.TargetNamespace][result["name"]] = result
+            elif infos["type"] == ELEMENTSGROUP:
+                elements = []
+                if infos.has_key("elements"):
+                    elements = infos["elements"]
+                elif infos.has_key("choices"):
+                    elements = infos["choices"]
+                for element in elements:
+                    if not isinstance(element["elmt_type"], (UnicodeType, StringType)) and \
+                       element["elmt_type"]["type"] == COMPLEXTYPE:
+                        self.ComputeAfter.append((element["name"], infos["name"], element["elmt_type"]))
+                        while len(self.ComputeAfter) > 0:
+                            result = self.CreateClass(*self.ComputeAfter.pop(0))
+                            if result is not None and \
+                               not isinstance(result, (UnicodeType, StringType)):
+                                self.Namespaces[self.TargetNamespace][result["name"]] = result
+        return self.ComputedClasses
+
+    def CreateClass(self, name, parent, classinfos, baseclass = False):
+        if parent is not None:
+            classname = "%s_%s" % (parent, name)
+        else:
+            classname = name
+        
+        # Checks that classe haven't been generated yet
+        if self.AlreadyComputed.get(classname, False):
+            if baseclass:
+                self.AlreadyComputed[classname].IsBaseClass = baseclass
+            return self.ComputedClassesInfos.get(classname, None)
+        
+        # If base classes haven't been generated
+        bases = []
+        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(base_infos)                
+                if self.AlreadyComputed.get(base_name, False):
+                    self.ComputeAfter.append((name, parent, classinfos))
+                    if self.TargetNamespace is not None:
+                        return "%s:%s" % (self.TargetNamespace, classname)
+                    else:
+                        return classname
+            elif result is not None:
+                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}
+        
+        self.AlreadyComputed[classname] = True
+        
+        for attribute in classinfos["attributes"]:
+            infos = self.ExtractTypeInfos(attribute["name"], name, attribute["attr_type"])
+            if infos is not None:                    
+                if infos["type"] != SIMPLETYPE:
+                    raise ValueError("\"%s\" type is not a simple type!" % attribute["attr_type"])
+                attrname = attribute["name"]
+                if attribute["use"] == "optional":
+                    classmembers[attrname] = None
+                    classmembers["add%s"%attrname] = generateAddMethod(attrname, self, attribute)
+                    classmembers["delete%s"%attrname] = generateDeleteMethod(attrname)
+                else:
+                    classmembers[attrname] = infos["initial"]()
+                classmembers["set%s"%attrname] = generateSetMethod(attrname)
+                classmembers["get%s"%attrname] = generateGetMethod(attrname)
+            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 = 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, name, choices)
+            elif element["type"] == ANY:
+                elmtname = element["name"] = "text"
+                element["minOccurs"] = element["maxOccurs"] = 1
+                infos = GenerateAnyInfos(element)
+            else:
+                elmtname = element["name"]
+                if element["elmt_type"] == "tag":
+                    infos = GenerateTagInfos(element)
+                else:
+                    infos = self.ExtractTypeInfos(element["name"], name, element["elmt_type"])
+            if infos is not None:
+                element["elmt_type"] = infos
+            if element["maxOccurs"] == "unbounded" or element["maxOccurs"] > 1:
+                classmembers[elmtname] = []
+                classmembers["append%s" % elmtname] = generateAppendMethod(elmtname, element["maxOccurs"], self, element)
+                classmembers["insert%s" % elmtname] = generateInsertMethod(elmtname, element["maxOccurs"], self, element)
+                classmembers["remove%s" % elmtname] = generateRemoveMethod(elmtname, element["minOccurs"])
+                classmembers["count%s" % elmtname] = generateCountMethod(elmtname)
+            else:
+                if element["minOccurs"] == 0:
+                    classmembers[elmtname] = None
+                    classmembers["add%s" % elmtname] = generateAddMethod(elmtname, self, element)
+                    classmembers["delete%s" % elmtname] = generateDeleteMethod(elmtname)
+                elif not isinstance(element["elmt_type"], (UnicodeType, StringType)):
+                    classmembers[elmtname] = element["elmt_type"]["initial"]()
+                else:
+                    classmembers[elmtname] = None
+            classmembers["set%s" % elmtname] = generateSetMethod(elmtname)
+            classmembers["get%s" % elmtname] = generateGetMethod(elmtname)
+            
+        classmembers["__init__"] = generateInitMethod(self, classinfos)
+        classmembers["getStructure"] = generateStructureMethod(classinfos)
+        classmembers["loadXMLTree"] = generateLoadXMLTree(self, classinfos)
+        classmembers["generateXMLText"] = generateGenerateXMLText(self, classinfos)
+        classmembers["getElementAttributes"] = generateGetElementAttributes(self, classinfos)
+        classmembers["getElementInfos"] = generateGetElementInfos(self, classinfos)
+        classmembers["setElementValue"] = generateSetElementValue(self, classinfos)
+        classmembers["singleLineAttributes"] = True
+        classmembers["compatibility"] = lambda x, y: None
+        classmembers["extraAttrs"] = {}
+        
+        class_definition = classobj(str(classname), bases, classmembers)
+        setattr(class_definition, "__setattr__", generateSetattrMethod(self, class_definition, classinfos))
+        class_infos = {"type": COMPILEDCOMPLEXTYPE,
+                       "name": classname,
+                       "check": generateClassCheckFunction(class_definition),
+                       "initial": generateClassCreateFunction(class_definition),
+                       "extract": generateClassExtractFunction(class_definition),
+                       "generate": class_definition.generateXMLText}
+        
+        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
+
+    """
+    Methods that print the classes generated
+    """
+    def PrintClasses(self):
+        items = self.ComputedClasses.items()
+        items.sort()
+        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()
+        classnames.sort()
+        for classname in classnames:
+            print classname
+
+"""
+Method that generate the method for checking a class instance
+"""
+def generateClassCheckFunction(class_definition):
+    def classCheckfunction(instance):
+        return isinstance(instance, class_definition)
+    return classCheckfunction
+
+"""
+Method that generate the method for creating a class instance
+"""
+def generateClassCreateFunction(class_definition):
+    def classCreatefunction():
+        return class_definition()
+    return classCreatefunction
+
+"""
+Method that generate the method for extracting a class instance
+"""
+def generateClassExtractFunction(class_definition):
+    def classExtractfunction(node):
+        instance = class_definition()
+        instance.loadXMLTree(node)
+        return instance
+    return classExtractfunction
+
+"""
+Method that generate the method for loading an xml tree by following the
+attributes list defined
+"""
+def generateSetattrMethod(factory, class_definition, classinfos):
+    attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
+    optional_attributes = dict([(attr["name"], True) for attr in classinfos["attributes"] if attr["use"] == "optional"])
+    elements = dict([(element["name"], element) for element in classinfos["elements"]])
+    
+    def setattrMethod(self, name, value):
+        if attributes.has_key(name):
+            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)
+                else:
+                    raise ValueError("Attribute '%s' isn't optional." % name)
+            elif attributes[name].has_key("fixed") and value != attributes[name]["fixed"]:
+                raise ValueError, "Value of attribute '%s' can only be '%s'."%(name, str(attributes[name]["fixed"]))
+            elif attributes[name]["attr_type"]["check"](value):
+                return object.__setattr__(self, name, value)
+            else:
+                raise ValueError("Invalid value for attribute '%s'." % (name))
+        elif elements.has_key(name):
+            if CheckElementValue(factory, name, elements[name], value):
+                return object.__setattr__(self, name, value)
+            else:
+                raise ValueError("Invalid value for attribute '%s'." % (name))
+        elif classinfos.has_key("base"):
+            return classinfos["base"].__setattr__(self, name, value)
+        elif class_definition.__dict__.has_key(name):
+            return object.__setattr__(self, name, value)
+        else:
+            raise AttributeError("'%s' can't have an attribute '%s'." % (self.__class__.__name__, name))
+        
+    return setattrMethod
+
+"""
+Method that generate the method for generating the xml tree structure model by 
+following the attributes list defined
+"""
+def ComputeMultiplicity(name, infos):
+    if infos["minOccurs"] == 0:
+        if infos["maxOccurs"] == "unbounded":
+            return "(?:%s)*" % name
+        elif infos["maxOccurs"] == 1:
+            return "(?:%s)?" % name
+        else:
+            return "(?:%s){,%d}" % (name, infos["maxOccurs"])
+    elif infos["minOccurs"] == 1:
+        if infos["maxOccurs"] == "unbounded":
+            return "(?:%s)+" % name
+        elif infos["maxOccurs"] == 1:
+            return "(?:%s)" % name
+        else:
+            return "(?:%s){1,%d}" % (name, infos["maxOccurs"])
+    else:
+        if infos["maxOccurs"] == "unbounded":
+            return "(?:%s){%d,}" % (name, infos["minOccurs"], name)
+        else:
+            return "(?:%s){%d,%d}" % (name, infos["minOccurs"], 
+                                       infos["maxOccurs"])
+
+def GetStructure(classinfos):
+    elements = []
+    for element in classinfos["elements"]:
+        if element["type"] == ANY:
+            infos = element.copy()
+            infos["minOccurs"] = 0
+            elements.append(ComputeMultiplicity("#text |#cdata-section |\w* ", infos))
+        elif element["type"] == CHOICE:
+            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("(?:#text |#cdata-section )?")
+        else:
+            elements.append(ComputeMultiplicity("%s " % element["name"], element))
+    if classinfos.get("order", True) or len(elements) == 0:
+        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
+    return getStructureMethod
+
+"""
+Method that generate the method for loading an xml tree by following the
+attributes list defined
+"""
+def generateLoadXMLTree(factory, classinfos):
+    attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
+    elements = dict([(element["name"], element) for element in classinfos["elements"]])
+    
+    def loadXMLTreeMethod(self, tree, extras=[], derived=False):
+        self.extraAttrs = {}
+        self.compatibility(tree)
+        if not derived:
+            children_structure = ""
+            for node in tree.childNodes:
+                if not (node.nodeName == "#text" and node.data.strip() == "") and node.nodeName != "#comment":
+                    children_structure += "%s " % node.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):
+                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 not attrname in extras and not self.extraAttrs.has_key(attrname):
+                self.extraAttrs[attrname] = GetAttributeValue(attr)
+            required_attributes.pop(attrname, None)
+        if len(required_attributes) > 0:
+            raise ValueError("Required attributes %s missing for \"%s\" element!" % (", ".join(["\"%s\""%name for name in required_attributes]), tree.nodeName))
+        first = {}
+        for node in tree.childNodes:
+            name = node.nodeName
+            if name == "#text" and node.data.strip() == "" or name == "#comment":
+                continue
+            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):
+                        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:
+                    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):
+                        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:
+                    object.__setattr__(self, "text", elements["text"]["elmt_type"]["extract"](node))
+            elif elements.has_key("content"):
+                if name in ["#cdata-section", "#text"]:
+                    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:
+                        object.__setattr__(self, "content", elements["content"]["elmt_type"]["extract"](node, content))
+    return loadXMLTreeMethod
+        
+
+"""
+Method that generates the method for generating an xml text by following the
+attributes list defined
+"""
+def generateGenerateXMLText(factory, classinfos):
+    def generateXMLTextMethod(self, name, indent=0, extras={}, derived=False):
+        ind1, ind2 = getIndent(indent, name)
+        if not derived:
+            text = ind1 + u'<%s' % name
+        else:
+            text = u''
+        
+        first = True
+        
+        if not classinfos.has_key("base"):
+            extras.update(self.extraAttrs)
+            for attr, value in extras.iteritems():
+                if not first and not self.singleLineAttributes:
+                    text += u'\n%s' % (ind2)
+                text += u' %s=%s' % (attr, quoteattr(value))
+                first = False
+            extras.clear()
+        for attr in classinfos["attributes"]:
+            if attr["use"] != "prohibited":
+                attr["attr_type"] = FindTypeInfos(factory, attr["attr_type"])
+                value = getattr(self, attr["name"], None)
+                if value != None:
+                    computed_value = attr["attr_type"]["generate"](value)
+                else:
+                    computed_value = None
+                if attr["use"] != "optional" or (value != None and \
+                   computed_value != attr.get("default", attr["attr_type"]["generate"](attr["attr_type"]["initial"]()))):
+                    if classinfos.has_key("base"):
+                        extras[attr["name"]] = computed_value
+                    else:
+                        if not first and not self.singleLineAttributes:
+                            text += u'\n%s' % (ind2)
+                        text += ' %s=%s' % (attr["name"], quoteattr(computed_value))
+                    first = False
+        if classinfos.has_key("base"):
+            first, new_text = classinfos["base"].generateXMLText(self, name, indent, extras, True)
+            text += new_text
+        else:
+            first = True
+        for element in classinfos["elements"]:
+            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:
+                    if first:
+                        text += u'>\n'
+                        first = False
+                    text += element["elmt_type"]["generate"](value, element["name"], indent + 1)
+            elif element["minOccurs"] == 1 and element["maxOccurs"] == 1:
+                if first:
+                    text += u'>\n'
+                    first = False
+                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'
+                    first = False
+                for item in value:
+                    text += element["elmt_type"]["generate"](item, element["name"], indent + 1)
+        if not derived:
+            if first:
+                text += u'/>\n'
+            else:
+                text += ind1 + u'</%s>\n' % (name)
+            return text
+        else:
+            return first, text
+    return generateXMLTextMethod
+
+def gettypeinfos(name, facets):
+    if facets.has_key("enumeration") and facets["enumeration"][0] is not None:
+        return facets["enumeration"][0]
+    elif facets.has_key("maxInclusive"):
+        limits = {"max" : None, "min" : None}
+        if facets["maxInclusive"][0] is not None:
+            limits["max"] = facets["maxInclusive"][0]
+        elif facets["maxExclusive"][0] is not None:
+            limits["max"] = facets["maxExclusive"][0] - 1
+        if facets["minInclusive"][0] is not None:
+            limits["min"] = facets["minInclusive"][0]
+        elif facets["minExclusive"][0] is not None:
+            limits["min"] = facets["minExclusive"][0] + 1
+        if limits["max"] is not None or limits["min"] is not None:
+            return limits
+    return name
+
+def generateGetElementAttributes(factory, classinfos):
+    def getElementAttributes(self):
+        attr_list = []
+        if classinfos.has_key("base"):
+            attr_list.extend(classinfos["base"].getElementAttributes(self))
+        for attr in classinfos["attributes"]:
+            if attr["use"] != "prohibited":
+                attr_params = {"name" : attr["name"], "use" : attr["use"], 
+                    "type" : gettypeinfos(attr["attr_type"]["basename"], attr["attr_type"]["facets"]),
+                    "value" : getattr(self, attr["name"], "")}
+                attr_list.append(attr_params)
+        return attr_list
+    return getElementAttributes
+
+def generateGetElementInfos(factory, classinfos):
+    attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
+    elements = dict([(element["name"], element) for element in classinfos["elements"]])
+    
+    def getElementInfos(self, name, path=None, derived=False):
+        attr_type = "element"
+        value = None
+        use = "required"
+        children = []
+        if path is not None:
+            parts = path.split(".", 1)
+            if attributes.has_key(parts[0]):
+                if len(parts) != 0:
+                    raise ValueError("Wrong path!")
+                attr_type = gettypeinfos(attributes[parts[0]]["attr_type"]["basename"], 
+                                         attributes[parts[0]]["attr_type"]["facets"])
+                value = getattr(self, parts[0], "")
+            elif elements.has_key(parts[0]):
+                if elements[parts[0]]["elmt_type"]["type"] == SIMPLETYPE:
+                    if len(parts) != 0:
+                        raise ValueError("Wrong path!")
+                    attr_type = gettypeinfos(elements[parts[0]]["elmt_type"]["basename"], 
+                                             elements[parts[0]]["elmt_type"]["facets"])
+                    value = getattr(self, parts[0], "")
+                elif parts[0] == "content":
+                    return self.content["value"].getElementInfos(self.content["name"], path)
+                else:
+                    attr = getattr(self, parts[0], None)
+                    if attr is None:
+                        raise ValueError("Wrong path!")
+                    if len(parts) == 1:
+                        return attr.getElementInfos(parts[0])
+                    else:
+                        return attr.getElementInfos(parts[0], parts[1])
+            else:
+                raise ValueError("Wrong path!")
+        else:
+            if not derived:
+                children.extend(self.getElementAttributes())
+            if classinfos.has_key("base"):
+                children.extend(classinfos["base"].getElementInfos(self, name, derived=True)["children"])
+            for element_name, element in elements.items():
+                if element["minOccurs"] == 0:
+                    use = "optional"
+                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:
+                            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"], 
+                                             element["elmt_type"]["facets"]),
+                        "value": getattr(self, element_name, None)})
+                else:
+                    instance = getattr(self, element_name, None)
+                    if instance is None:
+                        instance = element["elmt_type"]["initial"]()
+                    children.append(instance.getElementInfos(element_name))
+        return {"name": name, "type": attr_type, "value": value, "use": use, "children": children}
+    return getElementInfos
+
+def generateSetElementValue(factory, classinfos):
+    attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
+    elements = dict([(element["name"], element) for element in classinfos["elements"]])
+    
+    def setElementValue(self, path, value):
+        if path is not None:
+            parts = path.split(".", 1)
+            if attributes.has_key(parts[0]):
+                if len(parts) != 1:
+                    raise ValueError("Wrong path!")
+                if attributes[parts[0]]["attr_type"]["basename"] == "boolean":
+                    setattr(self, parts[0], value)
+                else:
+                    setattr(self, parts[0], attributes[parts[0]]["attr_type"]["extract"](value, False))
+            elif elements.has_key(parts[0]):
+                if elements[parts[0]]["elmt_type"]["type"] == SIMPLETYPE:
+                    if len(parts) != 1:
+                        raise ValueError("Wrong path!")
+                    if elements[parts[0]]["elmt_type"]["basename"] == "boolean":
+                        setattr(self, parts[0], value)
+                    else:
+                        setattr(self, parts[0], elements[parts[0]]["elmt_type"]["extract"](value, False))
+                else:
+                    instance = getattr(self, parts[0], None)
+                    if instance is None and elements[parts[0]]["minOccurs"] == 0:
+                        instance = elements[parts[0]]["elmt_type"]["initial"]()
+                        setattr(self, parts[0], instance)
+                    if instance != None:
+                        if len(parts) > 1:
+                            instance.setElementValue(parts[1], value)
+                        else:
+                            instance.setElementValue(None, value)
+            elif elements.has_key("content"):
+                if len(parts) > 0:
+                    self.content["value"].setElementValue(path, value)
+            elif classinfos.has_key("base"):
+                classinfos["base"].setElementValue(self, path, value)
+        elif elements.has_key("content"):
+            if value == "":
+                if elements["content"]["minOccurs"] == 0:
+                    self.setcontent(None)
+                else:
+                    raise ValueError("\"content\" element is required!")
+            else:
+                self.setcontentbytype(value)
+    return setElementValue
+
+"""
+Methods that generates the different methods for setting and getting the attributes
+"""
+def generateInitMethod(factory, classinfos):
+    def initMethod(self):
+        self.extraAttrs = {}
+        if classinfos.has_key("base"):
+            classinfos["base"].__init__(self)
+        for attribute in classinfos["attributes"]:
+            attribute["attr_type"] = FindTypeInfos(factory, attribute["attr_type"])
+            if attribute["use"] == "required":
+                setattr(self, attribute["name"], attribute["attr_type"]["initial"]())
+            elif attribute["use"] == "optional":
+                if attribute.has_key("default"):
+                    setattr(self, attribute["name"], attribute["attr_type"]["extract"](attribute["default"], False))
+                else:
+                    setattr(self, attribute["name"], None)
+        for element in classinfos["elements"]:
+            setattr(self, element["name"], GetElementInitialValue(factory, element))
+    return initMethod
+
+def generateSetMethod(attr):
+    def setMethod(self, value):
+        setattr(self, attr, value)
+    return setMethod
+
+def generateGetMethod(attr):
+    def getMethod(self):
+        return getattr(self, attr, None)
+    return getMethod
+
+def generateAddMethod(attr, factory, infos):
+    def addMethod(self):
+        if infos["type"] == ATTRIBUTE:
+            infos["attr_type"] = FindTypeInfos(factory, infos["attr_type"])
+            initial = infos["attr_type"]["initial"]
+            extract = infos["attr_type"]["extract"]
+        elif infos["type"] == ELEMENT:
+            infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
+            initial = infos["elmt_type"]["initial"]
+            extract = infos["elmt_type"]["extract"]
+        else:
+            raise ValueError("Invalid class attribute!")
+        if infos.has_key("default"):
+            setattr(self, attr, extract(infos["default"], False))
+        else:
+            setattr(self, attr, initial())
+    return addMethod
+
+def generateDeleteMethod(attr):
+    def deleteMethod(self):
+        setattr(self, attr, None)
+    return deleteMethod
+
+def generateAppendMethod(attr, maxOccurs, factory, infos):
+    def appendMethod(self, value):
+        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):
+                attr_list.append(value)
+            else:
+                raise ValueError("\"%s\" value isn't valid!" % attr)
+        else:
+            raise ValueError("There can't be more than %d values in \"%s\"!" % (maxOccurs, attr))
+    return appendMethod
+
+def generateInsertMethod(attr, maxOccurs, factory, infos):
+    def insertMethod(self, index, value):
+        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):
+                attr_list.insert(index, value)
+            else:
+                raise ValueError("\"%s\" value isn't valid!" % attr)
+        else:
+            raise ValueError("There can't be more than %d values in \"%s\"!" % (maxOccurs, attr))
+    return insertMethod
+
+def generateGetChoicesMethod(choice_types):
+    def getChoicesMethod(self):
+        return [choice["name"] for choice in choice_types]
+    return getChoicesMethod
+
+def generateSetChoiceByTypeMethod(factory, choice_types):
+    choices = dict([(choice["name"], choice) for choice in choice_types])
+    def setChoiceMethod(self, type):
+        if not choices.has_key(type):
+            raise ValueError("Unknown \"%s\" choice type for \"content\"!" % type)
+        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
+    return setChoiceMethod
+
+def generateAppendChoiceByTypeMethod(maxOccurs, factory, choice_types):
+    choices = dict([(choice["name"], choice) for choice in choice_types])
+    def appendChoiceMethod(self, type):
+        if not choices.has_key(type):
+            raise ValueError("Unknown \"%s\" choice type for \"content\"!" % type)
+        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})
+            return new_element
+        else:
+            raise ValueError("There can't be more than %d values in \"content\"!" % maxOccurs)
+    return appendChoiceMethod
+
+def generateInsertChoiceByTypeMethod(maxOccurs, factory, choice_types):
+    choices = dict([(choice["name"], choice) for choice in choice_types])
+    def insertChoiceMethod(self, index, type):
+        if not choices.has_key(type):
+            raise ValueError("Unknown \"%s\" choice type for \"content\"!" % type)
+        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})
+            return new_element
+        else:
+            raise ValueError("There can't be more than %d values in \"content\"!" % maxOccurs)
+    return insertChoiceMethod
+
+def generateRemoveMethod(attr, minOccurs):
+    def removeMethod(self, index):
+        attr_list = getattr(self, attr)
+        if len(attr_list) > minOccurs:
+            getattr(self, attr).pop(index)
+        else:
+            raise ValueError("There can't be less than %d values in \"%s\"!" % (minOccurs, attr))
+    return removeMethod
+
+def generateCountMethod(attr):
+    def countMethod(self):
+        return len(getattr(self, attr))
+    return countMethod
+
+"""
+This function generate the classes from a class factory
+"""
+def GenerateClasses(factory):
+    ComputedClasses = factory.CreateClasses()
+    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
+