xmlclass/xsdschema.py
author Laurent Bessard
Tue, 23 Apr 2013 12:50:53 +0200
changeset 1048 b450202605ab
parent 814 5743cbdff669
child 1078 f0ea86d830ed
permissions -rw-r--r--
Fixed bug in program elements computation order in PLCGenerator
#!/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, re
import datetime
from xml.dom import minidom
from types import *

from xmlclass import *

def GenerateDictFacets(facets):
    return dict([(name, (None, False)) for name in facets])

def GenerateSimpleTypeXMLText(function):
    def generateXMLTextMethod(value, name=None, indent=0):
        text = ""
        if name is not None:
            ind1, ind2 = getIndent(indent, name)
            text += ind1 + "<%s>" % name
        text += function(value)
        if name is not None:
            text += "</%s>\n" % name
        return text
    return generateXMLTextMethod

def GenerateFloatXMLText(extra_values=[]):
    def generateXMLTextMethod(value, name=None, indent=0):
        text = ""
        if name is not None:
            ind1, ind2 = getIndent(indent, name)
            text += ind1 + "<%s>" % name
        if value in extra_values or value % 1 != 0 or isinstance(value, IntType):
            text += str(value)
        else:
            text += "%.0f" % value
        if name is not None:
            text += "</%s>\n" % name
        return text
    return generateXMLTextMethod
        
DEFAULT_FACETS = GenerateDictFacets(["pattern", "whiteSpace", "enumeration"])
NUMBER_FACETS = GenerateDictFacets(DEFAULT_FACETS.keys() + ["maxInclusive", "maxExclusive", "minInclusive", "minExclusive"])
DECIMAL_FACETS = GenerateDictFacets(NUMBER_FACETS.keys() + ["totalDigits", "fractionDigits"])
STRING_FACETS = GenerateDictFacets(DEFAULT_FACETS.keys() + ["length", "minLength", "maxLength"])

ALL_FACETS = ["pattern", "whiteSpace", "enumeration", "maxInclusive", 
    "maxExclusive", "minInclusive", "minExclusive", "totalDigits", 
    "fractionDigits", "length", "minLength", "maxLength"]


#-------------------------------------------------------------------------------
#                           Structure reducing functions
#-------------------------------------------------------------------------------


# Documentation elements

def ReduceAppInfo(factory, attributes, elements):
    return {"type": "appinfo", "source": attributes.get("source", None), 
            "content": "\n".join(elements)}


def ReduceDocumentation(factory, attributes, elements):
    return {"type": "documentation", "source": attributes.get("source", None), 
            "language": attributes.get("lang", "any"), "content": "\n".join(elements)}


def ReduceAnnotation(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    annotation = {"type": "annotation", "appinfo": [], "documentation": {}}
    for child in children:
        if child["type"] == "appinfo":
            annotation["appinfo"].append((child["source"], child["content"]))
        elif child["type"] == "documentation":
            if child["source"] is not None:
                text = "(source: %(source)s):\n%(content)s\n\n"%child
            else:
                text = child["content"] + "\n\n"
            if not annotation["documentation"].has_key(child["language"]):
                annotation["documentation"] = text
            else:
                annotation["documentation"] += text
    return annotation

# Simple type elements

def GenerateFacetReducing(facetname, canbefixed):
    def ReduceFacet(factory, attributes, elements):
        annotations, children = factory.ReduceElements(elements)
        if attributes.has_key("value"):
            facet = {"type": facetname, "value": attributes["value"], "doc": annotations}
            if canbefixed:
                facet["fixed"] = attributes.get("fixed", False)
            return facet
        raise ValueError("A value must be defined for the \"%s\" facet!" % facetname)
    return ReduceFacet


def ReduceList(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    list = {"type": "list", "itemType": attributes.get("itemType", None), "doc": annotations}
    
    if len(children) > 0 and children[0]["type"] == SIMPLETYPE:
        if list["itemType"] is None:
            list["itemType"] = children[0]
        else:
            raise ValueError("Only one base type can be defined for restriction!")
    if list["itemType"] is None:
        raise ValueError("No base type has been defined for list!")
    return list


def ReduceUnion(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    union = {"type": "union", "memberTypes": attributes.get("memberTypes", []), "doc": annotations}
    
    for child in children:
        if child["type"] == SIMPLETYPE:
            union["memberTypes"].appendchild
    if len(union["memberTypes"]) == 0:
        raise ValueError("No base type has been defined for union!")
    return union


def CreateSimpleType(factory, attributes, typeinfos):
    # Initialize type informations
    facets = {}
    simpleType = {"type": SIMPLETYPE, "final": attributes.get("final", [])}
    if attributes.has_key("name"):
        simpleType["name"] = attributes["name"]
    
    if typeinfos["type"] in ["restriction", "extension"]:
        # Search for base type definition
        if isinstance(typeinfos["base"], (StringType, UnicodeType)):
            basetypeinfos = factory.FindSchemaElement(typeinfos["base"], SIMPLETYPE)
            if basetypeinfos is None:
                raise "\"%s\" isn't defined!" % typeinfos["base"] 
        else:
            basetypeinfos = typeinfos["base"]
        
        # Check that base type is a simple type
        if basetypeinfos["type"] != SIMPLETYPE:
            raise ValueError("Base type given isn't a simpleType!")
        
        simpleType["basename"] = basetypeinfos["basename"]
        
        # Check that derivation is allowed
        if basetypeinfos.has_key("final"):
            if "#all" in basetypeinfos["final"]:
                raise ValueError("Base type can't be derivated!")
            if "restriction" in basetypeinfos["final"] and typeinfos["type"] == "restriction":
                raise ValueError("Base type can't be derivated by restriction!")
        
        # Extract simple type facets
        for facet in typeinfos.get("facets", []):
            facettype = facet["type"]
            if not basetypeinfos["facets"].has_key(facettype):
                raise ValueError("\"%s\" facet can't be defined for \"%s\" type!" % (facettype, type))
            elif basetypeinfos["facets"][facettype][1]:
                raise ValueError("\"%s\" facet is fixed on base type!" % facettype)
            value = facet["value"]
            basevalue = basetypeinfos["facets"][facettype][0]
            if facettype in ["enumeration", "pattern"]:
                value = basetypeinfos["extract"](value, False)
                if len(facets) == 0:
                    facets[facettype] = ([value], False)
                    continue
                elif facets.keys() == [facettype]:
                    facets[facettype][0].append(value)
                    continue
                else:
                    raise ValueError("\"%s\" facet can't be defined with another facet type!" % facettype)
            elif facets.has_key("enumeration"):
                raise ValueError("\"enumeration\" facet can't be defined with another facet type!")
            elif facets.has_key("pattern"):
                raise ValueError("\"pattern\" facet can't be defined with another facet type!")
            elif facets.has_key(facettype):
                raise ValueError("\"%s\" facet can't be defined two times!" % facettype)
            elif facettype == "length":
                if facets.has_key("minLength"):
                    raise ValueError("\"length\" and \"minLength\" facets can't be defined at the same time!")
                if facets.has_key("maxLength"):
                    raise ValueError("\"length\" and \"maxLength\" facets can't be defined at the same time!")
                try:
                    value = int(value)
                except:
                    raise ValueError("\"length\" must be an integer!")
                if value < 0:
                    raise ValueError("\"length\" can't be negative!")
                elif basevalue is not None and basevalue != value:
                    raise ValueError("\"length\" can't be different from \"length\" defined in base type!")
            elif facettype == "minLength":
                if facets.has_key("length"):
                    raise ValueError("\"length\" and \"minLength\" facets can't be defined at the same time!")
                try:
                    value = int(value)
                except:
                    raise ValueError("\"minLength\" must be an integer!")
                if value < 0:
                    raise ValueError("\"minLength\" can't be negative!")
                elif facets.has_key("maxLength") and value > facets["maxLength"]:
                    raise ValueError("\"minLength\" must be lesser than or equal to \"maxLength\"!")
                elif basevalue is not None and basevalue < value:
                    raise ValueError("\"minLength\" can't be lesser than \"minLength\" defined in base type!")
            elif facettype == "maxLength":
                if facets.has_key("length"):
                    raise ValueError("\"length\" and \"maxLength\" facets can't be defined at the same time!")
                try:
                    value = int(value)
                except:
                    raise ValueError("\"maxLength\" must be an integer!")
                if value < 0:
                    raise ValueError("\"maxLength\" can't be negative!")
                elif facets.has_key("minLength") and value < facets["minLength"]:
                    raise ValueError("\"minLength\" must be lesser than or equal to \"maxLength\"!")
                elif basevalue is not None and basevalue > value:
                    raise ValueError("\"maxLength\" can't be greater than \"maxLength\" defined in base type!")
            elif facettype == "minInclusive":
                if facets.has_key("minExclusive"):
                    raise ValueError("\"minExclusive\" and \"minInclusive\" facets can't be defined at the same time!")
                value = basetypeinfos["extract"](facet["value"], False)
                if facets.has_key("maxInclusive") and value > facets["maxInclusive"][0]:
                    raise ValueError("\"minInclusive\" must be lesser than or equal to \"maxInclusive\"!")
                elif facets.has_key("maxExclusive") and value >= facets["maxExclusive"][0]:
                    raise ValueError("\"minInclusive\" must be lesser than \"maxExclusive\"!")
            elif facettype == "minExclusive":
                if facets.has_key("minInclusive"):
                    raise ValueError("\"minExclusive\" and \"minInclusive\" facets can't be defined at the same time!")
                value = basetypeinfos["extract"](facet["value"], False)
                if facets.has_key("maxInclusive") and value >= facets["maxInclusive"][0]:
                    raise ValueError("\"minExclusive\" must be lesser than \"maxInclusive\"!")
                elif facets.has_key("maxExclusive") and value >= facets["maxExclusive"][0]:
                    raise ValueError("\"minExclusive\" must be lesser than \"maxExclusive\"!")
            elif facettype == "maxInclusive":
                if facets.has_key("maxExclusive"):
                    raise ValueError("\"maxExclusive\" and \"maxInclusive\" facets can't be defined at the same time!")
                value = basetypeinfos["extract"](facet["value"], False)
                if facets.has_key("minInclusive") and value < facets["minInclusive"][0]:
                    raise ValueError("\"minInclusive\" must be lesser than or equal to \"maxInclusive\"!")
                elif facets.has_key("minExclusive") and value <= facets["minExclusive"][0]:
                    raise ValueError("\"minExclusive\" must be lesser than \"maxInclusive\"!")
            elif facettype == "maxExclusive":
                if facets.has_key("maxInclusive"):
                    raise ValueError("\"maxExclusive\" and \"maxInclusive\" facets can't be defined at the same time!")
                value = basetypeinfos["extract"](facet["value"], False)
                if facets.has_key("minInclusive") and value <= facets["minInclusive"][0]:
                    raise ValueError("\"minInclusive\" must be lesser than \"maxExclusive\"!")
                elif facets.has_key("minExclusive") and value <= facets["minExclusive"][0]:
                    raise ValueError("\"minExclusive\" must be lesser than \"maxExclusive\"!")
            elif facettype == "whiteSpace":
                if basevalue == "collapse" and value in ["preserve", "replace"] or basevalue == "replace" and value == "preserve":
                   raise ValueError("\"whiteSpace\" is incompatible with \"whiteSpace\" defined in base type!")
            elif facettype == "totalDigits":
                if facets.has_key("fractionDigits") and value <= facets["fractionDigits"][0]:
                    raise ValueError("\"fractionDigits\" must be lesser than or equal to \"totalDigits\"!")
                elif basevalue is not None and value > basevalue:
                    raise ValueError("\"totalDigits\" can't be greater than \"totalDigits\" defined in base type!")
            elif facettype == "fractionDigits":
                if facets.has_key("totalDigits") and value <= facets["totalDigits"][0]:
                    raise ValueError("\"fractionDigits\" must be lesser than or equal to \"totalDigits\"!")
                elif basevalue is not None and value > basevalue:
                    raise ValueError("\"totalDigits\" can't be greater than \"totalDigits\" defined in base type!")
            facets[facettype] = (value, facet.get("fixed", False))
        
        # Report not redefined facet from base type to new created type 
        for facettype, facetvalue in basetypeinfos["facets"].items():
            if not facets.has_key(facettype):
                facets[facettype] = facetvalue
        
        # Generate extract value for new created type
        def ExtractSimpleTypeValue(attr, extract=True):
            value = basetypeinfos["extract"](attr, extract)
            for facetname, (facetvalue, facetfixed) in facets.items():
                if facetvalue is not None:
                    if facetname == "enumeration" and value not in facetvalue:
                        raise ValueError("\"%s\" not in enumerated values" % value)
                    elif facetname == "length" and len(value) != facetvalue:
                        raise ValueError("value must have a length of %d" % facetvalue)
                    elif facetname == "minLength" and len(value) < facetvalue:
                        raise ValueError("value must have a length of %d at least" % facetvalue)
                    elif facetname == "maxLength" and len(value) > facetvalue:
                        raise ValueError("value must have a length of %d at most" % facetvalue)
                    elif facetname == "minInclusive" and value < facetvalue:
                        raise ValueError("value must be greater than or equal to %s" % str(facetvalue))
                    elif facetname == "minExclusive" and value <= facetvalue:
                        raise ValueError("value must be greater than %s" % str(facetvalue))
                    elif facetname == "maxInclusive" and value > facetvalue:
                        raise ValueError("value must be lesser than or equal to %s" % str(facetvalue))
                    elif facetname == "maxExclusive"  and value >= facetvalue:
                        raise ValueError("value must be lesser than %s" % str(facetvalue))
                    elif facetname == "pattern":
                        model = re.compile("(?:%s)?$" % "|".join(map(lambda x: "(?:%s)" % x, facetvalue)))
                        result = model.match(value)
                        if result is None:
                            if len(facetvalue) > 1:   
                                raise ValueError("value doesn't follow any of the patterns %s" % ",".join(facetvalue))
                            else:
                                raise ValueError("value doesn't follow the pattern %s" % facetvalue[0])
                    elif facetname == "whiteSpace":
                        if facetvalue == "replace":
                            value = GetNormalizedString(value, False)
                        elif facetvalue == "collapse":
                            value = GetToken(value, False)
            return value
        
        def CheckSimpleTypeValue(value):
            for facetname, (facetvalue, facetfixed) in facets.items():
                if facetvalue is not None:
                    if facetname == "enumeration" and value not in facetvalue:
                        return False
                    elif facetname == "length" and len(value) != facetvalue:
                        return False
                    elif facetname == "minLength" and len(value) < facetvalue:
                        return False
                    elif facetname == "maxLength" and len(value) > facetvalue:
                        return False
                    elif facetname == "minInclusive" and value < facetvalue:
                        return False
                    elif facetname == "minExclusive" and value <= facetvalue:
                        return False
                    elif facetname == "maxInclusive" and value > facetvalue:
                        return False
                    elif facetname == "maxExclusive"  and value >= facetvalue:
                        return False
                    elif facetname == "pattern":
                        model = re.compile("(?:%s)?$" % "|".join(map(lambda x: "(?:%s)" % x, facetvalue)))
                        result = model.match(value)
                        if result is None:
                            if len(facetvalue) > 1:   
                                raise ValueError("value doesn't follow any of the patterns %s" % ",".join(facetvalue))
                            else:
                                raise ValueError("value doesn't follow the pattern %s" % facetvalue[0])
            return True
        
        def SimpleTypeInitialValue():
            for facetname, (facetvalue, facetfixed) in facets.items():
                if facetvalue is not None:
                    if facetname == "enumeration":
                        return facetvalue[0]
                    elif facetname == "length":
                        return " "*facetvalue
                    elif facetname == "minLength":
                        return " "*minLength
                    elif facetname == "minInclusive" and facetvalue > 0:
                        return facetvalue
                    elif facetname == "minExclusive" and facetvalue >= 0:
                        return facetvalue + 1
                    elif facetname == "maxInclusive" and facetvalue < 0:
                        return facetvalue
                    elif facetname == "maxExclusive"  and facetvalue <= 0:
                        return facetvalue - 1
            return basetypeinfos["initial"]()
        
        GenerateSimpleType = basetypeinfos["generate"]
        
    elif typeinfos["type"] == "list":
        # Search for item type definition
        if isinstance(typeinfos["itemType"], (StringType, UnicodeType)):
            itemtypeinfos = factory.FindSchemaElement(typeinfos["itemType"], SIMPLETYPE)
            if itemtypeinfos is None:
                raise "\"%s\" isn't defined!" % typeinfos["itemType"]
        else:
            itemtypeinfos = typeinfos["itemType"]
        
        # Check that item type is a simple type
        if itemtypeinfos["type"] != SIMPLETYPE:
            raise ValueError, "Item type given isn't a simpleType!"
        
        simpleType["basename"] = "list"
        
        # Check that derivation is allowed
        if itemtypeinfos.has_key("final"):
            if itemtypeinfos["final"].has_key("#all"):
                raise ValueError("Item type can't be derivated!")
            if itemtypeinfos["final"].has_key("list"):
                raise ValueError("Item type can't be derivated by list!")
        
        # Generate extract value for new created type
        def ExtractSimpleTypeValue(attr, extract = True):
            values = []
            for value in GetToken(attr, extract).split(" "):
                values.append(itemtypeinfos["extract"](value, False))
            return values
        
        def CheckSimpleTypeValue(value):
            for item in value:
                result = itemtypeinfos["check"](item)
                if not result:
                    return result
            return True
        
        SimpleTypeInitialValue = lambda: []
        
        GenerateSimpleType = GenerateSimpleTypeXMLText(lambda x: " ".join(map(itemtypeinfos["generate"], x)))
        
        facets = GenerateDictFacets(["length", "maxLength", "minLength", "enumeration", "pattern"])
        facets["whiteSpace"] = ("collapse", False)
    
    elif typeinfos["type"] == "union":
        # Search for member types definition
        membertypesinfos = []
        for membertype in typeinfos["memberTypes"]:
            if isinstance(membertype, (StringType, UnicodeType)):
                infos = factory.FindSchemaElement(membertype, SIMPLETYPE)
                if infos is None:
                    raise ValueError("\"%s\" isn't defined!" % membertype)
            else:
                infos = membertype
            
            # Check that member type is a simple type
            if infos["type"] != SIMPLETYPE:
                raise ValueError("Member type given isn't a simpleType!")
            
            # Check that derivation is allowed
            if infos.has_key("final"):
                if infos["final"].has_key("#all"):
                    raise ValueError("Item type can't be derivated!")
                if infos["final"].has_key("union"):
                    raise ValueError("Member type can't be derivated by union!")
            
            membertypesinfos.append(infos)
        
        simpleType["basename"] = "union"
        
        # Generate extract value for new created type
        def ExtractSimpleTypeValue(attr, extract = True):
            if extract:
                value = GetAttributeValue(attr)
            else:
                value = attr
            for infos in membertypesinfos:
                try:
                    return infos["extract"](attr, False)
                except:
                    pass
            raise ValueError("\"%s\" isn't valid for type defined for union!")
        
        def CheckSimpleTypeValue(value):
            for infos in membertypesinfos:
                result = infos["check"](value)
                if result:
                    return result
            return False
        
        SimpleTypeInitialValue = membertypesinfos[0]["initial"]
        
        def GenerateSimpleTypeFunction(value):
            if isinstance(value, BooleanType):
                return {True: "true", False: "false"}[value]
            else:
                return str(value)
        GenerateSimpleType = GenerateSimpleTypeXMLText(GenerateSimpleTypeFunction)
        
        facets = GenerateDictFacets(["pattern", "enumeration"])
    
    simpleType["facets"] = facets
    simpleType["extract"] = ExtractSimpleTypeValue
    simpleType["initial"] = SimpleTypeInitialValue
    simpleType["check"] = CheckSimpleTypeValue
    simpleType["generate"] = GenerateSimpleType
    return simpleType

def ReduceSimpleType(factory, attributes, elements):
    # Reduce all the simple type children
    annotations, children = factory.ReduceElements(elements)
    
    simpleType = CreateSimpleType(factory, attributes, children[0])
    simpleType["doc"] = annotations
    
    return simpleType

# Complex type

def ExtractAttributes(factory, elements, base=None):
    attrs = []
    attrnames = {}
    if base is not None:
        basetypeinfos = factory.FindSchemaElement(base)
        if not isinstance(basetypeinfos, (UnicodeType, StringType)) and basetypeinfos["type"] == COMPLEXTYPE:
            attrnames = dict(map(lambda x:(x["name"], True), basetypeinfos["attributes"]))
        
    for element in elements:
        if element["type"] == ATTRIBUTE:
            if attrnames.get(element["name"], False):
                raise ValueError("\"%s\" attribute has been defined two times!" % element["name"])
            else:
                attrnames[element["name"]] = True
                attrs.append(element)
        elif element["type"] == "attributeGroup":
            attrgroup = factory.FindSchemaElement(element["ref"], ATTRIBUTESGROUP)
            for attr in attrgroup["attributes"]:
                if attrnames.get(attr["name"], False):
                    raise ValueError("\"%s\" attribute has been defined two times!" % attr["name"])
                else:
                    attrnames[attr["name"]] = True
                    attrs.append(attr)
        elif element["type"] == "anyAttribute":
            raise ValueError("\"anyAttribute\" element isn't supported yet!")
    return attrs


def ReduceRestriction(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    restriction = {"type": "restriction", "base": attributes.get("base", None), "facets": [], "doc": annotations}
    if len(children) > 0 and children[0]["type"] == SIMPLETYPE:
        if restriction["base"] is None:
            restriction["base"] = children.pop(0)
        else:
            raise ValueError("Only one base type can be defined for restriction!")
    if restriction["base"] is None:
        raise ValueError("No base type has been defined for restriction!")
    
    while len(children) > 0 and children[0]["type"] in ALL_FACETS:
        restriction["facets"].append(children.pop(0))
    restriction["attributes"] = ExtractAttributes(factory, children, restriction["base"])
    return restriction


def ReduceExtension(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    if not attributes.has_key("base"):
        raise ValueError("No base type has been defined for extension!")
    extension = {"type": "extension", "attributes": [], "elements": [], "base": attributes["base"], "doc": annotations}
    if len(children) > 0:
        if children[0]["type"] in ["group", "all", CHOICE, "sequence"]:
            group = children.pop(0)
            if group["type"] in ["all", "sequence"]:
                extension["elements"] = group["elements"]
                extension["order"] = group["order"]
            elif group["type"] == CHOICE:
                content = group.copy()
                content["name"] = "content"
                extension["elements"].append(content)
            elif group["type"] == "group":
                elmtgroup = factory.FindSchemaElement(child["ref"], ELEMENTSGROUP)
                if elmtgroup.has_key("elements"):
                    extension["elements"] = elmtgroup["elements"]
                    extension["order"] = elmtgroup["order"]
                else:
                    content = elmtgroup.copy()
                    content["name"] = "content"
                    extension["elements"].append(content)
        extension["attributes"] = ExtractAttributes(factory, children)
    return extension


def ReduceSimpleContent(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    
    simpleContent = children[0].copy()
    
    basetypeinfos = factory.FindSchemaElement(simpleContent["base"])
    if basetypeinfos["type"] == SIMPLETYPE:
        contenttypeinfos = simpleContent.copy()
        simpleContent.pop("base")
    elif basetypeinfos["type"] == COMPLEXTYPE and \
         len(basetypeinfos["elements"]) == 1 and \
         basetypeinfos["elements"][0]["name"] == "content" and \
         basetypeinfos["elements"][0].has_key("elmt_type") and \
         basetypeinfos["elements"][0]["elmt_type"]["type"] == SIMPLETYPE:
        contenttypeinfos = simpleContent.copy()
        contenttypeinfos["base"] = basetypeinfos["elements"][0]["elmt_type"]
    else:
        raise ValueError("No compatible base type defined for simpleContent!")
    contenttypeinfos = CreateSimpleType(factory, attributes, contenttypeinfos)
    
    simpleContent["elements"] = [{"name": "content", "type": ELEMENT,
                                  "elmt_type": contenttypeinfos, "doc": annotations,
                                  "minOccurs": 1, "maxOccurs": 1}]
    simpleContent["type"] = "simpleContent"
    return simpleContent


def ReduceComplexContent(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    complexContent = children[0].copy()
    complexContent["type"] = "complexContent"
    return complexContent


def ReduceComplexType(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    
    if len(children) > 0:
        if children[0]["type"] in ["simpleContent", "complexContent"]:
            complexType = children[0].copy()
            complexType.update(attributes)
            complexType["type"] = COMPLEXTYPE
            return complexType
        elif children[0]["type"] in ["group", "all", CHOICE, "sequence"]:
            complexType = {"type": COMPLEXTYPE, "elements": [], "order": True, "doc": annotations}
            complexType.update(attributes)
            group = children.pop(0)
            if group["type"] in ["all", "sequence"]:
                choice_number = 0
                for element in group["elements"]:
                    if element["type"] == CHOICE:
                        choice_number += 1
                if (group["minOccurs"] == 0 or group["maxOccurs"] != 1) and len(group["elements"]) > 1 or choice_number > 1:
                    content = {"type": CHOICE, "name": "content", "choices": [group], "minOccurs": 1, "maxOccurs": 1}
                    complexType["elements"].append(content)
                else:
                    if len(group["elements"]) == 1:
                        if group["minOccurs"] == 0:
                            group["elements"][0]["minOccurs"] = group["minOccurs"]
                        if group["maxOccurs"] != 1:
                            group["elements"][0]["maxOccurs"] = group["maxOccurs"]
                    for element in group["elements"]:
                        if element["type"] == CHOICE:
                            element["name"] = "content"
                    complexType["elements"] = group["elements"]
                    complexType["order"] = group["order"]
            elif group["type"] == CHOICE:
                content = group.copy()
                content["name"] = "content"
                complexType["elements"].append(content)
            elif group["type"] == "group":
                elmtgroup = factory.FindSchemaElement(child["ref"], ELEMENTSGROUP)
                if elmtgroup.has_key("elements"):
                    complexType["elements"] = elmtgroup["elements"]
                    complexType["order"] = elmtgroup["order"]
                else:
                    content = elmtgroup.copy()
                    content["name"] = "content"
                    complexType["elements"].append(content)
        else:
            complexType = {"elements": [], "order": True, "doc": annotations}
            complexType.update(attributes)
            complexType["type"] = COMPLEXTYPE
        complexType["attributes"] = ExtractAttributes(factory, children)
        return complexType
    else:
        raise ValueError("\"ComplexType\" can't be empty!")


# Attribute elements

def ReduceAnyAttribute(factory, attributes, elements):
    return {"type" : "anyAttribute"}


def ReduceAttribute(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    
    if attributes.has_key("default"):
        if attributes.has_key("fixed"):
            raise ValueError("\"default\" and \"fixed\" can't be defined at the same time!")
        elif attributes.get("use", "optional") != "optional":
            raise ValueError("if \"default\" present, \"use\" can only have the value \"optional\"!")
    
    attribute = {"type": ATTRIBUTE, "attr_type": attributes.get("type", None), "doc": annotations}
    if len(children) > 0:
        if attribute["attr_type"] is None:
            attribute["attr_type"] = children[0]
        else:
            raise ValueError("Only one type can be defined for attribute!")
    
    if attributes.has_key("ref"):
        if attributes.has_key("name"):
            raise ValueError("\"ref\" and \"name\" can't be defined at the same time!")
        elif attributes.has_key("form"):
            raise ValueError("\"ref\" and \"form\" can't be defined at the same time!")
        elif attribute["attr_type"] is not None:
            raise ValueError("if \"ref\" is present, no type can be defined!")
    elif attribute["attr_type"] is None:
        raise ValueError("No type has been defined for attribute \"%s\"!" % attributes["name"])
    
    if attributes.has_key("type"):
        tmp_attrs = attributes.copy()
        tmp_attrs.pop("type")
        attribute.update(tmp_attrs)
    else:
        attribute.update(attributes)
    return attribute


def ReduceAttributeGroup(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    if attributes.has_key("ref"):
        return {"type": "attributeGroup", "ref": attributes["ref"], "doc": annotations}
    else:
        return {"type": ATTRIBUTESGROUP, "attributes": ExtractAttributes(factory, children), "doc": annotations}


# Elements groups

def ReduceAny(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    
    any = {"type": ANY, "doc": annotations}
    any.update(attributes)
    return any

def ReduceElement(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    
    types = []
    constraints = []
    for child in children:
        if child["type"] == CONSTRAINT:
            constraints.append(child)
        else:
            types.append(child)
    
    if attributes.has_key("default") and attributes.has_key("fixed"):
        raise ValueError("\"default\" and \"fixed\" can't be defined at the same time!")
    
    if attributes.has_key("ref"):
        for attr in ["name", "default", "fixed", "form", "block", "type"]:
            if attributes.has_key(attr):
                raise ValueError("\"ref\" and \"%s\" can't be defined at the same time!" % attr)
        if attributes.has_key("nillable"):
            raise ValueError("\"ref\" and \"nillable\" can't be defined at the same time!")
        if len(types) > 0:
            raise ValueError("No type and no constraints can be defined where \"ref\" is defined!")
    
        infos = factory.FindSchemaElement(attributes["ref"], ELEMENT)
        if infos is not None:
            element = infos.copy()
            element["constraints"] = constraints
            element["minOccurs"] = attributes["minOccurs"]
            element["maxOccurs"] = attributes["maxOccurs"]
            return element
        else:
            raise ValueError("\"%s\" base type isn't defined or circular referenced!" % name)
    
    elif attributes.has_key("name"):
        element = {"type": ELEMENT, "elmt_type": attributes.get("type", None), "constraints": constraints, "doc": annotations}
        if len(types) > 0:
            if element["elmt_type"] is None:
                element["elmt_type"] = types[0]
            else:
                raise ValueError("Only one type can be defined for attribute!")
        elif element["elmt_type"] is None:
            element["elmt_type"] = "tag"
            element["type"] = TAG
        
        if attributes.has_key("type"):
            tmp_attrs = attributes.copy()
            tmp_attrs.pop("type")
            element.update(tmp_attrs)
        else:
            element.update(attributes)
        return element
    else:
        raise ValueError("\"Element\" must have at least a \"ref\" or a \"name\" defined!")

def ReduceAll(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    
    for child in children:
        if children["maxOccurs"] == "unbounded" or children["maxOccurs"] > 1:
            raise ValueError("\"all\" item can't have \"maxOccurs\" attribute greater than 1!")
    
    return {"type": "all", "elements": children, "minOccurs": attributes["minOccurs"],
            "maxOccurs": attributes["maxOccurs"], "order": False, "doc": annotations}


def ReduceChoice(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    
    choices = []
    for child in children:
        if child["type"] in [ELEMENT, ANY, TAG]:
            choices.append(child)
        elif child["type"] == "sequence":
            child["minOccurs"] = child["maxOccurs"] = 1
            choices.append(child)
            #raise ValueError("\"sequence\" in \"choice\" is not supported. Create instead a new complex type!")
        elif child["type"] == CHOICE:
            choices.extend(child["choices"])
        elif child["type"] == "group":
            elmtgroup = factory.FindSchemaElement(child["ref"], ELEMENTSGROUP) 
            if not elmtgroup.has_key("choices"):
                raise ValueError("Only group composed of \"choice\" can be referenced in \"choice\" element!")
            choices_tmp = []
            for choice in elmtgroup["choices"]:
                if not isinstance(choice["elmt_type"], (UnicodeType, StringType)) and choice["elmt_type"]["type"] == COMPLEXTYPE:
                    elmt_type = "%s_%s" % (elmtgroup["name"], choice["name"])
                    if factory.TargetNamespace is not None:
                        elmt_type = "%s:%s" % (factory.TargetNamespace, elmt_type)
                    new_choice = choice.copy()
                    new_choice["elmt_type"] = elmt_type
                    choices_tmp.append(new_choice)
                else:
                    choices_tmp.append(choice)
            choices.extend(choices_tmp)
    
    for choice in choices:
        attributes["minOccurs"] = min(attributes["minOccurs"], choice["minOccurs"])
        choice["minOccurs"] = 1
    
    return {"type": CHOICE, "choices": choices, "minOccurs": attributes["minOccurs"],
            "maxOccurs": attributes["maxOccurs"], "doc": annotations}


def ReduceSequence(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    
    sequence = []
    for child in children:
        if child["type"] in [ELEMENT, ANY, TAG, CHOICE]:
            sequence.append(child)
        elif child["type"] == "sequence":
            sequence.extend(child["elements"])
        elif child["type"] == "group":
            elmtgroup = factory.FindSchemaElement(child["ref"], ELEMENTSGROUP)
            if not elmtgroup.has_key("elements") or not elmtgroup["order"]:
                raise ValueError("Only group composed of \"sequence\" can be referenced in \"sequence\" element!")
            elements_tmp = []
            for element in elmtgroup["elements"]:
                if not isinstance(element["elmt_type"], (UnicodeType, StringType)) and element["elmt_type"]["type"] == COMPLEXTYPE:
                    elmt_type = "%s_%s"%(elmtgroup["name"], element["name"])
                    if factory.TargetNamespace is not None:
                        elmt_type = "%s:%s" % (factory.TargetNamespace, elmt_type)
                    new_element = element.copy()
                    new_element["elmt_type"] = elmt_type
                    elements_tmp.append(new_element)
                else:
                    elements_tmp.append(element)
            sequence.extend(elements_tmp)
            
    return {"type": "sequence", "elements": sequence, "minOccurs": attributes["minOccurs"],
            "maxOccurs": attributes["maxOccurs"], "order": True, "doc": annotations}
    
    
def ReduceGroup(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    
    if attributes.has_key("ref"):
        return {"type": "group", "ref": attributes["ref"], "doc": annotations}
    else:
        element = children[0]
        group = {"type": ELEMENTSGROUP, "doc": annotations}
        if element["type"] == CHOICE:
            group["choices"] = element["choices"]
        else:
            group.update({"elements": element["elements"], "order": group["order"]})
        group.update(attributes)
        return group

# Constraint elements

def ReduceUnique(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    
    unique = {"type": CONSTRAINT, "const_type": "unique", "selector": children[0], "fields": children[1:]}
    unique.update(attributes)
    return unique
    
def ReduceKey(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    
    key = {"type": CONSTRAINT, "const_type": "key", "selector": children[0], "fields": children[1:]}
    key.update(attributes)
    return key

def ReduceKeyRef(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    
    keyref = {"type": CONSTRAINT, "const_type": "keyref", "selector": children[0], "fields": children[1:]}
    keyref.update(attributes)
    return keyref
    
def ReduceSelector(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    
    selector = {"type": CONSTRAINT, "const_type": "selector"}
    selector.update(attributes)
    return selector

def ReduceField(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    
    field = {"type": CONSTRAINT, "const_type": "field"}
    field.update(attributes)
    return field
    

# Inclusion elements

def ReduceImport(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    raise ValueError("\"import\" element isn't supported yet!")

def ReduceInclude(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    
    if factory.FileName is None:
        raise ValueError("Include in XSD string not yet supported")
    filepath = attributes["schemaLocation"]
    if filepath is not None and not os.path.exists(filepath):
        filepath = os.path.join(factory.BaseFolder, filepath)
        if not os.path.exists(filepath):
            raise ValueError("No file '%s' found for include" % attributes["schemaLocation"])
    xsdfile = open(filepath, 'r')
    include_factory = XSDClassFactory(minidom.parse(xsdfile), filepath)
    xsdfile.close()
    include_factory.CreateClasses()
    
    if factory.TargetNamespace == include_factory.TargetNamespace:
        factory.Namespaces[factory.TargetNamespace].update(include_factory.Namespaces[include_factory.TargetNamespace])
    else:
        factory.Namespaces[include_factory.TargetNamespace] = include_factory.Namespaces[include_factory.TargetNamespace]
    factory.ComputedClasses.update(include_factory.ComputedClasses)
    return None
    
def ReduceRedefine(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    raise ValueError("\"redefine\" element isn't supported yet!")


# Schema element

def ReduceSchema(factory, attributes, elements):
    factory.AttributeFormDefault = attributes["attributeFormDefault"]
    factory.ElementFormDefault = attributes["elementFormDefault"]
    factory.BlockDefault = attributes["blockDefault"]
    factory.FinalDefault = attributes["finalDefault"]
    
    if attributes.has_key("targetNamespace"):
        factory.TargetNamespace = factory.DefinedNamespaces.get(attributes["targetNamespace"], None)
    factory.Namespaces[factory.TargetNamespace] = {}
    
    annotations, children = factory.ReduceElements(elements, True)
    
    for child in children:
        if child.has_key("name"):
            infos = factory.GetQualifiedNameInfos(child["name"], factory.TargetNamespace, True)
            if infos is None:
                factory.Namespaces[factory.TargetNamespace][child["name"]] = child
            elif not CompareSchema(infos, child):
                raise ValueError("\"%s\" is defined twice in targetNamespace!" % child["name"])

def CompareSchema(schema, reference):
    if isinstance(schema, ListType):
        if not isinstance(reference, ListType) or len(schema) != len(reference):
            return False
        for i, value in enumerate(schema):
            result = CompareSchema(value, reference[i])
            if not result:
                return result
        return True
    elif isinstance(schema, DictType):
        if not isinstance(reference, DictType) or len(schema) != len(reference):
            return False
        for name, value in schema.items():
            ref_value = reference.get(name, None)
            if ref_value is None and value != None:
                return False
            result = CompareSchema(value, ref_value)
            if not result:
                return result
        return True
    elif isinstance(schema, FunctionType):
        if not isinstance(reference, FunctionType) or schema.__name__ != reference.__name__:
            return False
        else:
            return True
    return schema == reference
    
#-------------------------------------------------------------------------------
#                       Base class for XSD schema extraction
#-------------------------------------------------------------------------------


class XSDClassFactory(ClassFactory):

    def __init__(self, document, filepath=None, debug=False):
        ClassFactory.__init__(self, document, filepath, debug)
        self.Namespaces["xml"] = {
            "lang": {
                "type": SYNTAXATTRIBUTE, 
                "extract": {
                    "default": GenerateModelNameExtraction("lang", LANGUAGE_model)
                }
            }
        }
        self.Namespaces["xsi"] = {
            "noNamespaceSchemaLocation": {
                "type": SYNTAXATTRIBUTE, 
                "extract": {
                    "default": NotSupportedYet("noNamespaceSchemaLocation")
                }
            },
            "nil": {
                "type": SYNTAXATTRIBUTE, 
                "extract": {
                    "default": NotSupportedYet("nil")
                }
            },
            "schemaLocation": {
                "type": SYNTAXATTRIBUTE, 
                "extract": {
                    "default": NotSupportedYet("schemaLocation")
                }
            },
            "type": {
                "type": SYNTAXATTRIBUTE, 
                "extract": {
                    "default": NotSupportedYet("type")
                }
            }
        }
        
    def ParseSchema(self):
        for child in self.Document.childNodes:
            if child.nodeType == self.Document.ELEMENT_NODE:
                schema = child
                break
        for qualified_name, attr in schema._attrs.items():
            value = GetAttributeValue(attr)
            if value == "http://www.w3.org/2001/XMLSchema":
                namespace, name = DecomposeQualifiedName(qualified_name)
                if namespace == "xmlns":
                    self.DefinedNamespaces["http://www.w3.org/2001/XMLSchema"] = name
                    self.SchemaNamespace = name
                else:
                    self.DefinedNamespaces["http://www.w3.org/2001/XMLSchema"] = self.SchemaNamespace
                self.Namespaces[self.SchemaNamespace] = XSD_NAMESPACE
        self.Schema = XSD_NAMESPACE["schema"]["extract"]["default"](self, schema)
        ReduceSchema(self, self.Schema[1], self.Schema[2])

    def FindSchemaElement(self, element_name, element_type=None):
        namespace, name = DecomposeQualifiedName(element_name)
        element = self.GetQualifiedNameInfos(name, namespace, True)
        if element is None and namespace == self.TargetNamespace and name not in self.CurrentCompilations:
            self.CurrentCompilations.append(name)
            element = self.CreateSchemaElement(name, element_type)
            self.CurrentCompilations.pop(-1)
            if element is not None:
                self.Namespaces[self.TargetNamespace][name] = element
        if element is None:
            if name in self.CurrentCompilations:
                if self.Debug:
                    print "Warning : \"%s\" is circular referenced!" % element_name
            else:
                raise ValueError("\"%s\" isn't defined!" % element_name)
        if element_type is not None and element["type"] != element_type:
            raise ValueError("\"%s\" isn't of the expected type!" % element_name)
        return element
    
    def CreateSchemaElement(self, element_name, element_type):
        for type, attributes, elements in self.Schema[2]:
            namespace, name = DecomposeQualifiedName(type)
            if attributes.get("name", None) == element_name:
                element_infos = None
                if element_type in (ATTRIBUTE, None) and name == "attribute":
                    element_infos = ReduceAttribute(self, attributes, elements)
                elif element_type in (ELEMENT, None) and name == "element":
                    element_infos = ReduceElement(self, attributes, elements)
                elif element_type in (ATTRIBUTESGROUP, None) and name == "attributeGroup":
                    element_infos = ReduceAttributeGroup(self, attributes, elements)
                elif element_type in (ELEMENTSGROUP, None) and name == "group":
                    element_infos = ReduceGroup(self, attributes, elements)
                elif element_type in (SIMPLETYPE, None) and name == "simpleType":
                    element_infos = ReduceSimpleType(self, attributes, elements)
                elif element_type in (COMPLEXTYPE, None) and name == "complexType":
                    element_infos = ReduceComplexType(self, attributes, elements)
                if element_infos is not None:
                    self.Namespaces[self.TargetNamespace][element_name] = element_infos
                    return element_infos
        return None

"""
This function opens the xsd file and generate the classes from the xml tree
"""
def GenerateClassesFromXSD(filepath):
    xsdfile = open(filepath, 'r')
    factory = XSDClassFactory(minidom.parse(xsdfile), filepath)
    xsdfile.close()
    return GenerateClasses(factory)

"""
This function generate the classes from the xsd given as a string
"""
def GenerateClassesFromXSDstring(xsdstring):
    return GenerateClasses(XSDClassFactory(minidom.parseString(xsdstring)))


#-------------------------------------------------------------------------------
#                           XSD schema syntax elements
#-------------------------------------------------------------------------------

XSD_NAMESPACE = {

#-------------------------------------------------------------------------------
#                           Syntax elements definition
#-------------------------------------------------------------------------------

    "all": {"struct": """
        <all
          id = ID
          maxOccurs = 1 : 1
          minOccurs = (0 | 1) : 1
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, element*)
        </all>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("all", ["id", "maxOccurs", "minOccurs"], 
                re.compile("((?:annotation )?(?:element )*)"))
        },
        "reduce": ReduceAll
    },

    "annotation": {"struct": """
        <annotation
          id = ID
          {any attributes with non-schema namespace . . .}>
          Content: (appinfo | documentation)*
        </annotation>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("annotation", ["id"], 
                re.compile("((?:app_info |documentation )*)"))
        },
        "reduce": ReduceAnnotation
    },

    "any": {"struct": """
        <any
          id = ID
          maxOccurs = (nonNegativeInteger | unbounded)  : 1
          minOccurs = nonNegativeInteger : 1
          namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) )  : ##any
          processContents = (lax | skip | strict) : strict
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </any>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("any", 
                ["id", "maxOccurs", "minOccurs", "namespace", "processContents"], 
                re.compile("((?:annotation )?(?:simpleType )*)"))
        },
        "reduce": ReduceAny
    },

    "anyAttribute": {"struct": """
        <anyAttribute
          id = ID
          namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) )  : ##any
          processContents = (lax | skip | strict) : strict
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </anyAttribute>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("anyAttribute",
                ["id", "namespace", "processContents"], ONLY_ANNOTATION)
        },
        "reduce": ReduceAnyAttribute
    },

    "appinfo": {"struct": """
        <appinfo
          source = anyURI
          {any attributes with non-schema namespace . . .}>
          Content: ({any})*
        </appinfo>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("appinfo", ["source"], re.compile("(.*)"), True)
        },
        "reduce": ReduceAppInfo
    },

    "attribute": {"struct": """
        <attribute
          default = string
          fixed = string
          form = (qualified | unqualified)
          id = ID
          name = NCName
          ref = QName
          type = QName
          use = (optional | prohibited | required) : optional
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, simpleType?)
        </attribute>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("attribute", 
                ["default", "fixed", "form", "id", "name", "ref", "type", "use"], 
                re.compile("((?:annotation )?(?:simpleType )?)")),
            "schema": GenerateElement("attribute", 
                ["default", "fixed", "form", "id", "name", "type"], 
                re.compile("((?:annotation )?(?:simpleType )?)"))
        },
        "reduce": ReduceAttribute
    },

    "attributeGroup": {"struct": """
        <attributeGroup
          id = ID
          name = NCName
          ref = QName
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, ((attribute | attributeGroup)*, anyAttribute?))
        </attributeGroup>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("attributeGroup", 
                ["id", "ref"], ONLY_ANNOTATION),
            "schema": GenerateElement("attributeGroup",
                ["id", "name"], 
                re.compile("((?:annotation )?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?))"))
        },
        "reduce": ReduceAttributeGroup
    },

    "choice": {"struct": """
        <choice
          id = ID
          maxOccurs = (nonNegativeInteger | unbounded)  : 1
          minOccurs = nonNegativeInteger : 1
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, (element | group | choice | sequence | any)*)
        </choice>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("choice", ["id", "maxOccurs", "minOccurs"], 
                re.compile("((?:annotation )?(?:element |group |choice |sequence |any )*)"))
        },
        "reduce": ReduceChoice
    },

    "complexContent": {"struct": """
        <complexContent
          id = ID
          mixed = boolean
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, (restriction | extension))
        </complexContent>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("complexContent", ["id", "mixed"], 
                re.compile("((?:annotation )?(?:restriction |extension ))"))
        },
        "reduce": ReduceComplexContent
    },

    "complexType": {"struct": """
        <complexType
          abstract = boolean : false
          block = (#all | List of (extension | restriction))
          final = (#all | List of (extension | restriction))
          id = ID
          mixed = boolean : false
          name = NCName
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, (simpleContent | complexContent | ((group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?))))
        </complexType>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("complexType", 
                ["abstract", "block", "final", "id", "mixed", "name"], 
                re.compile("((?:annotation )?(?:simpleContent |complexContent |(?:(?:group |all |choice |sequence )?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?))))"))
        },
        "reduce": ReduceComplexType
    },

    "documentation": {"struct" : """
        <documentation
          source = anyURI
          xml:lang = language
          {any attributes with non-schema namespace . . .}>
          Content: ({any})*
        </documentation>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("documentation", 
                ["source", "lang"], re.compile("(.*)"), True)
        },
        "reduce": ReduceDocumentation
    },

    "element": {"struct": """
        <element
          abstract = boolean : false
          block = (#all | List of (extension | restriction | substitution))
          default = string
          final = (#all | List of (extension | restriction))
          fixed = string
          form = (qualified | unqualified)
          id = ID
          maxOccurs = (nonNegativeInteger | unbounded)  : 1
          minOccurs = nonNegativeInteger : 1
          name = NCName
          nillable = boolean : false
          ref = QName
          substitutionGroup = QName
          type = QName
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, ((simpleType | complexType)?, (unique | key | keyref)*))
        </element>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("element", 
                ["abstract", "block", "default", "final", "fixed", "form", "id", "maxOccurs", "minOccurs", "name", "nillable", "ref", "substitutionGroup", "type"], 
                re.compile("((?:annotation )?(?:simpleType |complexType )?(?:unique |key |keyref )*)")),
            "schema": GenerateElement("element", 
                ["abstract", "block", "default", "final", "fixed", "form", "id", "name", "nillable", "substitutionGroup", "type"], 
                re.compile("((?:annotation )?(?:simpleType |complexType )?(?:unique |key |keyref )*)"))
        },
        "reduce": ReduceElement
    },

    "enumeration": {"struct": """
        <enumeration
          id = ID
          value = anySimpleType
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </enumeration>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("enumeration", ["id", "value"], ONLY_ANNOTATION)
        },
        "reduce": GenerateFacetReducing("enumeration", False)
    },

    "extension": {"struct": """
        <extension
          base = QName
          id = ID
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, ((group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?)))
        </extension>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("extension", ["base", "id"], 
                re.compile("((?:annotation )?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?))")),
            "complexContent": GenerateElement("extension", ["base", "id"], 
                re.compile("((?:annotation )?(?:group |all |choice |sequence )?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?))"))
        },
        "reduce": ReduceExtension
    },

    "field": {"struct": """
        <field
          id = ID
          xpath = a subset of XPath expression, see below
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </field>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("field", ["id", "xpath"], ONLY_ANNOTATION)
        },
        "reduce": ReduceField
    },

    "fractionDigits": {"struct": """
        <fractionDigits
          fixed = boolean : false
          id = ID
          value = nonNegativeInteger
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </fractionDigits>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("fractionDigits", 
                ["fixed", "id", "value"], ONLY_ANNOTATION)
        },
        "reduce": GenerateFacetReducing("fractionDigits", True)
    },

    "group": {"struct": """
        <group
          id = ID
          maxOccurs = (nonNegativeInteger | unbounded)  : 1
          minOccurs = nonNegativeInteger : 1
          name = NCName
          ref = QName
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, (all | choice | sequence)?)
        </group>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("group",
                ["id", "maxOccurs", "minOccurs", "ref"], 
                re.compile("((?:annotation )?(?:all |choice |sequence )?)")),
            "schema": GenerateElement("group",
                ["id", "name"], 
                re.compile("((?:annotation )?(?:all |choice |sequence )?)"))
        },
        "reduce": ReduceGroup
    },

    "import": {"struct": """
        <import
          id = ID
          namespace = anyURI
          schemaLocation = anyURI
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </import>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("import",
                ["id", "namespace", "schemaLocation"], ONLY_ANNOTATION)
        },
        "reduce": ReduceImport
    },

    "include": {"struct": """
        <include
          id = ID
          schemaLocation = anyURI
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </include>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("include",
                ["id", "schemaLocation"], ONLY_ANNOTATION)
        },
        "reduce": ReduceInclude
    },

    "key": {"struct": """
        <key
          id = ID
          name = NCName
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, (selector, field+))
        </key>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("key", ["id", "name"], 
                re.compile("((?:annotation )?(?:selector (?:field )+))"))
        },
        "reduce": ReduceKey
    },

    "keyref": {"struct": """
        <keyref
          id = ID
          name = NCName
          refer = QName
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, (selector, field+))
        </keyref>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("keyref", ["id", "name", "refer"], 
                re.compile("((?:annotation )?(?:selector (?:field )+))"))
        },
        "reduce": ReduceKeyRef
    },

    "length": {"struct" : """
        <length
          fixed = boolean : false
          id = ID
          value = nonNegativeInteger
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </length>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("length", 
                ["fixed", "id", "value"], ONLY_ANNOTATION)
        },
        "reduce": GenerateFacetReducing("length", True)
    },

    "list": {"struct": """
        <list
          id = ID
          itemType = QName
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, simpleType?)
        </list>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("list", ["id", "itemType"], 
                re.compile("((?:annotation )?(?:simpleType )?)$"))
        },
        "reduce": ReduceList
    },

    "maxExclusive": {"struct": """
        <maxInclusive
          fixed = boolean : false
          id = ID
          value = anySimpleType
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </maxInclusive>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("maxExclusive",
                ["fixed", "id", "value"], ONLY_ANNOTATION)
        },
        "reduce": GenerateFacetReducing("maxExclusive", True)
    },

    "maxInclusive": {"struct": """
        <maxExclusive
          fixed = boolean : false
          id = ID
          value = anySimpleType
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </maxExclusive>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("maxInclusive", 
                ["fixed", "id", "value"], ONLY_ANNOTATION)
        },
        "reduce": GenerateFacetReducing("maxInclusive", True)
    },

    "maxLength": {"struct": """
        <maxLength
          fixed = boolean : false
          id = ID
          value = nonNegativeInteger
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </maxLength>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("maxLength", 
                ["fixed", "id", "value"], ONLY_ANNOTATION)
        },
        "reduce": GenerateFacetReducing("maxLength", True)
    },

    "minExclusive": {"struct": """
        <minExclusive
          fixed = boolean : false
          id = ID
          value = anySimpleType
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </minExclusive>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("minExclusive", 
                ["fixed", "id", "value"], ONLY_ANNOTATION)
        },
        "reduce": GenerateFacetReducing("minExclusive", True)
    },

    "minInclusive": {"struct": """
        <minInclusive
          fixed = boolean : false
          id = ID
          value = anySimpleType
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </minInclusive>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("minInclusive", 
                ["fixed", "id", "value"], ONLY_ANNOTATION)
        },
        "reduce": GenerateFacetReducing("minInclusive", True)
    },

    "minLength": {"struct": """
        <minLength
          fixed = boolean : false
          id = ID
          value = nonNegativeInteger
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </minLength>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("minLength",
                ["fixed", "id", "value"], ONLY_ANNOTATION)
        },
        "reduce": GenerateFacetReducing("minLength", True)
    },

    "pattern": {"struct": """
        <pattern
          id = ID
          value = string
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </pattern>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("pattern", ["id", "value"], ONLY_ANNOTATION)
        },
        "reduce": GenerateFacetReducing("pattern", False)
    },

    "redefine": {"struct": """
        <redefine
          id = ID
          schemaLocation = anyURI
          {any attributes with non-schema namespace . . .}>
          Content: (annotation | (simpleType | complexType | group | attributeGroup))*
        </redefine>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("refine", ["id", "schemaLocation"], 
                re.compile("((?:annotation |(?:simpleType |complexType |group |attributeGroup ))*)"))
        },
        "reduce": ReduceRedefine
    },

    "restriction": {"struct": """
        <restriction
          base = QName
          id = ID
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, (group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?))
        </restriction>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("restriction", ["base", "id"], 
                re.compile("((?:annotation )?(?:(?:simpleType )?(?:(?:minExclusive |minInclusive |maxExclusive |maxInclusive |totalDigits |fractionDigits |length |minLength |maxLength |enumeration |whiteSpace |pattern )*)))")),
            "simpleContent": GenerateElement("restriction", ["base", "id"], 
                re.compile("((?:annotation )?(?:(?:simpleType )?(?:(?:minExclusive |minInclusive |maxExclusive |maxInclusive |totalDigits |fractionDigits |length |minLength |maxLength |enumeration |whiteSpace |pattern )*)?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?)))")),
            "complexContent": GenerateElement("restriction", ["base", "id"], 
                re.compile("((?:annotation )?(?:(?:simpleType )?(?:group |all |choice |sequence )?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?)))")),
        },
        "reduce": ReduceRestriction
    },

    "schema": {"struct": """
        <schema
          attributeFormDefault = (qualified | unqualified) : unqualified
          blockDefault = (#all | List of (extension | restriction | substitution))  : ''
          elementFormDefault = (qualified | unqualified) : unqualified
          finalDefault = (#all | List of (extension | restriction | list | union))  : ''
          id = ID
          targetNamespace = anyURI
          version = token
          xml:lang = language
          {any attributes with non-schema namespace . . .}>
          Content: ((include | import | redefine | annotation)*, (((simpleType | complexType | group | attributeGroup) | element | attribute | notation), annotation*)*)
        </schema>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("schema",
                ["attributeFormDefault", "blockDefault", "elementFormDefault", "finalDefault", "id", "targetNamespace", "version", "lang"], 
                re.compile("((?:include |import |redefine |annotation )*(?:(?:(?:simpleType |complexType |group |attributeGroup )|element |attribute |annotation )(?:annotation )*)*)"))
        }
    },

    "selector": {"struct": """
        <selector
          id = ID
          xpath = a subset of XPath expression, see below
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </selector>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("selector", ["id", "xpath"], ONLY_ANNOTATION)
        },
        "reduce": ReduceSelector
    },

    "sequence": {"struct": """
        <sequence
          id = ID
          maxOccurs = (nonNegativeInteger | unbounded)  : 1
          minOccurs = nonNegativeInteger : 1
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, (element | group | choice | sequence | any)*)
        </sequence>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("sequence", ["id", "maxOccurs", "minOccurs"], 
                re.compile("((?:annotation )?(?:element |group |choice |sequence |any )*)"))
        },
        "reduce": ReduceSequence
    },

    "simpleContent": {"struct" : """
        <simpleContent
          id = ID
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, (restriction | extension))
        </simpleContent>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("simpleContent", ["id"], 
                re.compile("((?:annotation )?(?:restriction |extension ))"))
        },
        "reduce": ReduceSimpleContent
    },

    "simpleType": {"struct" : """
        <simpleType
          final = (#all | List of (list | union | restriction))
          id = ID
          name = NCName
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, (restriction | list | union))
        </simpleType>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("simpleType", ["final", "id", "name"], 
                re.compile("((?:annotation )?(?:restriction |list |union ))"))
        },
        "reduce": ReduceSimpleType
    },

    "totalDigits": {"struct" : """
        <totalDigits
          fixed = boolean : false
          id = ID
          value = positiveInteger
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </totalDigits>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("totalDigits", 
                ["fixed", "id", "value"], ONLY_ANNOTATION),
        },
        "reduce": GenerateFacetReducing("totalDigits", True)
    },

    "union": {"struct": """
        <union
          id = ID
          memberTypes = List of QName
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, simpleType*)
        </union>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("union", ["id", "memberTypes"], 
                re.compile("((?:annotation )?(?:simpleType )*)"))
        },
        "reduce": ReduceUnion
    },

    "unique": {"struct": """
        <unique
          id = ID
          name = NCName
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?, (selector, field+))
        </unique>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("unique", ["id", "name"], 
                re.compile("((?:annotation )?(?:selector |(?:field )+))"))
        },
        "reduce": ReduceUnique
    },
    
    "whiteSpace": {"struct" : """
        <whiteSpace
          fixed = boolean : false
          id = ID
          value = (collapse | preserve | replace)
          {any attributes with non-schema namespace . . .}>
          Content: (annotation?)
        </whiteSpace>""",
        "type": SYNTAXELEMENT, 
        "extract": {
            "default": GenerateElement("whiteSpace", 
                ["fixed", "id", "value"], ONLY_ANNOTATION)
        },
        "reduce": GenerateFacetReducing("whiteSpace", True)
    },

#-------------------------------------------------------------------------------
#                       Syntax attributes definition
#-------------------------------------------------------------------------------

    "abstract": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GetBoolean
        },
        "default": {
            "default": False
        }
    },

    "attributeFormDefault": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateEnumeratedExtraction("member attributeFormDefault", ["qualified", "unqualified"])
        },
        "default": {
            "default": "unqualified"
        }
    },
    
    "base": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateModelNameExtraction("member base", QName_model)
        }
    },
    
    "block": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateGetList("block", ["restriction", "extension", "substitution"])
        }
    },
    
    "blockDefault": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateGetList("block", ["restriction", "extension", "substitution"])
        },
        "default": {
            "default": ""
        }
    },
    
    "default": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GetAttributeValue
        }
    },

    "elementFormDefault": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateEnumeratedExtraction("member elementFormDefault", ["qualified", "unqualified"])
        },
        "default": {
            "default": "unqualified"
        }
    },
    
    "final": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateGetList("final", ["restriction", "extension", "substitution"]),
            "simpleType": GenerateGetList("final", ["list", "union", "restriction"])
        }
    },

    "finalDefault": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateGetList("finalDefault", ["restriction", "extension", "list", "union"])
        },
        "default": {
            "default": ""
        }
    },
    
    "fixed": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GetBoolean,
            "attribute": GetAttributeValue,
            "element": GetAttributeValue
        },
        "default": {
            "default": False,
            "attribute": None,
            "element": None
        }
    },

    "form": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateEnumeratedExtraction("member form", ["qualified", "unqualified"])
        }
    },

    "id": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateModelNameExtraction("member id", NCName_model)
        }
    },
    
    "itemType": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateModelNameExtraction("member itemType", QName_model)
        }
    },

    "memberTypes": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateModelNameListExtraction("member memberTypes", QNames_model)
        },
    },
    
    "maxOccurs": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateLimitExtraction(),
            "all": GenerateLimitExtraction(1, 1, False)
        },
        "default": {
            "default": 1
        }
    },

    "minOccurs": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateLimitExtraction(unbounded = False),
            "all": GenerateLimitExtraction(0, 1, False)
        },
        "default": {
            "default": 1
        }
    },

    "mixed": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GetBoolean
        },
        "default": {
            "default": None,
            "complexType": False
        }
    },
    
    "name": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateModelNameExtraction("member name", NCName_model)
        }
    },
    
    "namespace": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateModelNameExtraction("member namespace", URI_model),
            "any": GetNamespaces
        },
        "default": {
            "default": None,
            "any": "##any"
        }
    },

    "nillable": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GetBoolean
        },
    },
    
    "processContents": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateEnumeratedExtraction("member processContents", ["lax", "skip", "strict"])
        },
        "default": {
            "default": "strict"
        }
    },
    
    "ref": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateModelNameExtraction("member ref", QName_model)
        }
    },

    "refer": {
        "type": SYNTAXATTRIBUTE,
        "extract": {
            "default": GenerateModelNameExtraction("member refer", QName_model)
        }
    },
    
    "schemaLocation": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateModelNameExtraction("member schemaLocation", URI_model)
        }
    },
    
    "source": {
        "type": SYNTAXATTRIBUTE,
        "extract": {
            "default": GenerateModelNameExtraction("member source", URI_model)
        }
    },
    
    "substitutionGroup": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateModelNameExtraction("member substitutionGroup", QName_model)
        }
    },

    "targetNamespace": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateModelNameExtraction("member targetNamespace", URI_model)
        }
    },
    
    "type": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateModelNameExtraction("member type", QName_model)
        }
    },

    "use": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GenerateEnumeratedExtraction("member usage", ["required", "optional", "prohibited"])
        },
        "default": {
            "default": "optional"
        }
    },

    "value": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
            "default": GetAttributeValue,
            "fractionDigits": GenerateIntegerExtraction(minInclusive=0),
            "length": GenerateIntegerExtraction(minInclusive=0),
            "maxLength": GenerateIntegerExtraction(minInclusive=0),
            "minLength": GenerateIntegerExtraction(minInclusive=0),
            "totalDigits": GenerateIntegerExtraction(minExclusive=0),
            "whiteSpace": GenerateEnumeratedExtraction("value", ["collapse", "preserve", "replace"])
        }
    },

    "version": {
        "type": SYNTAXATTRIBUTE,
        "extract": {
            "default": GetToken
        }
    },

    "xpath": {
        "type": SYNTAXATTRIBUTE, 
        "extract": {
#            "default": NotSupportedYet("xpath")
            "default": GetAttributeValue
        }
    },
    
#-------------------------------------------------------------------------------
#                           Simple types definition
#-------------------------------------------------------------------------------

    "string": {
        "type": SIMPLETYPE,
        "basename": "string",
        "extract": GetAttributeValue,
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(lambda x : x),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "normalizedString": {
        "type": SIMPLETYPE,
        "basename": "normalizedString",
        "extract": GetNormalizedString,
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(lambda x : x),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "token": {
        "type": SIMPLETYPE,
        "basename": "token",  
        "extract": GetToken,
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(lambda x : x),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },
    
    "base64Binary": {
        "type": SIMPLETYPE, 
        "basename": "base64Binary", 
        "extract": NotSupportedYet("base64Binary"),
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: 0,
        "check": lambda x: isinstance(x, (IntType, LongType))
    },
    
    "hexBinary": {
        "type": SIMPLETYPE,
        "basename": "hexBinary", 
        "extract": GetHexInteger,
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(lambda x: ("%."+str(int(round(len("%X"%x)/2.)*2))+"X")%x),
        "initial": lambda: 0,
        "check": lambda x: isinstance(x, (IntType, LongType))
    },

    "integer": {
        "type": SIMPLETYPE,
        "basename": "integer", 
        "extract": GenerateIntegerExtraction(),
        "facets": DECIMAL_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: 0,
        "check": lambda x: isinstance(x, IntType)
    },
    
    "positiveInteger": {
        "type": SIMPLETYPE,
        "basename": "positiveInteger", 
        "extract": GenerateIntegerExtraction(minExclusive=0),
        "facets": DECIMAL_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: 0,
        "check": lambda x: isinstance(x, IntType)
    },
    
    "negativeInteger": {
        "type": SIMPLETYPE,
        "basename": "negativeInteger",
        "extract": GenerateIntegerExtraction(maxExclusive=0),
        "facets": DECIMAL_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: 0,
        "check": lambda x: isinstance(x, IntType)
    },
    
    "nonNegativeInteger": {
        "type": SIMPLETYPE, 
        "basename": "nonNegativeInteger", 
        "extract": GenerateIntegerExtraction(minInclusive=0),
        "facets": DECIMAL_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: 0,
        "check": lambda x: isinstance(x, IntType)
    },
    
    "nonPositiveInteger": {
        "type": SIMPLETYPE,
        "basename": "nonPositiveInteger", 
        "extract": GenerateIntegerExtraction(maxInclusive=0),
        "facets": DECIMAL_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: 0,
        "check": lambda x: isinstance(x, IntType)
    },
    
    "long": {
        "type": SIMPLETYPE,
        "basename": "long",
        "extract": GenerateIntegerExtraction(minInclusive=-2**63,maxExclusive=2**63),
        "facets": DECIMAL_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: 0,
        "check": lambda x: isinstance(x, IntType)
    },
    
    "unsignedLong": {
        "type": SIMPLETYPE,
        "basename": "unsignedLong",
        "extract": GenerateIntegerExtraction(minInclusive=0,maxExclusive=2**64),
        "facets": DECIMAL_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: 0,
        "check": lambda x: isinstance(x, IntType)
    },

    "int": {
        "type": SIMPLETYPE,
        "basename": "int",
        "extract": GenerateIntegerExtraction(minInclusive=-2**31,maxExclusive=2**31),
        "facets": DECIMAL_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: 0,
        "check": lambda x: isinstance(x, IntType)
    },

    "unsignedInt": {
        "type": SIMPLETYPE,
        "basename": "unsignedInt",
        "extract": GenerateIntegerExtraction(minInclusive=0,maxExclusive=2**32),
        "facets": DECIMAL_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: 0,
        "check": lambda x: isinstance(x, IntType)
    },

    "short": {
        "type": SIMPLETYPE,
        "basename": "short",
        "extract": GenerateIntegerExtraction(minInclusive=-2**15,maxExclusive=2**15),
        "facets": DECIMAL_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: 0,
        "check": lambda x: isinstance(x, IntType)
    },

    "unsignedShort": {
        "type": SIMPLETYPE,
        "basename": "unsignedShort", 
        "extract": GenerateIntegerExtraction(minInclusive=0,maxExclusive=2**16),
        "facets": DECIMAL_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: 0,
        "check": lambda x: isinstance(x, IntType)
    },

    "byte": {
        "type": SIMPLETYPE,
        "basename": "byte",
        "extract": GenerateIntegerExtraction(minInclusive=-2**7,maxExclusive=2**7),
        "facets": DECIMAL_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: 0,
        "check": lambda x: isinstance(x, IntType)
    },

    "unsignedByte": {
        "type": SIMPLETYPE,
        "basename": "unsignedByte",
        "extract": GenerateIntegerExtraction(minInclusive=0,maxExclusive=2**8),
        "facets": DECIMAL_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: 0,
        "check": lambda x: isinstance(x, IntType)
    },

    "decimal": {
        "type": SIMPLETYPE,
        "basename": "decimal",
        "extract": GenerateFloatExtraction("decimal"),
        "facets": DECIMAL_FACETS,
        "generate": GenerateFloatXMLText(),
        "initial": lambda: 0.,
        "check": lambda x: isinstance(x, (IntType, FloatType))
    },

    "float": {
        "type": SIMPLETYPE,
        "basename": "float",
        "extract": GenerateFloatExtraction("float", ["INF", "-INF", "NaN"]),
        "facets": NUMBER_FACETS,
        "generate": GenerateFloatXMLText(["INF", "-INF", "NaN"]),
        "initial": lambda: 0.,
        "check": lambda x: {"INF" : True, "-INF" : True, "NaN" : True}.get(x, isinstance(x, (IntType, FloatType)))
    },

    "double": {
        "type": SIMPLETYPE,
        "basename": "double",
        "extract": GenerateFloatExtraction("double", ["INF", "-INF", "NaN"]),
        "facets": NUMBER_FACETS,
        "generate": GenerateFloatXMLText(["INF", "-INF", "NaN"]),
        "initial": lambda: 0.,
        "check": lambda x: {"INF" : True, "-INF" : True, "NaN" : True}.get(x, isinstance(x, (IntType, FloatType)))
    },

    "boolean": {
        "type": SIMPLETYPE,
        "basename": "boolean",
        "extract": GetBoolean,
        "facets": GenerateDictFacets(["pattern", "whiteSpace"]),
        "generate": GenerateSimpleTypeXMLText(lambda x:{True : "true", False : "false"}[x]),
        "initial": lambda: False,
        "check": lambda x: isinstance(x, BooleanType)
    },	

    "duration": {
        "type": SIMPLETYPE,
        "basename": "duration",
        "extract": NotSupportedYet("duration"),
        "facets": NUMBER_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "dateTime": {
        "type": SIMPLETYPE,
        "basename": "dateTime",
        "extract": GetDateTime,
        "facets": NUMBER_FACETS,
        "generate": GenerateSimpleTypeXMLText(datetime.datetime.isoformat),
        "initial": lambda: datetime.datetime(1,1,1,0,0,0,0),
        "check": lambda x: isinstance(x, datetime.datetime)
    },

    "date": {
        "type": SIMPLETYPE,
        "basename": "date",
        "extract": GetDate,
        "facets": NUMBER_FACETS,
        "generate": GenerateSimpleTypeXMLText(datetime.date.isoformat),
        "initial": lambda: datetime.date(1,1,1),
        "check": lambda x: isinstance(x, datetime.date)
    },
    
    "time": {
        "type": SIMPLETYPE,
        "basename": "time",
        "extract": GetTime,
        "facets": NUMBER_FACETS,
        "generate": GenerateSimpleTypeXMLText(datetime.time.isoformat),
        "initial": lambda: datetime.time(0,0,0,0),
        "check": lambda x: isinstance(x, datetime.time)
    },

    "gYear": {
        "type": SIMPLETYPE,
        "basename": "gYear",
        "extract": NotSupportedYet("gYear"),
        "facets": NUMBER_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "gYearMonth": {
        "type": SIMPLETYPE,
        "basename": "gYearMonth",
        "extract": NotSupportedYet("gYearMonth"),
        "facets": NUMBER_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "gMonth": {
        "type": SIMPLETYPE,
        "basename": "gMonth",
        "extract": NotSupportedYet("gMonth"),
        "facets": NUMBER_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "gMonthDay": {
        "type": SIMPLETYPE,
        "basename": "gMonthDay",
        "extract": NotSupportedYet("gMonthDay"),
        "facets": NUMBER_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "gDay": {
        "type": SIMPLETYPE,
        "basename": "gDay",
        "extract": NotSupportedYet("gDay"),
        "facets": NUMBER_FACETS,
        "generate": GenerateSimpleTypeXMLText(str),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "Name": {
        "type": SIMPLETYPE,
        "basename": "Name",
        "extract": GenerateModelNameExtraction("Name", Name_model),
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(lambda x: x),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },
    
    "QName": {
        "type": SIMPLETYPE,
        "basename": "QName",
        "extract": GenerateModelNameExtraction("QName", QName_model),
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(lambda x: x),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "NCName": {
        "type": SIMPLETYPE,
        "basename": "NCName",
        "extract": GenerateModelNameExtraction("NCName", NCName_model),
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(lambda x: x),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "anyURI": {
        "type": SIMPLETYPE,
        "basename": "anyURI",
        "extract": GenerateModelNameExtraction("anyURI", URI_model),
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(lambda x: x),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "language": {
        "type": SIMPLETYPE,
        "basename": "language",
        "extract": GenerateModelNameExtraction("language", LANGUAGE_model),
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(lambda x: x),
        "initial": lambda: "en",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "ID": {
        "type": SIMPLETYPE,
        "basename": "ID",
        "extract": GenerateModelNameExtraction("ID", Name_model),
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(lambda x: x),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "IDREF": {
        "type": SIMPLETYPE,
        "basename": "IDREF",
        "extract": GenerateModelNameExtraction("IDREF", Name_model),
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(lambda x: x),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "IDREFS": {
        "type": SIMPLETYPE,
        "basename": "IDREFS",
        "extract": GenerateModelNameExtraction("IDREFS", Names_model),
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(lambda x: x),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "ENTITY": {
        "type": SIMPLETYPE,
        "basename": "ENTITY",
        "extract": GenerateModelNameExtraction("ENTITY", Name_model),
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(lambda x: x),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "ENTITIES": {
        "type": SIMPLETYPE,
        "basename": "ENTITIES",
        "extract": GenerateModelNameExtraction("ENTITIES", Names_model),
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(lambda x: x),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "NOTATION": {
        "type": SIMPLETYPE,
        "basename": "NOTATION",
        "extract": GenerateModelNameExtraction("NOTATION", Name_model),
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(lambda x: x),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "NMTOKEN": {
        "type": SIMPLETYPE,
        "basename": "NMTOKEN",
        "extract": GenerateModelNameExtraction("NMTOKEN", NMToken_model),
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(lambda x: x),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    "NMTOKENS": {
        "type": SIMPLETYPE,
        "basename": "NMTOKENS",
        "extract": GenerateModelNameExtraction("NMTOKENS", NMTokens_model),
        "facets": STRING_FACETS,
        "generate": GenerateSimpleTypeXMLText(lambda x: x),
        "initial": lambda: "",
        "check": lambda x: isinstance(x, (StringType, UnicodeType))
    },

    # Complex Types
    "anyType": {"type": COMPLEXTYPE, "extract": lambda x:None},
}

if __name__ == '__main__':
    classes = GenerateClassesFromXSD("test.xsd")
    
    # Code for test of test.xsd
    xmlfile = open("po.xml", 'r')
    tree = minidom.parse(xmlfile)
    xmlfile.close()
    test = classes["PurchaseOrderType"]()
    for child in tree.childNodes:
        if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "purchaseOrder":
            test.loadXMLTree(child)
    test.items.item[0].setquantity(2)
    testfile = open("test.xml", 'w')
    testfile.write(u'<?xml version=\"1.0\"?>\n')
    testfile.write(test.generateXMLText("purchaseOrder").encode("utf-8"))
    testfile.close()