#!/usr/bin/env python
# SPDX-License-Identifier: MIT

## LICENSE

## Copyright (c) 2003 Dave Kuhlman

## Permission is hereby granted, free of charge, to any person obtaining
## a copy of this software and associated documentation files (the
## "Software"), to deal in the Software without restriction, including
## without limitation the rights to use, copy, modify, merge, publish,
## distribute, sublicense, and/or sell copies of the Software, and to
## permit persons to whom the Software is furnished to do so, subject to
## the following conditions:

## The above copyright notice and this permission notice shall be
## included in all copies or substantial portions of the Software.

## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
## IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
## CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
## TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
## SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import sys
import os.path
import time
import getopt
from urllib.request import urlopen
from urllib.error import HTTPError
from xml.sax import handler, make_parser
import xml.sax.xmlreader

##from IPython.Shell import IPShellEmbed
##args = ''
##ipshell = IPShellEmbed(args,
##    banner = 'Dropping into IPython',
##    exit_msg = 'Leaving Interpreter, back to program.')

# Then use the following line where and when you want to drop into the
# IPython shell:
#    ipshell('<some message> -- Entering ipshell.\\nHit Ctrl-D to exit')


#
# Global variables etc.
#
GenerateProperties = 0
DelayedElements = []
DelayedElements_subclass = []
AlreadyGenerated = []
AlreadyGenerated_subclass = []
PostponedExtensions = []
ElementsForSubclasses = []
ElementDict = {}
SaxElementDict = {}
ElementDebugList = []
Force = 0
NameTable = {
    "class": "klass",
    "import": "emport",
    "type": "ttype",
}
SubclassSuffix = "Sub"
RootElement = None
AttributeGroups = {}
SubstitutionGroups = {}
#
# SubstitutionGroups can also include simple types that are
#   not (defined) elements.  Keep a list of these simple types.
#   These are simple types defined at top level.
SimpleElementDict = {}


def set_type_constants(nameSpace):
    global StringType, TokenType, IntegerType, DecimalType, ShortType, LongType, PositiveIntegerType, NegativeIntegerType, NonPositiveIntegerType, NonNegativeIntegerType, BooleanType, FloatType, DoubleType, ElementType, ComplexTypeType, SequenceType, ChoiceType, AttributeGroupType, AttributeType, SchemaType, DateTimeType, DateType, ComplexContentType, ExtensionType, IDType, IDREFType, IDREFSType, AnyAttributeType
    AttributeGroupType = nameSpace + "attributeGroup"
    AttributeType = nameSpace + "attribute"
    BooleanType = nameSpace + "boolean"
    ChoiceType = nameSpace + "choice"
    ComplexContentType = nameSpace + "complexContent"
    ComplexTypeType = nameSpace + "complexType"
    AnyAttributeType = nameSpace + "anyAttribute"
    DateTimeType = nameSpace + "dateTime"
    DateType = nameSpace + "date"
    IntegerType = (
        nameSpace + "integer",
        nameSpace + "xs:unsignedShort",
        nameSpace + "short",
        nameSpace + "long",
    )
    # ShortType = nameSpace + 'short'
    # LongType = nameSpace + 'long'
    DecimalType = nameSpace + "decimal"
    PositiveIntegerType = nameSpace + "positiveInteger"
    NegativeIntegerType = nameSpace + "negativeInteger"
    NonPositiveIntegerType = nameSpace + "nonPositiveInteger"
    NonNegativeIntegerType = nameSpace + "nonNegativeInteger"
    DoubleType = nameSpace + "double"
    ElementType = nameSpace + "element"
    ExtensionType = nameSpace + "extension"
    FloatType = nameSpace + "float"
    IDREFSType = nameSpace + "IDREFS"
    IDREFType = nameSpace + "IDREF"
    IDType = nameSpace + "ID"
    SchemaType = nameSpace + "schema"
    SequenceType = nameSpace + "sequence"
    StringType = (
        nameSpace + "string",
        nameSpace + "duration",
        nameSpace + "anyURI",
    )
    TokenType = nameSpace + "token"


#
# For debugging.
#

# Print only if DEBUG is true.
DEBUG = 1


def dbgprint(level, msg):
    if DEBUG and level > 0:
        print(msg)


def pplist(lst):
    for count, item in enumerate(lst):
        print("%d. %s" % (count, item))


#
# Representation of element definition.
#


def showLevel(outfile, level):
    for idx in range(level):
        outfile.write("    ")


class XschemaElement:
    def __init__(self, attrs):
        self.cleanName = ""
        self.attrs = dict(attrs)
        name_val = ""
        type_val = ""
        ref_val = ""
        if "name" in self.attrs:
            name_val = strip_namespace(self.attrs["name"])
        if "type" in self.attrs:
            # fix
            # type_val = strip_namespace(self.attrs['type'])
            type_val = self.attrs["type"]
        if "ref" in self.attrs:
            ref_val = strip_namespace(self.attrs["ref"])
        if type_val and not name_val:
            name_val = type_val
        if ref_val and not name_val:
            name_val = ref_val
        if ref_val and not type_val:
            type_val = ref_val
        if name_val:
            self.attrs["name"] = name_val
        if type_val:
            self.attrs["type"] = type_val
        if ref_val:
            self.attrs["ref"] = ref_val
        self.name = name_val
        self.children = []
        self.maxOccurs = 1
        self.complex = 0
        self.complexType = 0
        self.type = "NoneType"
        self.mixed = 0
        self.base = None
        self.mixedExtensionError = 0
        # Attribute definitions for the correct element.
        self.attributeDefs = {}
        # Attribute definitions for the current attributeGroup, if there is one.
        self.attributeGroup = None
        # List of names of attributes for this element.
        # We will add the attribute definitions in each of these groups
        #   to this element in annotate().
        self.attributeGroupNameList = []
        self.topLevel = 0
        # Does this element contain an anyAttribute?
        self.anyAttribute = 0

    def addChild(self, element):
        self.children.append(element)

    def getChildren(self):
        return self.children

    def getName(self):
        return self.name

    def getCleanName(self):
        return self.cleanName

    def getUnmappedCleanName(self):
        return self.unmappedCleanName

    def setName(self, name):
        self.name = name

    def getAttrs(self):
        return self.attrs

    def setAttrs(self, attrs):
        self.attrs = attrs

    def getMaxOccurs(self):
        return self.maxOccurs

    def getRawType(self):
        return self.type

    def getType(self):
        returnType = self.type
        if self.type in ElementDict:
            typeObj = ElementDict[self.type]
            typeObjType = typeObj.getRawType()
            if (
                typeObjType in StringType
                or typeObjType == TokenType
                or typeObjType == DateTimeType
                or typeObjType == DateType
                or typeObjType in IntegerType
                or typeObjType == DecimalType
                or typeObjType == PositiveIntegerType
                or typeObjType == NegativeIntegerType
                or typeObjType == NonPositiveIntegerType
                or typeObjType == NonNegativeIntegerType
                or typeObjType == BooleanType
                or typeObjType == FloatType
                or typeObjType == DoubleType
            ):
                returnType = typeObjType
        return returnType

    def isComplex(self):
        return self.complex

    def addAttributeDefs(self, attrs):
        self.attributeDefs.append(attrs)

    def getAttributeDefs(self):
        return self.attributeDefs

    def isMixed(self):
        return self.mixed

    def setMixed(self, mixed):
        self.mixed = mixed

    def setBase(self, base):
        self.base = base

    def getBase(self):
        return self.base

    def getMixedExtensionError(self):
        return self.mixedExtensionError

    def getAttributeGroups(self):
        return self.attributeGroups

    def addAttribute(self, name, attribute):
        self.attributeGroups[name] = attribute

    def setAttributeGroup(self, attributeGroup):
        self.attributeGroup = attributeGroup

    def getAttributeGroup(self):
        return self.attributeGroup

    def setTopLevel(self, topLevel):
        self.topLevel = topLevel

    def getTopLevel(self):
        return self.topLevel

    def setAnyAttribute(self, anyAttribute):
        self.anyAttribute = anyAttribute

    def getAnyAttribute(self):
        return self.anyAttribute

    def show(self, outfile, level):
        showLevel(outfile, level)
        outfile.write("Name: %s  Type: %s\n" % (self.name, self.getType()))
        showLevel(outfile, level)
        outfile.write("  - Complex: %d  MaxOccurs: %d\n" % (self.complex, self.maxOccurs))
        showLevel(outfile, level)
        outfile.write("  - Attrs: %s\n" % self.attrs)
        showLevel(outfile, level)
        outfile.write("  - AttributeDefs: %s\n" % self.attributeDefs)
        # ipshell('(visit_title) Entering ipshell.\nHit Ctrl-D to exit')

        for attr in self.getAttributeDefs():
            key = attr["name"]
            try:
                value = attr["value"]
            except:
                value = "<empty>"
            showLevel(outfile, level + 1)
            outfile.write("key: %s  value: %s\n" % (key, value))
        for child in self.children:
            child.show(outfile, level + 1)

    def annotate(self):
        self.collect_element_dict()
        self.annotate_find_type()
        self.annotate_tree()
        self.fix_dup_names()
        self.coerce_attr_types()
        self.checkMixedBases()

    def collect_element_dict(self):
        base = self.getBase()
        if (
            self.getTopLevel()
            or len(self.getChildren()) > 0
            or len(self.getAttributeDefs()) > 0
            or base
        ):
            ElementDict[self.name] = self
        for child in self.children:
            child.collect_element_dict()

    def element_is_complex(self):
        pass

    # If it is a mixed-content element and it is defined as
    #   an extension, then all of its bases (base, base of base, ...)
    #   must be mixed-content.  Mark it as an error, if not.
    def checkMixedBases(self):
        self.checkMixedBasesChain(self, self.mixed)
        for child in self.children:
            child.checkMixedBases()

    def checkMixedBasesChain(self, child, childMixed):
        base = self.getBase()
        if base and base in ElementDict:
            parent = ElementDict[base]
            if childMixed != parent.isMixed():
                self.mixedExtensionError = 1
                return
            parent.checkMixedBasesChain(child, childMixed)

    def resolve_type(self):
        self.complex = 0
        # If it has any attributes, then it's complex.
        attrDefs = self.getAttributeDefs()
        if len(attrDefs) > 0:
            self.complex = 1
            # type_val = ''
        type_val = self.resolve_type_1()
        if type_val:
            if type_val in ElementDict:
                element = ElementDict[type_val]
                type_val1 = element.resolve_type_1()
                if (
                    type_val1 in StringType
                    or type_val1 == TokenType
                    or type_val1 == DateTimeType
                    or type_val1 == DateType
                    or type_val1 in IntegerType
                    or type_val1 == DecimalType
                    or type_val1 == PositiveIntegerType
                    or type_val1 == NonPositiveIntegerType
                    or type_val1 == NegativeIntegerType
                    or type_val1 == NonNegativeIntegerType
                    or type_val1 == BooleanType
                    or type_val1 == FloatType
                    or type_val1 == DoubleType
                ):
                    type_val = type_val1
                else:
                    self.complex = 1
            else:
                if (
                    type_val in StringType
                    or type_val == TokenType
                    or type_val == DateTimeType
                    or type_val == DateType
                    or type_val in IntegerType
                    or type_val == DecimalType
                    or type_val == PositiveIntegerType
                    or type_val == NonPositiveIntegerType
                    or type_val == NegativeIntegerType
                    or type_val == NonNegativeIntegerType
                    or type_val == BooleanType
                    or type_val == FloatType
                    or type_val == DoubleType
                ):
                    pass
                else:
                    type_val = StringType[0]
        else:
            type_val = StringType[0]
        return type_val

    def resolve_type_1(self):
        type_val = ""
        if "type" in self.attrs:
            # fix
            # type_val = strip_namespace(self.attrs['type'])
            type_val = self.attrs["type"]
        elif "ref" in self.attrs:
            # fix
            type_val = strip_namespace(self.attrs["ref"])
            # type_val = self.attrs['ref']
        elif "name" in self.attrs:
            # fix
            type_val = strip_namespace(self.attrs["name"])
            # type_val = self.attrs['name']
        return type_val

    def annotate_find_type(self):
        type_val = self.resolve_type()
        # dbgprint(1, '(aft) n: %s  t: %s  c: %s  id: %s' % \
        #    (self.name, type_val, self.complex, id(self), ))
        self.attrs["type"] = type_val
        self.type = type_val
        if not self.complex:
            SimpleElementDict[self.name] = self.name
        for child in self.children:
            child.annotate_find_type()

    def annotate_tree(self):
        # If there is a namespace, replace it with an underscore.
        if self.base:
            self.base = strip_namespace(self.base)
        self.unmappedCleanName = cleanupName(self.name)
        self.cleanName = mapName(self.unmappedCleanName)
        SaxElementDict[self.cleanName] = self
        self.replace_attributeGroup_names()
        if "maxOccurs" in self.attrs:
            maxOccurs = self.attrs["maxOccurs"]
            if maxOccurs == "unbounded":
                maxOccurs = 99999
            else:
                try:
                    maxOccurs = int(self.attrs["maxOccurs"])
                except ValueError:
                    sys.stderr.write(
                        '*** %s  maxOccurs must be integer or "unbounded".' % (self.getName(),)
                    )
                    sys.exit(-1)
        else:
            maxOccurs = 1
        self.maxOccurs = maxOccurs
        # if self.cleanName == 'Reason_XXX':
        #    ipshell('(annotate_tree) -- Entering ipshell.\\nHit Ctrl-D to exit')
        # If it does not have a type, then make the type the same as the name.
        if self.type == "NoneType" and self.name:
            self.type = self.name
        # Is it a mixed-content element definition?
        if "mixed" in self.attrs:
            mixed = self.attrs["mixed"].strip()
            if mixed == "1" or mixed.lower() == "true":
                self.mixed = 1
        # Do it recursively for all descendents.
        for child in self.children:
            child.annotate_tree()

    #
    # For each name in the attributeGroupNameList for this element,
    #   add the attributes defined for that name in the global
    #   attributeGroup dictionary.
    def replace_attributeGroup_names(self):
        for groupName in self.attributeGroupNameList:
            if groupName in AttributeGroups:
                attrGroup = AttributeGroups[groupName]
                for name in attrGroup.getKeys():
                    attr = attrGroup.get(name)
                    self.attributeDefs[name] = attr
            else:
                print("*** Error. attributeGroup %s not defined." % groupName)

    def __str__(self):
        s1 = '<"%s" XschemaElement instance at 0x%x>' % (self.getName(), id(self))
        return s1

    def __repr__(self):
        s1 = '<"%s" XschemaElement instance at 0x%x>' % (self.getName(), id(self))
        return s1

    def fix_dup_names(self):
        # Patch-up names that are used for both a child element and an attribute.
        #
        attrDefs = self.getAttributeDefs()
        # Collect a list of child element names.
        #   Must do this for base (extension) elements also.
        elementNames = []
        self.collectElementNames(elementNames)
        replaced = []
        # Create the needed new attributes.
        keys = attrDefs.keys()
        for key in keys:
            attr = attrDefs[key]
            name = attr.getName()
            if name in elementNames:
                newName = name + "_attr"
                newAttr = XschemaAttribute(newName)
                attrDefs[newName] = newAttr
                replaced.append(name)
        # Remove the old (replaced) attributes.
        for name in replaced:
            del attrDefs[name]
        for child in self.children:
            child.fix_dup_names()

    def collectElementNames(self, elementNames):
        for child in self.children:
            elementNames.append(cleanupName(child.cleanName))
        base = self.getBase()
        if base and base in ElementDict:
            parent = ElementDict[base]
            parent.collectElementNames(elementNames)

    def coerce_attr_types(self):
        replacements = []
        attrDefs = self.getAttributeDefs()
        for idx, name in enumerate(attrDefs):
            attr = attrDefs[name]
            attrType = attr.getData_type()
            if attrType == IDType or attrType == IDREFType or attrType == IDREFSType:
                attr.setData_type(StringType[0])
        for child in self.children:
            child.coerce_attr_types()


# end class XschemaElement


class XschemaAttributeGroup:
    def __init__(self, name="", group=None):
        self.name = name
        if group:
            self.group = group
        else:
            self.group = {}

    def setName(self, name):
        self.name = name

    def getName(self):
        return self.name

    def setGroup(self, group):
        self.group = group

    def getGroup(self):
        return self.group

    def get(self, name, default=None):
        if name in self.group:
            return self.group[name]
        else:
            return default

    def getKeys(self):
        return self.group.keys()

    def add(self, name, attr):
        self.group[name] = attr

    def delete(self, name):
        # if has_key(self.group, name):
        if name in self.group:
            del self.group[name]
            return 1
        else:
            return 0


# end class XschemaAttributeGroup


class XschemaAttribute:
    def __init__(self, name, data_type="xs:string", use="optional"):
        self.name = name
        self.data_type = data_type
        self.use = use

    def setName(self, name):
        self.name = name

    def getName(self):
        return self.name

    def setData_type(self, data_type):
        self.data_type = data_type

    def getData_type(self):
        return self.data_type

    def setUse(self, use):
        self.use = use

    def getUse(self):
        return self.use


# end class XschemaAttribute


#
# SAX handler
#
class XschemaHandler(handler.ContentHandler):
    def __init__(self):
        handler.ContentHandler.__init__(self)
        self.stack = []
        self.root = None
        self.inElement = 0
        self.inComplexType = 0
        self.inNonanonymousComplexType = 0
        self.inSequence = 0
        self.inChoice = 1
        self.inAttribute = 0
        self.inAttributeGroup = 0
        self.inSimpleElement = 0

    ##        self.dbgcount = 1
    ##        self.dbgnames = []

    def getRoot(self):
        # ipshell('Returning root -- Entering ipshell.\\nHit Ctrl-D to exit')
        return self.root

    def showError(self, msg):
        print(msg)
        sys.exit(-1)

    def startElement(self, name, attrs):
        # dbgprint(1, 'before schema name: %s  SchemaType: %s' % (name, SchemaType,))
        if name == SchemaType:
            # dbgprint(1, '(schema in)')
            self.inSchema = 1
            element = XschemaElement(attrs)
            if len(self.stack) == 1:
                element.setTopLevel(1)
            self.stack.append(element)
            # If there is an attribute "xmlns" and its value is
            #   "http://www.w3.org/2001/XMLSchema", then remember and
            #   use that namespace prefix.
            for name, value in attrs.items():
                if name[:6] == "xmlns:" and value == "http://www.w3.org/2001/XMLSchema":
                    nameSpace = name[6:] + ":"
                    set_type_constants(nameSpace)
        elif name == ElementType or ((name == ComplexTypeType) and (len(self.stack) == 1)):
            self.inElement = 1
            self.inNonanonymousComplexType = 1
            element = XschemaElement(attrs)
            if len(self.stack) == 1:
                element.setTopLevel(1)
            if "substitutionGroup" in attrs and "name" in attrs:
                substituteName = attrs["name"]
                headName = attrs["substitutionGroup"]
                if headName not in SubstitutionGroups:
                    SubstitutionGroups[headName] = []
                SubstitutionGroups[headName].append(substituteName)
                # dbgprint(1, '(startElement) added %s to %s' % (substituteName, headName))
            if name == ComplexTypeType:
                element.complexType = 1
            self.stack.append(element)
        elif name == ComplexTypeType:
            # If it have any attributes and there is something on the stack,
            #   then copy the attributes to the item on top of the stack.
            if len(self.stack) > 1 and len(attrs) > 0:
                parentDict = self.stack[-1].getAttrs()
                for key in attrs.keys():
                    parentDict[key] = attrs[key]
            self.inComplexType = 1
        elif name == SequenceType:
            self.inSequence = 1
        elif name == ChoiceType:
            self.inChoice = 1
        elif name == AttributeType:
            self.inAttribute = 1
            if "name" in attrs:
                name = attrs["name"]
            # fix-attribute-ref
            elif "ref" in attrs:
                name = strip_namespace(attrs["ref"])
            else:
                name = "no_attribute_name"
            if "type" in attrs:
                data_type = attrs["type"]
            else:
                data_type = StringType[0]
            if "use" in attrs:
                use = attrs["use"]
            else:
                use = "optional"
            if self.stack[-1].attributeGroup:
                # Add this attribute to a current attributeGroup.
                attribute = XschemaAttribute(name, data_type, use)
                self.stack[-1].attributeGroup.add(name, attribute)
            else:
                # Add this attribute to the element/complexType.
                attribute = XschemaAttribute(name, data_type, use)
                self.stack[-1].attributeDefs[name] = attribute
        elif name == AttributeGroupType:
            self.inAttributeGroup = 1
            # If it has attribute 'name', then it's a definition.
            #   Prepare to save it as an attributeGroup.
            if "name" in attrs:
                name = strip_namespace(attrs["name"])
                attributeGroup = XschemaAttributeGroup(name)
                element = XschemaElement(attrs)
                if len(self.stack) == 1:
                    element.setTopLevel(1)
                element.setAttributeGroup(attributeGroup)
                self.stack.append(element)
            # If it has attribute 'ref', add it to the list of
            #   attributeGroups for this element/complexType.
            if "ref" in attrs:
                self.stack[-1].attributeGroupNameList.append(attrs["ref"])
        elif name == ComplexContentType:
            pass
        elif name == ExtensionType:
            if "base" in attrs and len(self.stack) > 0:
                extensionBase = attrs["base"]
                if (
                    extensionBase in StringType
                    or extensionBase == TokenType
                    or extensionBase == DateTimeType
                    or extensionBase == DateType
                    or extensionBase in IntegerType
                    or extensionBase == DecimalType
                    or extensionBase == PositiveIntegerType
                    or extensionBase == NegativeIntegerType
                    or extensionBase == NonPositiveIntegerType
                    or extensionBase == NonNegativeIntegerType
                    or extensionBase == BooleanType
                    or extensionBase == FloatType
                    or extensionBase == DoubleType
                ):
                    pass
                else:
                    self.stack[-1].setBase(extensionBase)
        elif name == AnyAttributeType:
            # Mark the current element as containing anyAttribute.
            self.stack[-1].setAnyAttribute(1)

    def endElement(self, name):
        if self.inSimpleElement:
            self.inSimpleElement = 0
        elif name == ElementType or (name == ComplexTypeType and self.stack[-1].complexType):
            self.inElement = 0
            self.inNonanonymousComplexType = 0
            element = self.stack.pop()
            self.stack[-1].addChild(element)
        elif name == ComplexTypeType:
            self.inComplexType = 0
        elif name == SequenceType:
            self.inSequence = 0
        elif name == ChoiceType:
            self.inChoice = 0
        elif name == AttributeType:
            self.inAttribute = 0
        elif name == AttributeGroupType:
            self.inAttributeGroup = 0
            if self.stack[-1].attributeGroup:
                # The top of the stack contains an XschemaElement which
                #   contains the definition of an attributeGroup.
                #   Save this attributeGroup in the
                #   global AttributeGroup dictionary.
                attributeGroup = self.stack[-1].attributeGroup
                name = attributeGroup.getName()
                AttributeGroups[name] = attributeGroup
                self.stack[-1].attributeGroup = None
                self.stack.pop()
            else:
                # This is a reference to an attributeGroup.
                # We have already added it to the list of attributeGroup names.
                # Leave it.  We'll fill it in during annotate.
                pass
        elif name == SchemaType:
            self.inSchema = 0
            if len(self.stack) != 1:
                print("*** error stack.  len(self.stack): %d" % len(self.stack))
                sys.exit(-1)
            self.root = self.stack[0]
        elif name == ComplexContentType:
            pass
        elif name == ExtensionType:
            pass

    def characters(self, chrs):
        if self.inElement:
            pass
        elif self.inComplexType:
            pass
        elif self.inSequence:
            pass
        elif self.inChoice:
            pass


#
# Code generation
#


def generateExportFn_1(outfile, child, name, fill):
    cleanName = cleanupName(name)
    if (
        child.getType() in StringType
        or child.getType() == TokenType
        or child.getType() == DateTimeType
        or child.getType() == DateType
    ):
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('<%s>%%s</%s>\\n' %% quote_xml(self.get%s()))\n" % (
            fill,
            name,
            name,
            cleanName.capitalize(),
        )
        outfile.write(s1)
    elif (
        child.getType() in IntegerType
        or child.getType() == BooleanType
        or child.getType() == PositiveIntegerType
        or child.getType() == NonPositiveIntegerType
        or child.getType() == NegativeIntegerType
        or child.getType() == NonNegativeIntegerType
    ):
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('<%s>%%d</%s>\\n' %% self.get%s())\n" % (
            fill,
            name,
            name,
            cleanName.capitalize(),
        )
        outfile.write(s1)
    elif child.getType() == FloatType or child.getType() == DecimalType:
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('<%s>%%f</%s>\\n' %% self.get%s())\n" % (
            fill,
            name,
            name,
            cleanName.capitalize(),
        )
        outfile.write(s1)
    elif child.getType() == DoubleType:
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('<%s>%%e</%s>\\n' %% self.get%s())\n" % (
            fill,
            name,
            name,
            cleanName.capitalize(),
        )
        outfile.write(s1)
    else:
        s1 = "%s        if self.%s:\n" % (fill, cleanName)
        outfile.write(s1)
        if name == child.getType():
            s1 = "%s            self.%s.export(outfile, level)\n" % (fill, cleanName)
        else:
            s1 = "%s            self.%s.export(outfile, level, name_='%s')\n" % (
                fill,
                cleanName,
                name,
            )
        outfile.write(s1)


def generateExportFn_2(outfile, child, name, fill):
    cleanName = cleanupName(name)
    s1 = "%s    for %s_ in self.get%s():\n" % (fill, cleanName, cleanName.capitalize())
    outfile.write(s1)
    if (
        child.getType() in StringType
        or child.getType() == TokenType
        or child.getType() == DateTimeType
        or child.getType() == DateType
    ):
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('<%s>%%s</%s>\\n' %% quote_xml(%s_))\n" % (
            fill,
            name,
            name,
            cleanName,
        )
        outfile.write(s1)
    elif (
        child.getType() in IntegerType
        or child.getType() == BooleanType
        or child.getType() == PositiveIntegerType
        or child.getType() == NonPositiveIntegerType
        or child.getType() == NegativeIntegerType
        or child.getType() == NonNegativeIntegerType
    ):
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('<%s>%%d</%s>\\n' %% %s_)\n" % (
            fill,
            name,
            name,
            cleanName,
        )
        outfile.write(s1)
    elif child.getType() == FloatType or child.getType() == DecimalType:
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('<%s>%%f</%s>\\n' %% %s_)\n" % (
            fill,
            name,
            name,
            cleanName,
        )
        outfile.write(s1)
    elif child.getType() == DoubleType:
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('<%s>%%e</%s>\\n' %% %s_)\n" % (
            fill,
            name,
            name,
            cleanName,
        )
        outfile.write(s1)
    else:
        if name == child.getType():
            s1 = "%s        %s_.export(outfile, level)\n" % (fill, cleanName)
        else:
            s1 = "%s        %s_.export(outfile, level, name_='%s')\n" % (
                fill,
                cleanName,
                cleanName,
            )
        outfile.write(s1)


def generateExportAttributes(outfile, element, hasAttributes):
    if len(element.getAttributeDefs()) > 0:
        hasAttributes += 1
        attrDefs = element.getAttributeDefs()
        for key in attrDefs.keys():
            attrDef = attrDefs[key]
            name = attrDef.getName()
            cleanName = cleanupName(name)
            capName = cleanName.capitalize()
            if attrDef.getUse() == "optional":
                s1 = "        if self.get%s() is not None:\n" % (capName,)
                outfile.write(s1)
                s1 = "            outfile.write(' %s=\"%%s\"' %% (self.get%s(), ))\n" % (
                    name,
                    capName,
                )
                outfile.write(s1)
            else:
                s1 = "        outfile.write(' %s=\"%%s\"' %% (self.get%s(), ))\n" % (
                    name,
                    capName,
                )
                outfile.write(s1)
    if element.getAnyAttribute():
        s1 = "        for name, value in self.anyAttributes_.items():\n"
        outfile.write(s1)
        s1 = "            outfile.write(' %s=\"%s\"' % (name, value, ))\n"
        outfile.write(s1)
    return hasAttributes


def generateExportChildren(outfile, element, hasChildren):
    if len(element.getChildren()) > 0:
        hasChildren += 1
        if element.isMixed():
            s1 = "        for item_ in self.content_:\n"
            outfile.write(s1)
            s1 = "            item_.export(outfile, level, name_)\n"
            outfile.write(s1)
        else:
            for child in element.getChildren():
                name = child.getName()
                if child.getMaxOccurs() > 1:
                    generateExportFn_2(outfile, child, name, "    ")
                else:
                    generateExportFn_1(outfile, child, name, "")
    ##    base = element.getBase()
    ##    if base and base in ElementDict:
    ##        parent = ElementDict[base]
    ##        hasAttributes = generateExportChildren(outfile, parent, hasChildren)
    return hasChildren


def countChildren(element, count):
    count += len(element.getChildren())
    base = element.getBase()
    if base and base in ElementDict:
        parent = ElementDict[base]
        count = countChildren(parent, count)
    return count


def generateExportFn(outfile, prefix, element):
    base = element.getBase()
    s1 = "    def export(self, outfile, level, name_='%s'):\n" % element.getName()
    outfile.write(s1)
    s1 = "        showIndent(outfile, level)\n"
    outfile.write(s1)
    if len(element.getAttributeDefs()) > 0:
        s1 = "        outfile.write('<%s' % (name_, ))\n"
        outfile.write(s1)

        s1 = "        self.exportAttributes(outfile, level, name_='%s')\n" % element.getName()
        outfile.write(s1)
        if element.isMixed():
            s1 = "        outfile.write('>')\n"
        else:
            s1 = "        outfile.write('>\\n')\n"
        outfile.write(s1)
    else:
        if element.isMixed():
            s1 = "        outfile.write('<%s>' % name_)\n"
        else:
            s1 = "        outfile.write('<%s>\\n' % name_)\n"
        outfile.write(s1)

    s1 = "        self.exportChildren(outfile, level + 1, name_)\n"
    outfile.write(s1)
    s1 = "        showIndent(outfile, level)\n"
    outfile.write(s1)
    s1 = "        outfile.write('</%s>\\n' % name_)\n"
    outfile.write(s1)
    s1 = "    def exportAttributes(self, outfile, level, name_='%s'):\n" % element.getName()
    outfile.write(s1)
    hasAttributes = 0
    hasAttributes = generateExportAttributes(outfile, element, hasAttributes)
    if base:
        hasAttributes += 1
        s1 = "        %s.exportAttributes(self, outfile, level, name_='%s')\n" % (
            base,
            element.getName(),
        )
        outfile.write(s1)
    if hasAttributes == 0:
        s1 = "        pass\n"
        outfile.write(s1)
    ##    if len(element.getChildren()) > 0 and not element.isMixed():
    ##        s1 = '        showIndent(outfile, level)\n'
    ##        outfile.write(s1)
    s1 = "    def exportChildren(self, outfile, level, name_='%s'):\n" % element.getName()
    outfile.write(s1)
    hasChildren = 0
    hasChildren = generateExportChildren(outfile, element, hasChildren)
    if base:
        hasChildren += 1
        s1 = "        %s.exportChildren(self, outfile, level, name_)\n" % (base,)
        outfile.write(s1)
    count = countChildren(element, 0)
    if count == 0:
        s1 = "        outfile.write(self.valueOf_)\n"
        outfile.write(s1)


#
# Generate exportLiteral method.
#


def generateExportLiteralFn_1(outfile, child, name, fill):
    mappedName = mapName(name)
    if (
        child.getType() in StringType
        or child.getType() == TokenType
        or child.getType() == DateTimeType
        or child.getType() == DateType
    ):
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('%s=%%s,\\n' %% quote_python(self.get%s()))\n" % (
            fill,
            mappedName,
            name.capitalize(),
        )
        outfile.write(s1)
    elif (
        child.getType() in IntegerType
        or child.getType() == BooleanType
        or child.getType() == PositiveIntegerType
        or child.getType() == NonPositiveIntegerType
        or child.getType() == NegativeIntegerType
        or child.getType() == NonNegativeIntegerType
    ):
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('%s=%%d,\\n' %% self.get%s())\n" % (
            fill,
            mappedName,
            name.capitalize(),
        )
        outfile.write(s1)
    elif child.getType() == FloatType or child.getType() == DecimalType:
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('%s=%%f,\\n' %% self.get%s())\n" % (
            fill,
            mappedName,
            name.capitalize(),
        )
        outfile.write(s1)
    elif child.getType() == DoubleType:
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('%s=%%e,\\n' %% self.get%s())\n" % (
            fill,
            name,
            name.capitalize(),
        )
        outfile.write(s1)
    else:
        s1 = "%s        if self.%s:\n" % (fill, name)
        outfile.write(s1)
        s1 = "%s            showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s            outfile.write('%s=%s(\\n')\n" % (
            fill,
            name,
            child.getType(),
        )
        outfile.write(s1)
        if name == child.getType():
            s1 = "%s            self.%s.exportLiteral(outfile, level)\n" % (fill, name)
        else:
            s1 = "%s            self.%s.exportLiteral(outfile, level, name_='%s')\n" % (
                fill,
                name,
                name,
            )
        outfile.write(s1)
        s1 = "%s            showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s            outfile.write('),\\n')\n" % (fill,)
        outfile.write(s1)


def generateExportLiteralFn_2(outfile, child, name, fill):
    if (
        child.getType() in StringType
        or child.getType() == TokenType
        or child.getType() == DateTimeType
        or child.getType() == DateType
    ):
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('%%s,\\n' %% quote_python(%s))\n" % (fill, name)
        outfile.write(s1)
    elif (
        child.getType() in IntegerType
        or child.getType() == BooleanType
        or child.getType() == PositiveIntegerType
        or child.getType() == NonPositiveIntegerType
        or child.getType() == NegativeIntegerType
        or child.getType() == NonNegativeIntegerType
    ):
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('%%d,\\n' %% %s)\n" % (fill, name)
        outfile.write(s1)
    elif child.getType() == FloatType or child.getType() == DecimalType:
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('%%f,\\n' %% %s)\n" % (fill, name)
        outfile.write(s1)
    elif child.getType() == DoubleType:
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('%%e,\\n' %% %s)\n" % (fill, name)
        outfile.write(s1)
    else:
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('%s(\\n')\n" % (
            fill,
            cleanupName(child.getType()),
        )
        outfile.write(s1)
        if name == child.getType():
            s1 = "%s        %s.exportLiteral(outfile, level)\n" % (
                fill,
                child.getType(),
            )
        else:
            s1 = "%s        %s.exportLiteral(outfile, level, name_='%s')\n" % (
                fill,
                name,
                name,
            )
        outfile.write(s1)
        s1 = "%s        showIndent(outfile, level)\n" % fill
        outfile.write(s1)
        s1 = "%s        outfile.write('),\\n')\n" % (fill,)
        outfile.write(s1)


def generateExportLiteralFn(outfile, prefix, element):
    base = element.getBase()
    s1 = "    def exportLiteral(self, outfile, level, name_='%s'):\n" % element.getName()
    outfile.write(s1)
    s1 = "        level += 1\n"
    outfile.write(s1)
    s1 = "        self.exportLiteralAttributes(outfile, level, name_)\n"
    outfile.write(s1)
    s1 = "        self.exportLiteralChildren(outfile, level, name_)\n"
    outfile.write(s1)
    s1 = "    def exportLiteralAttributes(self, outfile, level, name_):\n"
    outfile.write(s1)
    count = 0
    attrDefs = element.getAttributeDefs()
    for key in attrDefs:
        attrDef = attrDefs[key]
        count += 1
        name = attrDef.getName()
        cleanName = cleanupName(name)
        capName = cleanName.capitalize()
        mappedName = mapName(cleanName)
        s1 = "        showIndent(outfile, level)\n"
        outfile.write(s1)
        ##        ipshell('(generateExportLiteral) -- Entering ipshell.\\nHit Ctrl-D to exit')
        stringType = 0
        data_type = attrDef.getData_type()
        if data_type.find("string") >= 0:
            stringType = 1
        else:
            stringType = 1
        if stringType:
            s1 = "        outfile.write('%s = \"%%s\",\\n' %% (self.get%s(),))\n" % (
                mappedName,
                capName,
            )
        else:
            s1 = "        outfile.write('%s = %%s,\\n' %% (self.get%s(),))\n" % (
                mappedName,
                capName,
            )
        outfile.write(s1)

    if element.getAnyAttribute():
        count += 1
        s1 = "        for name, value in self.anyAttributes_.items():\n"
        outfile.write(s1)
        s1 = "            showIndent(outfile, level)\n"
        outfile.write(s1)
        s1 = "            outfile.write('%s = \"%s\",\\n' % (name, value,))\n"
        outfile.write(s1)
    if count == 0:
        s1 = "        pass\n"
        outfile.write(s1)
    if base:
        s1 = "        %s.exportLiteralAttributes(self, outfile, level, name_)\n" % (base,)
        outfile.write(s1)
    s1 = "    def exportLiteralChildren(self, outfile, level, name_):\n"
    outfile.write(s1)
    for child in element.getChildren():
        name = child.getName()
        name = cleanupName(name)
        # unmappedName = child.getUnmappedCleanName()
        # cleanName = cleanupName(name)
        # mappedName = mapName(cleanName)
        if element.isMixed():
            s1 = "        showIndent(outfile, level)\n"
            outfile.write(s1)
            s1 = "        outfile.write('content_ = [\\n')\n"
            outfile.write(s1)
            s1 = "        for item_ in self.content_:\n"
            outfile.write(s1)
            s1 = "            item_.exportLiteral(outfile, level, name_)\n"
            outfile.write(s1)
            s1 = "        showIndent(outfile, level)\n"
            outfile.write(s1)
            s1 = "        outfile.write('],\\n')\n"
            outfile.write(s1)
        else:
            if child.getMaxOccurs() > 1:
                s1 = "        showIndent(outfile, level)\n"
                outfile.write(s1)
                s1 = "        outfile.write('%s=[\\n')\n" % name
                outfile.write(s1)
                s1 = "        level += 1\n"
                outfile.write(s1)
                s1 = "        for %s in self.%s:\n" % (name, name)
                outfile.write(s1)
                generateExportLiteralFn_2(outfile, child, name, "    ")
                s1 = "        level -= 1\n"
                outfile.write(s1)
                s1 = "        showIndent(outfile, level)\n"
                outfile.write(s1)
                s1 = "        outfile.write('],\\n')\n"
                outfile.write(s1)
            else:
                generateExportLiteralFn_1(outfile, child, name, "")
    if len(element.getChildren()) == 0:
        s1 = "        showIndent(outfile, level)\n"
        outfile.write(s1)
        s1 = "        outfile.write('valueOf_ = \"%s\",\\n' % (self.valueOf_,))\n"
        outfile.write(s1)
    if base:
        s1 = "        %s.exportLiteralChildren(self, outfile, level, name_)\n" % (base,)
        outfile.write(s1)
    # s1 = "        level -= 1\n"
    # outfile.write(s1)


#
# Generate build method.
#


def generateBuildAttributes(outfile, element, hasAttributes):
    attrDefs = element.getAttributeDefs()
    for key in attrDefs:
        attrDef = attrDefs[key]
        hasAttributes += 1
        name = attrDef.getName()
        cleanName = cleanupName(name)
        mappedName = mapName(cleanName)
        atype = attrDef.getData_type()
        if (
            atype in IntegerType
            or atype == PositiveIntegerType
            or atype == NonPositiveIntegerType
            or atype == NegativeIntegerType
            or atype == NonNegativeIntegerType
        ):
            s1 = "        if attrs.get('%s'):\n" % name
            outfile.write(s1)
            s1 = "            try:\n"
            outfile.write(s1)
            s1 = "                self.%s = int(attrs.get('%s').value)\n" % (
                mappedName,
                name,
            )
            outfile.write(s1)
            s1 = "            except ValueError:\n"
            outfile.write(s1)
            s1 = "                raise ValueError('Bad integer attribute (%s)')\n" % (name,)
            outfile.write(s1)
            if atype == PositiveIntegerType:
                s1 = "            if self.%s <= 0:\n" % mappedName
                outfile.write(s1)
                s1 = "                raise ValueError('Invalid PositiveInteger (%s)')\n" % name
                outfile.write(s1)
            elif atype == NonPositiveIntegerType:
                s1 = "            if self.%s > 0:\n" % mappedName
                outfile.write(s1)
                s1 = "                raise ValueError('Invalid NonPositiveInteger (%s)')\n" % name
                outfile.write(s1)
            elif atype == NegativeIntegerType:
                s1 = "            if self.%s >= 0:\n" % mappedName
                outfile.write(s1)
                s1 = "                raise ValueError('Invalid NegativeInteger (%s)')\n" % name
                outfile.write(s1)
            elif atype == NonNegativeIntegerType:
                s1 = "            if self.%s < 0:\n" % mappedName
                outfile.write(s1)
                s1 = "                raise ValueError('Invalid NonNegativeInteger (%s)')\n" % name
                outfile.write(s1)
        elif atype == BooleanType:
            s1 = "        if attrs.get('%s'):\n" % (name,)
            outfile.write(s1)
            s1 = "            if attrs.get('%s').value in ('true', '1'):\n" % (name,)
            outfile.write(s1)
            s1 = "                self.%s = 1\n" % (mappedName,)
            outfile.write(s1)
            s1 = "            elif attrs.get('%s').value in ('false', '0'):\n" % (name,)
            outfile.write(s1)
            s1 = "                self.%s = 0\n" % (mappedName,)
            outfile.write(s1)
            s1 = "            else:\n"
            outfile.write(s1)
            s1 = "                raise ValueError('Bad boolean attribute (%s)')\n" % (name,)
            outfile.write(s1)
        elif atype == FloatType or atype == DoubleType or atype == DecimalType:
            s1 = "        if attrs.get('%s'):\n" % (name,)
            outfile.write(s1)
            s1 = "            try:\n"
            outfile.write(s1)
            s1 = "                self.%s = float(attrs.get('%s').value)\n" % (
                mappedName,
                name,
            )
            outfile.write(s1)
            s1 = "            except:\n"
            outfile.write(s1)
            s1 = "                raise ValueError('Bad float/double attribute (%s)')\n" % (name,)
            outfile.write(s1)
        elif atype == TokenType:
            s1 = "        if attrs.get('%s'):\n" % (name,)
            outfile.write(s1)
            s1 = "            self.%s = attrs.get('%s').value\n" % (
                mappedName,
                name,
            )
            outfile.write(s1)
            s1 = "            self.%s = ' '.join(self.%s.split())\n" % (
                mappedName,
                mappedName,
            )
            outfile.write(s1)
        else:
            # Assume attr['type'] in StringType or attr['type'] == DateTimeType:
            s1 = "        if attrs.get('%s'):\n" % (name,)
            outfile.write(s1)
            s1 = "            self.%s = attrs.get('%s').value\n" % (
                mappedName,
                name,
            )
            outfile.write(s1)
    if element.getAnyAttribute():
        s1 = "        self.anyAttributes_ = {}\n"
        outfile.write(s1)
        s1 = "        for name, value in attrs.items():\n"
        outfile.write(s1)
        s1List = ["            if"]
        firstTime = 1
        for key in attrDefs:
            if firstTime:
                s1List.append(' name != "%s"' % key)
                firstTime = 0
            else:
                s1List.append(' and name != "%s"' % key)
        s1List.append(":\n")
        s1 = "".join(s1List)
        outfile.write(s1)
        s1 = "                self.anyAttributes_[name] = value\n"
        outfile.write(s1)
    return hasAttributes


def generateBuildMixed_1(outfile, prefix, child, headChild, keyword, delayed):
    global DelayedElements, DelayedElements_subclass
    nestedElements = 1
    origName = child.getName()
    name = child.getCleanName()
    headName = cleanupName(headChild.getName())
    childType = child.getType()
    if (
        childType in StringType
        or childType == TokenType
        or childType == DateTimeType
        or childType == DateType
    ):
        s1 = "        %s child_.nodeType == Node.ELEMENT_NODE and \\\n" % keyword
        outfile.write(s1)
        s1 = "            nodeName_ == '%s':\n" % origName
        outfile.write(s1)
        s1 = "            value_ = []\n"
        outfile.write(s1)
        s1 = "            for text_ in child_.childNodes:\n"
        outfile.write(s1)
        s1 = "                value_.append(text_.nodeValue)\n"
        outfile.write(s1)
        s1 = "            valuestr_ = ''.join(value_)\n"
        outfile.write(s1)
        if childType == TokenType:
            s1 = "            valuestr_ = ' '.join(valuestr_.split())\n"
            outfile.write(s1)
        s1 = "            obj_ = self.mixedclass_(MixedContainer.CategorySimple,\n"
        outfile.write(s1)
        s1 = "                MixedContainer.TypeString, '%s', valuestr_)\n" % origName
        outfile.write(s1)
        s1 = "            self.content_.append(obj_)\n"
        outfile.write(s1)
    elif (
        childType in IntegerType
        or childType == PositiveIntegerType
        or childType == NonPositiveIntegerType
        or childType == NegativeIntegerType
        or childType == NonNegativeIntegerType
    ):
        s1 = "        %s child_.nodeType == Node.ELEMENT_NODE and \\\n" % keyword
        outfile.write(s1)
        s1 = "            nodeName_ == '%s':\n" % origName
        outfile.write(s1)
        s1 = "            if child_.firstChild:\n"
        outfile.write(s1)
        s1 = "                sval_ = child_.firstChild.nodeValue\n"
        outfile.write(s1)
        s1 = "                try:\n"
        outfile.write(s1)
        s1 = "                    ival_ = int(sval_)\n"
        outfile.write(s1)
        s1 = "                except ValueError:\n"
        outfile.write(s1)
        s1 = "                    raise ValueError('requires integer -- %s' % child_.toxml())\n"
        outfile.write(s1)
        if childType == PositiveIntegerType:
            s1 = "                if ival_ <= 0:\n"
            outfile.write(s1)
            s1 = "                    raise ValueError('Invalid positiveInteger (%s)' % child_.toxml()))\n"
            outfile.write(s1)
        if childType == NonPositiveIntegerType:
            s1 = "                if ival_ > 0:\n"
            outfile.write(s1)
            s1 = "                    raise ValueError('Invalid nonPositiveInteger (%s)' % child_.toxml()))\n"
            outfile.write(s1)
        if childType == NegativeIntegerType:
            s1 = "                if ival_ >= 0:\n"
            outfile.write(s1)
            s1 = "                    raise ValueError('Invalid negativeInteger (%s)' % child_.toxml()))\n"
            outfile.write(s1)
        if childType == NonNegativeIntegerType:
            s1 = "                if ival_ < 0:\n"
            outfile.write(s1)
            s1 = "                    raise ValueError('Invalid nonNegativeInteger (%s)' % child_.toxml()))\n"
            outfile.write(s1)
        s1 = "            else:\n"
        outfile.write(s1)
        s1 = "                ival_ = -1\n"
        outfile.write(s1)
        s1 = "            obj_ = self.mixedclass_(MixedContainer.CategorySimple,\n"
        outfile.write(s1)
        s1 = "                MixedContainer.TypeInteger, '%s', ival_)\n" % origName
        outfile.write(s1)
        s1 = "            self.content_.append(obj_)\n"
        outfile.write(s1)
    elif childType == BooleanType:
        s1 = "        %s child_.nodeType == Node.ELEMENT_NODE and \\\n" % keyword
        outfile.write(s1)
        s1 = "            nodeName_ == '%s':\n" % origName
        outfile.write(s1)
        s1 = "            if child_.firstChild:\n"
        outfile.write(s1)
        s1 = "                sval_ = child_.firstChild.nodeValue\n"
        outfile.write(s1)
        s1 = "                if sval_ in ('true', '1'):\n"
        outfile.write(s1)
        s1 = "                    ival_ = 1\n"
        outfile.write(s1)
        s1 = "                elif sval_ in ('false', '0'):\n"
        outfile.write(s1)
        s1 = "                    ival_ = 0\n"
        outfile.write(s1)
        s1 = "                else:\n"
        outfile.write(s1)
        s1 = "                    raise ValueError('requires boolean -- %s' % child_.toxml())\n"
        outfile.write(s1)
        s1 = "            obj_ = self.mixedclass_(MixedContainer.CategorySimple,\n"
        outfile.write(s1)
        s1 = "                MixedContainer.TypeInteger, '%s', ival_)\n" % origName
        outfile.write(s1)
        s1 = "            self.content_.append(obj_)\n"
        outfile.write(s1)
    elif childType == FloatType or childType == DoubleType or childType == DecimalType:
        s1 = "        %s child_.nodeType == Node.ELEMENT_NODE and \\\n" % keyword
        outfile.write(s1)
        s1 = "            nodeName_ == '%s':\n" % origName
        outfile.write(s1)
        s1 = "            if child_.firstChild:\n"
        outfile.write(s1)
        s1 = "                sval_ = child_.firstChild.nodeValue\n"
        outfile.write(s1)
        s1 = "                try:\n"
        outfile.write(s1)
        s1 = "                    fval_ = float(sval_)\n"
        outfile.write(s1)
        s1 = "                except ValueError:\n"
        outfile.write(s1)
        s1 = "                    raise ValueError('requires float (or double) -- %s' % child_.toxml())\n"
        outfile.write(s1)
        s1 = "            obj_ = self.mixedclass_(MixedContainer.CategorySimple,\n"
        outfile.write(s1)
        s1 = "                MixedContainer.TypeFloat, '%s', fval_)\n" % origName
        outfile.write(s1)
        s1 = "            self.content_.append(obj_)\n"
        outfile.write(s1)
    else:
        # Perhaps it's a complexType that is defined right here.
        # Generate (later) a class for the nested types.
        if not delayed and not child in DelayedElements:
            DelayedElements.append(child)
            DelayedElements_subclass.append(child)
        s1 = "        %s child_.nodeType == Node.ELEMENT_NODE and \\\n" % keyword
        outfile.write(s1)
        s1 = "            nodeName_ == '%s':\n" % origName
        outfile.write(s1)
        s1 = "            childobj_ = %s%s.factory()\n" % (
            prefix,
            cleanupName(mapName(childType)),
        )
        outfile.write(s1)
        s1 = "            childobj_.build(child_)\n"
        outfile.write(s1)
        s1 = "            obj_ = self.mixedclass_(MixedContainer.CategoryComplex,\n"
        outfile.write(s1)
        s1 = "                MixedContainer.TypeNone, '%s', childobj_)\n" % origName
        outfile.write(s1)
        s1 = "            self.content_.append(obj_)\n"
        outfile.write(s1)


def generateBuildMixed(outfile, prefix, element, keyword, delayed, hasChildren):
    for child in element.getChildren():
        generateBuildMixed_1(outfile, prefix, child, child, keyword, delayed)
        hasChildren += 1
        keyword = "elif"
        # Does this element have a substitutionGroup?
        #   If so generate a clause for each element in the substitutionGroup.
        if child.getName() in SubstitutionGroups:
            for memberName in SubstitutionGroups[child.getName()]:
                if memberName in ElementDict:
                    member = ElementDict[memberName]
                    generateBuildMixed_1(outfile, prefix, member, child, keyword, delayed)
    s1 = "        %s child_.nodeType == Node.TEXT_NODE:\n" % keyword
    outfile.write(s1)
    s1 = "            obj_ = self.mixedclass_(MixedContainer.CategoryText,\n"
    outfile.write(s1)
    s1 = "                MixedContainer.TypeNone, '', child_.nodeValue)\n"
    outfile.write(s1)
    s1 = "            self.content_.append(obj_)\n"
    outfile.write(s1)
    ##    base = element.getBase()
    ##    if base and base in ElementDict:
    ##        parent = ElementDict[base]
    ##        hasChildren = generateBuildMixed(outfile, prefix, parent, keyword, delayed, hasChildren)
    return hasChildren


def generateBuildStandard_1(outfile, prefix, child, headChild, keyword, delayed):
    global DelayedElements, DelayedElements_subclass
    origName = child.getName()
    name = cleanupName(child.getName())
    mappedName = mapName(name)
    headName = cleanupName(headChild.getName())
    attrCount = len(child.getAttributeDefs())
    # dbgprint(1, '(gbs) name: %s  type: %s  complex: %s  id: %s' % \
    #    (child.getName(), child.getType(), child.isComplex(), id(child), ))
    childType = child.getType()
    if attrCount == 0 and (
        childType in StringType
        or childType == TokenType
        or childType == DateTimeType
        or childType == DateType
    ):
        s1 = "        %s child_.nodeType == Node.ELEMENT_NODE and \\\n" % keyword
        outfile.write(s1)
        s1 = "            nodeName_ == '%s':\n" % origName
        outfile.write(s1)
        s1 = "            %s_ = ''\n" % name
        outfile.write(s1)
        s1 = "            for text__content_ in child_.childNodes:\n"
        outfile.write(s1)
        s1 = "                %s_ += text__content_.nodeValue\n" % name
        outfile.write(s1)
        if childType == TokenType:
            s1 = "            %s_ = ' '.join(%s_.split())\n" % (
                name,
                name,
            )
            outfile.write(s1)
        if child.getMaxOccurs() > 1:
            s1 = "            self.%s.append(%s_)\n" % (
                mappedName,
                name,
            )
            outfile.write(s1)
        else:
            s1 = "            self.%s = %s_\n" % (
                mappedName,
                name,
            )
            outfile.write(s1)
    elif (
        childType in IntegerType
        or childType == PositiveIntegerType
        or childType == NonPositiveIntegerType
        or childType == NegativeIntegerType
        or childType == NonNegativeIntegerType
    ):
        s1 = "        %s child_.nodeType == Node.ELEMENT_NODE and \\\n" % keyword
        outfile.write(s1)
        s1 = "            nodeName_ == '%s':\n" % origName
        outfile.write(s1)
        s1 = "            if child_.firstChild:\n"
        outfile.write(s1)
        s1 = "                sval_ = child_.firstChild.nodeValue\n"
        outfile.write(s1)
        s1 = "                try:\n"
        outfile.write(s1)
        s1 = "                    ival_ = int(sval_)\n"
        outfile.write(s1)
        s1 = "                except ValueError:\n"
        outfile.write(s1)
        s1 = "                    raise ValueError('requires integer -- %s' % child_.toxml())\n"
        outfile.write(s1)
        if childType == PositiveIntegerType:
            s1 = "                if ival_ <= 0:\n"
            outfile.write(s1)
            s1 = "                    raise ValueError('requires positiveInteger -- %s' % child_.toxml())\n"
            outfile.write(s1)
        elif childType == NonPositiveIntegerType:
            s1 = "                if ival_ > 0:\n"
            outfile.write(s1)
            s1 = "                    raise ValueError('requires nonPositiveInteger -- %s' % child_.toxml())\n"
            outfile.write(s1)
        elif childType == NegativeIntegerType:
            s1 = "                if ival_ >= 0:\n"
            outfile.write(s1)
            s1 = "                    raise ValueError('requires negativeInteger -- %s' % child_.toxml())\n"
            outfile.write(s1)
        elif childType == NonNegativeIntegerType:
            s1 = "                if ival_ < 0:\n"
            outfile.write(s1)
            s1 = "                    raise ValueError('requires nonNegativeInteger -- %s' % child_.toxml())\n"
            outfile.write(s1)
        if child.getMaxOccurs() > 1:
            s1 = "                self.%s.append(ival_)\n" % (mappedName,)
            outfile.write(s1)
        else:
            s1 = "                self.%s = ival_\n" % (mappedName,)
            outfile.write(s1)
    elif childType == BooleanType:
        s1 = "        %s child_.nodeType == Node.ELEMENT_NODE and \\\n" % keyword
        outfile.write(s1)
        s1 = "            nodeName_ == '%s':\n" % origName
        outfile.write(s1)
        s1 = "            if child_.firstChild:\n"
        outfile.write(s1)
        s1 = "                sval_ = child_.firstChild.nodeValue\n"
        outfile.write(s1)
        s1 = "                if sval_ in ('true', '1'):\n"
        outfile.write(s1)
        s1 = "                    ival_ = 1\n"
        outfile.write(s1)
        s1 = "                elif sval_ in ('false', '0'):\n"
        outfile.write(s1)
        s1 = "                    ival_ = 0\n"
        outfile.write(s1)
        s1 = "                else:\n"
        outfile.write(s1)
        s1 = "                    raise ValueError('requires boolean -- %s' % child_.toxml())\n"
        outfile.write(s1)
        if child.getMaxOccurs() > 1:
            s1 = "                self.%s.append(ival_)\n" % (mappedName,)
            outfile.write(s1)
        else:
            s1 = "                self.%s = ival_\n" % (mappedName,)
            outfile.write(s1)
    elif childType == FloatType or childType == DoubleType or childType == DecimalType:
        s1 = "        %s child_.nodeType == Node.ELEMENT_NODE and \\\n" % keyword
        outfile.write(s1)
        s1 = "            nodeName_ == '%s':\n" % origName
        outfile.write(s1)
        s1 = "            if child_.firstChild:\n"
        outfile.write(s1)
        s1 = "                sval_ = child_.firstChild.nodeValue\n"
        outfile.write(s1)
        s1 = "                try:\n"
        outfile.write(s1)
        s1 = "                    fval_ = float(sval_)\n"
        outfile.write(s1)
        s1 = "                except ValueError:\n"
        outfile.write(s1)
        s1 = "                    raise ValueError('requires float (or double) -- %s' % child_.toxml())\n"
        outfile.write(s1)
        if child.getMaxOccurs() > 1:
            s1 = "                self.%s.append(fval_)\n" % (mappedName,)
            outfile.write(s1)
        else:
            s1 = "                self.%s = fval_\n" % (mappedName,)
            outfile.write(s1)
    else:
        # Perhaps it's a complexType that is defined right here.
        # Generate (later) a class for the nested types.
        if not delayed and not child in DelayedElements:
            DelayedElements.append(child)
            DelayedElements_subclass.append(child)
        s1 = "        %s child_.nodeType == Node.ELEMENT_NODE and \\\n" % keyword
        outfile.write(s1)
        s1 = "            nodeName_ == '%s':\n" % origName
        outfile.write(s1)
        s1 = "            obj_ = %s%s.factory()\n" % (
            prefix,
            cleanupName(mapName(childType)),
        )
        outfile.write(s1)
        s1 = "            obj_.build(child_)\n"
        outfile.write(s1)
        if headChild.getMaxOccurs() > 1:
            s1 = "            self.%s.append(obj_)\n" % headName
            outfile.write(s1)
        else:
            s1 = "            self.set%s(obj_)\n" % headName.capitalize()
            outfile.write(s1)


def generateBuildStandard(outfile, prefix, element, keyword, delayed, hasChildren):
    for child in element.getChildren():
        # dbgprint(1, '(generateBuildStandard) %s type: %s' % (child.getName(), child.getType(),))
        generateBuildStandard_1(outfile, prefix, child, child, keyword, delayed)
        hasChildren += 1
        keyword = "elif"
        # Does this element have a substitutionGroup?
        #   If so generate a clause for each element in the substitutionGroup.
        childName = child.getName()
        if childName in SubstitutionGroups:
            # dbgprint(1, '(BldStd) found: %s in %s' % (childName, SubstitutionGroups))
            for memberName in SubstitutionGroups[childName]:
                memberName = cleanupName(memberName)
                if memberName in ElementDict:
                    member = ElementDict[memberName]
                    # dbgprint(1, '(BldStd) found subst: %s/%s' % (memberName, member))
                    generateBuildStandard_1(outfile, prefix, member, child, keyword, delayed)
    return hasChildren


def generateBuildFn(outfile, prefix, element, delayed):
    base = element.getBase()
    outfile.write("    def build(self, node_):\n")
    outfile.write("        attrs = node_.attributes\n")
    outfile.write("        self.buildAttributes(attrs)\n")
    ##    if len(element.getChildren()) > 0:
    outfile.write("        for child_ in node_.childNodes:\n")
    outfile.write("            nodeName_ = child_.nodeName.split(':')[-1]\n")
    outfile.write("            self.buildChildren(child_, nodeName_)\n")
    outfile.write("    def buildAttributes(self, attrs):\n")
    hasAttributes = generateBuildAttributes(outfile, element, 0)
    if base:
        hasAttributes += 1
        s1 = "        %s.buildAttributes(self, attrs)\n" % (base,)
        outfile.write(s1)
    if hasAttributes == 0:
        outfile.write("        pass\n")
    outfile.write("    def buildChildren(self, child_, nodeName_):\n")
    keyword = "if"
    hasChildren = 0
    if element.isMixed():
        hasChildren = generateBuildMixed(outfile, prefix, element, keyword, delayed, hasChildren)
    else:  # not element.isMixed()
        hasChildren = generateBuildStandard(outfile, prefix, element, keyword, delayed, hasChildren)
    if hasChildren == 0:
        s1 = "        self.valueOf_ = ''\n"
        outfile.write(s1)
        s1 = "        for child in child_.childNodes:\n"
        outfile.write(s1)
        s1 = "            if child.nodeType == Node.TEXT_NODE:\n"
        outfile.write(s1)
        s1 = "                self.valueOf_ += child.nodeValue\n"
        outfile.write(s1)
    if base and base in ElementDict:
        parent = ElementDict[base]
        if len(parent.getChildren()) > 0:
            s1 = "        %s.buildChildren(self, child_, nodeName_)\n" % (base,)
            outfile.write(s1)


def countElementChildren(element, count):
    count += len(element.getChildren())
    base = element.getBase()
    if base and base in ElementDict:
        parent = ElementDict[base]
        countElementChildren(parent, count)
    return count


def buildCtorArgs_multilevel(element):
    content = []
    add = content.append
    buildCtorArgs_multilevel_aux(add, element)
    count = countElementChildren(element, 0)
    if count == 0:
        add(", valueOf_=''")
    if element.isMixed():
        add(", mixedclass_=None")
        add(", content_=None")
    s1 = "".join(content)
    return s1


def buildCtorArgs_multilevel_aux(add, element):
    buildCtorArgs_aux(add, element)
    base = element.getBase()
    if base and base in ElementDict:
        parent = ElementDict[base]
        buildCtorArgs_multilevel_aux(add, parent)


def buildCtorArgs_1_level(element):
    content = []
    add = content.append
    buildCtorArgs_aux(add, element)
    count = countElementChildren(element, 0)
    if count == 0:
        add(", valueOf_=''")
    s1 = "".join(content)
    return s1


def buildCtorArgs_aux(add, element):
    attrDefs = element.getAttributeDefs()
    for key in attrDefs:
        attrDef = attrDefs[key]
        name = attrDef.getName()
        mappedName = name.replace(":", "_")
        mappedName = cleanupName(mapName(mappedName))
        try:
            atype = attrDef.getData_type()
        except KeyError:
            atype = StringType
        if atype in StringType or atype == TokenType or atype == DateTimeType or atype == DateType:
            add(", %s=''" % mappedName)
        elif atype in IntegerType:
            add(", %s=-1" % mappedName)
        elif atype == PositiveIntegerType:
            add(", %s=1" % mappedName)
        elif atype == NonPositiveIntegerType:
            add(", %s=0" % mappedName)
        elif atype == NegativeIntegerType:
            add(", %s=-1" % mappedName)
        elif atype == NonNegativeIntegerType:
            add(", %s=0" % mappedName)
        elif atype == BooleanType:
            add(", %s=0" % mappedName)
        elif atype == FloatType or atype == DoubleType or atype == DecimalType:
            add(", %s=0.0" % mappedName)
        else:
            add(", %s=None" % mappedName)
    nestedElements = 0
    for child in element.getChildren():
        nestedElements = 1
        if child.getMaxOccurs() > 1:
            add(", %s=None" % child.getCleanName())
        else:
            childType = child.getType()
            if (
                childType in StringType
                or childType == TokenType
                or childType == DateTimeType
                or childType == DateType
            ):
                add(", %s=''" % child.getCleanName())
            elif childType in IntegerType:
                add(", %s=-1" % child.getCleanName())
            elif childType == PositiveIntegerType:
                add(", %s=1" % child.getCleanName())
            elif childType == NonPositiveIntegerType:
                add(", %s=0" % child.getCleanName())
            elif childType == NegativeIntegerType:
                add(", %s=-1" % child.getCleanName())
            elif childType == NonNegativeIntegerType:
                add(", %s=0" % child.getCleanName())
            elif childType == BooleanType:
                add(", %s=0" % child.getCleanName())
            elif childType == FloatType or childType == DoubleType or childType == DecimalType:
                add(", %s=0.0" % child.getCleanName())
            else:
                add(", %s=None" % child.getCleanName())


MixedCtorInitializers = """\
        if mixedclass_ is None:
            self.mixedclass_ = MixedContainer
        else:
            self.mixedclass_ = mixedclass_
        if content_ is None:
            self.content_ = []
        else:
            self.content_ = content_
"""


def generateCtor(outfile, element):
    s2 = buildCtorArgs_multilevel(element)
    s1 = "    def __init__(self%s):\n" % s2
    outfile.write(s1)
    base = element.getBase()
    if base and base in ElementDict:
        parent = ElementDict[base]
        s2 = buildCtorParams(parent)
        s1 = "        %s.__init__(self%s)\n" % (
            base,
            s2,
        )
        outfile.write(s1)
    attrDefs = element.getAttributeDefs()
    for key in attrDefs:
        attrDef = attrDefs[key]
        mappedName = cleanupName(attrDef.getName())
        mappedName = mapName(mappedName)
        s1 = "        self.%s = %s\n" % (mappedName, mappedName)
        outfile.write(s1)
        member = 1
    # Generate member initializers in ctor.
    if element.isMixed():
        outfile.write(MixedCtorInitializers)
    else:
        member = 0
        nestedElements = 0
        for child in element.getChildren():
            name = cleanupName(child.getCleanName())
            if child.getMaxOccurs() > 1:
                s1 = "        if %s is None:\n" % (name,)
                outfile.write(s1)
                s1 = "            self.%s = []\n" % (name,)
                outfile.write(s1)
                s1 = "        else:\n"
                outfile.write(s1)
                s1 = "            self.%s = %s\n" % (name, name)
                outfile.write(s1)
            else:
                s1 = "        self.%s = %s\n" % (name, name)
                outfile.write(s1)
            member = 1
            nestedElements = 1
        if not nestedElements:
            s1 = "        self.valueOf_ = valueOf_\n"
            outfile.write(s1)
            member = 1
        if element.getAnyAttribute():
            s1 = "        self.anyAttributes_ = {}\n"
            outfile.write(s1)
            member = 1
        if not member:
            outfile.write("        pass\n")


# Generate get/set/add member functions.
def generateGettersAndSetters(outfile, element):
    nestedElements = 0
    for child in element.getChildren():
        nestedElements = 1
        name = cleanupName(child.getCleanName())
        unmappedName = cleanupName(child.getName())
        capName = unmappedName.capitalize()
        s1 = "    def get%s(self): return self.%s\n" % (capName, name)
        outfile.write(s1)
        s1 = "    def set%s(self, %s): self.%s = %s\n" % (capName, name, name, name)
        outfile.write(s1)
        if child.getMaxOccurs() > 1:
            s1 = "    def add%s(self, value): self.%s.append(value)\n" % (capName, name)
            outfile.write(s1)
            s1 = "    def insert%s(self, index, value): self.%s[index] = value\n" % (
                capName,
                name,
            )
            outfile.write(s1)
        if GenerateProperties:
            s1 = "    %sProp = property(get%s, set%s)\n" % (
                unmappedName,
                capName,
                capName,
            )
            outfile.write(s1)
    attrDefs = element.getAttributeDefs()
    for key in attrDefs:
        attrDef = attrDefs[key]
        name = cleanupName(attrDef.getName().replace(":", "_"))
        mappedName = mapName(name)
        capName = mappedName.capitalize()
        s1 = "    def get%s(self): return self.%s\n" % (name.capitalize(), mappedName)
        outfile.write(s1)
        #
        # What?  An attribute cannot occur multiple times on the same
        #   element.  No attribute is a list of values.  Right?
        ##        if element.getMaxOccurs() > 1:
        ##            s1 = '    def add%s(self, %s): self.%s.append(%s)\n' % \
        ##                (capName, mappedName, mappedName, mappedName)
        ##            outfile.write(s1)
        ##            s1 = '    def set%s(self, %s, index): self.%s[index] = %s\n' % \
        ##                (name.capitalize(), mappedName, mappedName, mappedName)
        ##            outfile.write(s1)
        ##        else:
        s1 = "    def set%s(self, %s): self.%s = %s\n" % (
            name.capitalize(),
            mappedName,
            mappedName,
            mappedName,
        )
        outfile.write(s1)
        if GenerateProperties:
            s1 = "    %sProp = property(get%s, set%s)\n" % (
                mappedName,
                capName,
                capName,
            )
            outfile.write(s1)
    if not nestedElements:
        s1 = "    def getValueOf_(self): return self.valueOf_\n"
        outfile.write(s1)
        s1 = "    def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_\n"
        outfile.write(s1)
    if element.getAnyAttribute():
        s1 = "    def getAnyAttributes_(self): return self.anyAttributes_\n"
        outfile.write(s1)
        s1 = "    def setAnyAttributes_(self, anyAttributes_): self.anyAttributes_ = anyAttributes_\n"
        outfile.write(s1)


def generateClasses(outfile, prefix, element, delayed):
    base = element.getBase()
    wrt = outfile.write
    if (not element.getChildren()) and (not element.getAttributeDefs()):
        return
    # If this element is an extension (has a base) and the base has
    #   not been generated, then postpone it.
    if base and base in ElementDict:
        parent = ElementDict[base]
        parentName = parent.getName()
        if parentName not in AlreadyGenerated:
            PostponedExtensions.append(element)
            return
    if element.getName() in AlreadyGenerated:
        return
    AlreadyGenerated.append(element.getName())
    if element.getMixedExtensionError():
        print(
            "*** Element %s extension chain contains mixed and non-mixed content.  Not generated."
            % (element.getName(),)
        )
        return
    ElementsForSubclasses.append(element)
    name = element.getCleanName()
    if GenerateProperties:
        if base:
            s1 = "class %s%s(object, %s):\n" % (prefix, name, base)
        else:
            s1 = "class %s%s(object):\n" % (prefix, name)
    else:
        if base:
            s1 = "class %s%s(%s):\n" % (prefix, name, base)
        else:
            s1 = "class %s%s:\n" % (prefix, name)
    wrt(s1)
    wrt("    subclass = None\n")
    generateCtor(outfile, element)
    wrt("    def factory(*args_, **kwargs_):\n")
    wrt("        if %s%s.subclass:\n" % (prefix, name))
    wrt("            return %s%s.subclass(*args_, **kwargs_)\n" % (prefix, name))
    wrt("        else:\n")
    wrt("            return %s%s(*args_, **kwargs_)\n" % (prefix, name))
    wrt("    factory = staticmethod(factory)\n")
    generateGettersAndSetters(outfile, element)
    generateExportFn(outfile, prefix, element)
    generateExportLiteralFn(outfile, prefix, element)
    generateBuildFn(outfile, prefix, element, delayed)
    wrt("# end class %s\n" % name)
    wrt("\n\n")


#
# Generate the SAX handler class for SAX parsing.
#

SAX_STARTELEMENT_1 = """\
    def startElement(self, name, attrs):
        done = 0
        if name == '%s':
            obj = %s.factory()
            stackObj = SaxStackElement('%s', obj)
            self.stack.append(stackObj)
            done = 1
"""

SAX_STARTELEMENT_2 = """\
            stackObj = SaxStackElement('%s', obj)
            self.stack.append(stackObj)
            done = 1
"""

SAX_STARTELEMENT_3 = """\
            stackObj = SaxStackElement('%s', None)
            self.stack.append(stackObj)
            done = 1
"""

SAX_STARTELEMENT_4 = """\
        if not done:
            self.reportError('"%s" element not allowed here.' % name)
"""

SAX_ATTR_INTEGER = """\
            val = attrs.get('%s', None)
            if val is not None:
                try:
                    obj.set%s(int(val))
                except:
                    self.reportError('"%s" attribute must be integer')
"""

SAX_ATTR_BOOLEAN = """\
            val = attrs.get('%s', None)
            if val is not None:
                if val in ('true', '1'):
                    obj.set%s(1)
                elif val in ('false', '0'):
                    obj.set%s(0)
                else:
                    self.reportError('"%s" attribute must be boolean ("true", "1", "false", "0")')
"""

SAX_ATTR_FLOAT = """\
            val = attrs.get('%s', None)
            if val is not None:
                try:
                    obj.set%s(float(val))
                except:
                    self.reportError('"%s" attribute must be float')
"""

SAX_ATTR_STRING = """\
            val = attrs.get('%s', None)
            if val is not None:
                obj.set%s(val)
"""


def getClassName(element):
    name = element.getCleanName()
    return name


def generateSaxAttributes(wrt, element):
    attrDefs = element.getAttributeDefs()
    for key in attrDefs:
        attrDef = attrDefs[key]
        name = attrDef.getName()
        atype = attrDef.getData_type()
        if atype in IntegerType:
            s1 = SAX_ATTR_INTEGER % (name, name.capitalize(), name)
            wrt(s1)
        ##             s1 = "            if attrs.get('%s'):\n" % name
        ##             wrt(s1)
        ##             s1 = '                try:\n'
        ##             wrt(s1)
        ##             s1 = "                    self.%s = int(attrs.get('%s').value)\n" % \
        ##                 (name, name)
        ##             wrt(s1)
        ##             s1 = '                except ValueError:\n'
        ##             wrt(s1)
        ##             s1 = "                    raise ValueError('Bad integer')\n"
        ##             wrt(s1)
        elif atype == BooleanType:
            s1 = SAX_ATTR_BOOLEAN % (name, name.capitalize(), name.capitalize(), name)
            wrt(s1)
        ##             wrt(s1)
        ##             s1 = "            if attrs.get('%s'):\n" % name
        ##             wrt(s1)
        ##             s1 = "                if attrs.get('%s').value in ('true', '1'):\n" % \
        ##                 name
        ##             wrt(s1)
        ##             s1 = "                    self.%s = 1\n" % \
        ##                 name
        ##             wrt(s1)
        ##             s1 = "                elif attrs.get('%s').value in ('false', '0'):\n" % \
        ##                 name
        ##             wrt(s1)
        ##             s1 = "                    self.%s = 0\n" % \
        ##                 name
        ##             wrt(s1)
        ##             s1 = '            else:\n'
        ##             wrt(s1)
        ##             s1 = "                raise ValueError('Bad boolean')\n"
        ##             wrt(s1)
        elif atype == FloatType or atype == DoubleType or atype == DecimalType:
            s1 = SAX_ATTR_FLOAT % (name, name.capitalize(), name)
            wrt(s1)
        ##             s1 = "            if attrs.get('%s'):\n" % name
        ##             wrt(s1)
        ##             s1 = '                try:\n'
        ##             wrt(s1)
        ##             s1 = "                    self.%s = float(attrs.get('%s').value)\n" % \
        ##                 (name, name)
        ##             wrt(s1)
        ##             s1 = '                except:\n'
        ##             wrt(s1)
        ##             s1 = "                    raise ValueError('Bad float/double')\n"
        ##             wrt(s1)
        else:
            # Assume attr['type'] in StringType or attr['type'] == DateTimeType:
            s1 = SAX_ATTR_STRING % (name, name.capitalize())
            wrt(s1)


##             s1 = "            if attrs.get('%s'):\n" % name
##             wrt(s1)
##             s1 = "                self.%s = attrs.get('%s').value\n" % (name, name)
##             wrt(s1)


def generateSAXStartElement_1(wrt, element):
    origName = element.getName()
    typeName = cleanupName(mapName(element.getRawType()))
    className = element.getCleanName()
    s1 = "        elif name == '%s':\n" % origName
    wrt(s1)
    if element.isComplex():
        s1 = "            obj = %s.factory()\n" % cleanupName(typeName)
        wrt(s1)
    element1 = SaxElementDict[element.getCleanName()]
    generateSaxAttributes(wrt, element1)
    if element.isComplex():
        s1 = SAX_STARTELEMENT_2 % className
    else:
        s1 = SAX_STARTELEMENT_3 % className
    wrt(s1)


def generateSAXStartElement(outfile, root, elementList):
    wrt = outfile.write
    name = root.getChildren()[0].getName()
    s1 = SAX_STARTELEMENT_1 % (name, name, name)
    wrt(s1)
    for element, parent in elementList:
        generateSAXStartElement_1(wrt, element)
    s1 = SAX_STARTELEMENT_4
    wrt(s1)
    wrt("\n")


SAX_ENDELEMENT_1 = """\
        if name == '%s':
            if len(self.stack) == 1:
                self.root = self.stack[-1].obj
                self.stack.pop()
                done = 1
"""

SAX_ENDELEMENT_2 = """\
        elif name == '%s':
            if len(self.stack) >= 2:
                self.stack[-2].obj.%s%s(self.stack[-1].obj)
                self.stack.pop()
                done = 1
"""

SAX_ENDELEMENT_3 = """\
        elif name == '%s':
            if len(self.stack) >= 2:
                content = self.stack[-1].content
%s                self.stack[-2].obj.%s%s(content)
                self.stack.pop()
                done = 1
"""

SAX_ENDELEMENT_INT = """\
                if content:
                    try:
                        content = int(content)
                    except:
                        self.reportError('"%s" must be integer -- content: %%s' %% content)
                else:
                    content = -1
"""

SAX_ENDELEMENT_FLOAT = """\
                if content:
                    try:
                        content = float(content)
                    except:
                        self.reportError('"%s" must be float -- content: %%s' %% content)
                else:
                    content = -1
"""

SAX_ENDELEMENT_BOOLEAN = """\
                if content and content in ('true', '1'):
                    content = 1
                else:
                    content = 0
"""

SAX_ENDELEMENT_4 = """\
        if not done:
            self.reportError('"%s" element not allowed here.' % name)
"""


def generateParentCheck(parent):
    s1 = "self.stack[-2].name == '%s'" % getClassName(parent)
    return s1


##     strList = []
##     for parent in parentList:
##         strList.append("self.stack[-2].name == '%s'" % \
##             parent.getName())
##     s1 = ' or '.join(strList)
##     if len(parentList) > 1:
##         s1 = '(%s)' % s1
##     return s1


def generateSAXEndElement(outfile, root, elementList):
    wrt = outfile.write
    s1 = "    def endElement(self, name):\n"
    wrt(s1)
    s1 = "        done = 0\n"
    wrt(s1)
    name = root.getChildren()[0].getName()
    s1 = SAX_ENDELEMENT_1 % (name,)
    wrt(s1)
    for element, parent in elementList:
        # s2 = generateParentCheck(parent)
        name = element.getName()
        capName = element.getUnmappedCleanName().capitalize()
        if element.isComplex():
            if element.getMaxOccurs() > 1:
                s1 = SAX_ENDELEMENT_2 % (name, "add", capName)
            else:
                s1 = SAX_ENDELEMENT_2 % (name, "set", capName)
        else:
            etype = element.getType()
            if etype in IntegerType:
                s3 = SAX_ENDELEMENT_INT % name
            elif etype == FloatType or etype == DoubleType or etype == DecimalType:
                s3 = SAX_ENDELEMENT_FLOAT % name
            elif etype == BooleanType:
                s3 = SAX_ENDELEMENT_BOOLEAN
            else:
                s3 = ""
            if element.getMaxOccurs() > 1:
                s1 = SAX_ENDELEMENT_3 % (name, s3, "add", capName)
            else:
                s1 = SAX_ENDELEMENT_3 % (name, s3, "set", capName)
        wrt(s1)
    s1 = SAX_ENDELEMENT_4
    wrt(s1)
    wrt("\n")


SAX_HEADER = """\
from xml.sax import handler, make_parser

class SaxStackElement:
    def __init__(self, name='', obj=None):
        self.name = name
        self.obj = obj
        self.content = ''

#
# SAX handler
#
class Sax%sHandler(handler.ContentHandler):
    def __init__(self):
        self.stack = []
        self.root = None

    def getRoot(self):
        return self.root

    def setDocumentLocator(self, locator):
        self.locator = locator

    def showError(self, msg):
        print('*** (showError):', msg)
        sys.exit(-1)

"""

SAX_FOOTER = """\
    def characters(self, chrs, start, end):
        if len(self.stack) > 0:
            self.stack[-1].content += chrs[start:end]

    def reportError(self, mesg):
        locator = self.locator
        sys.stderr.write('Doc: %s  Line: %d  Column: %d\\n' % \\
            (locator.getSystemId(), locator.getLineNumber(),
            locator.getColumnNumber() + 1))
        sys.stderr.write(mesg)
        sys.stderr.write('\\n')
        sys.exit(-1)
        #raise RuntimeError

"""


##def produceAllElements(element, parent):
##     if element.getType() in StringType or \
##         element.getType() in IntegerType or \
##         element.getType() == DecimalType or \
##         element.getType() == FloatType or \
##         element.getType() == DoubleType or \
##         element.getType() == BooleanType or \
##         len(element.getChildren()) != 0:
##    yield (element, parent)
##    for child in element.getChildren():
##        for element1, parent1 in produceAllElements(child, element):
##            yield (element1, parent1)


#
# This version of produceAllElements does not use 'yield' and is,
#   therefore, usable with older versions of Python.
def produceAllElements_nogen(element, parent, collection):
    collection.append((element, parent))
    for child in element.getChildren():
        produceAllElements_nogen(child, element, collection)


def generateSAXHndlr(outfile, root):
    firstElement = root.getChildren()[0]
    name = firstElement.getName()
    s1 = SAX_HEADER % cleanupName(name.capitalize())
    outfile.write(s1)
    elementList = []
    collection = []
    produceAllElements_nogen(root, None, collection)
    for element, parent in collection:
        if element == root:
            continue
        elementList.append((element, parent))
    ##         print '(gsh) element: %s/%s/%d  parent: %s/%s/%d' % \
    ##             (element.getUnmappedCleanName(), element.getType(), id(element),
    ##             #(element.getName(), element.getType(), id(element),
    ##             parent.getName(), parent.getType(), id(parent))
    ##         if parent.getName() == 'booster':
    ##             ipshell('at booster -- Entering ipshell.\\nHit Ctrl-D to exit')
    ##         if element in elementDict:
    ##             elementDict[element].append(parent)
    ##         else:
    ##             elementDict[element] = [parent]
    elementList1 = []
    alreadySeen = []
    for element, parent in elementList:
        if parent == root:
            continue
        if element.getName() in alreadySeen:
            continue
        alreadySeen.append(element.getName())
        elementList1.append((element, parent))
    ##     print '+' * 20
    ##     for element, parent in elementList1:
    ##         print '(gsh) element: %s/%s/%d  parent: %s/%s/%d' % \
    ##             (element.getUnmappedCleanName(), element.getType(), id(element),
    ##             #(element.getName(), element.getType(), id(element),
    ##             parent.getName(), parent.getType(), id(parent))
    generateSAXStartElement(outfile, root, elementList1)
    generateSAXEndElement(outfile, root, elementList1)
    s1 = SAX_FOOTER
    outfile.write(s1)


def collect(element, elements):
    if element.getName() != "root":
        elements.append(element)
    for child in element.getChildren():
        collect(child, elements)


TEMPLATE_HEADER = """\
#!/usr/bin/env python3

#
# Generated %s by generateDS.py.
# Update it with: python generateDS.py -o generateModel_Module.py generateMetaModel_Module.xsd
#
# WARNING! All changes made in this file will be lost!
#


import sys
import getopt
from xml.dom import minidom
from xml.dom import Node

#
# If you have installed IPython you can uncomment and use the following.
# IPython is available from http://ipython.scipy.org/.
#

## from IPython.Shell import IPShellEmbed
## args = ''
## ipshell = IPShellEmbed(args,
##     banner = 'Dropping into IPython',
##     exit_msg = 'Leaving Interpreter, back to program.')

# Then use the following line where and when you want to drop into the
# IPython shell:
#    ipshell('<some message> -- Entering ipshell.\\nHit Ctrl-D to exit')

#
# Support/utility functions.
#

def showIndent(outfile, level):
    for idx in range(level):
        outfile.write('    ')

def quote_xml(inStr):
    s1 = inStr
    s1 = s1.replace('&', '&amp;')
    s1 = s1.replace('<', '&lt;')
    s1 = s1.replace('"', '&quot;')
    return s1

def quote_python(inStr):
    s1 = inStr
    if s1.find("'") == -1:
        if s1.find('\\n') == -1:
            return "'%%s'" %% s1
        else:
            return "'''%%s'''" %% s1
    else:
        if s1.find('"') != -1:
            s1 = s1.replace('"', '\\\\"')
        if s1.find('\\n') == -1:
            return '"%%s"' %% s1
        else:
            return '\"\"\"%%s\"\"\"' %% s1


class MixedContainer:
    # Constants for category:
    CategoryNone = 0
    CategoryText = 1
    CategorySimple = 2
    CategoryComplex = 3
    # Constants for content_type:
    TypeNone = 0
    TypeText = 1
    TypeString = 2
    TypeInteger = 3
    TypeFloat = 4
    TypeDecimal = 5
    TypeDouble = 6
    TypeBoolean = 7
    def __init__(self, category, content_type, name, value):
        self.category = category
        self.content_type = content_type
        self.name = name
        self.value = value
    def getCategory(self):
        return self.category
    def getContenttype(self, content_type):
        return self.content_type
    def getValue(self):
        return self.value
    def getName(self):
        return self.name
    def export(self, outfile, level, name):
        if self.category == MixedContainer.CategoryText:
            outfile.write(self.value)
        elif self.category == MixedContainer.CategorySimple:
            self.exportSimple(outfile, level, name)
        else:    # category == MixedContainer.CategoryComplex
            self.value.export(outfile, level, name)
    def exportSimple(self, outfile, level, name):
        if self.content_type == MixedContainer.TypeString:
            outfile.write('<%%s>%%s</%%s>' %% (self.name, self.value, self.name))
        elif self.content_type == MixedContainer.TypeInteger or \\
                self.content_type == MixedContainer.TypeBoolean:
            outfile.write('<%%s>%%d</%%s>' %% (self.name, self.value, self.name))
        elif self.content_type == MixedContainer.TypeFloat or \\
                self.content_type == MixedContainer.TypeDecimal:
            outfile.write('<%%s>%%f</%%s>' %% (self.name, self.value, self.name))
        elif self.content_type == MixedContainer.TypeDouble:
            outfile.write('<%%s>%%g</%%s>' %% (self.name, self.value, self.name))
    def exportLiteral(self, outfile, level, name):
        if self.category == MixedContainer.CategoryText:
            showIndent(outfile, level)
            outfile.write('MixedContainer(%%d, %%d, "%%s", "%%s"),\\n' %% \\
                (self.category, self.content_type, self.name, self.value))
        elif self.category == MixedContainer.CategorySimple:
            showIndent(outfile, level)
            outfile.write('MixedContainer(%%d, %%d, "%%s", "%%s"),\\n' %% \\
                (self.category, self.content_type, self.name, self.value))
        else:    # category == MixedContainer.CategoryComplex
            showIndent(outfile, level)
            outfile.write('MixedContainer(%%d, %%d, "%%s",\\n' %% \\
                (self.category, self.content_type, self.name,))
            self.value.exportLiteral(outfile, level + 1)
            showIndent(outfile, level)
            outfile.write(')\\n')


#
# Data representation classes.
#

"""

# Fool (and straighten out) the syntax highlighting.
# DUMMY = '''


def generateHeader(outfile, prefix):
    s1 = TEMPLATE_HEADER % time.ctime()
    outfile.write(s1)


TEMPLATE_MAIN = """\
USAGE_TEXT = \"\"\"
Usage: python <%(prefix)sParser>.py [ -s ] <in_xml_file>
Options:
    -s        Use the SAX parser, not the minidom parser.
\"\"\"

def usage():
    print(USAGE_TEXT)
    sys.exit(-1)


#
# SAX handler used to determine the top level element.
#
class SaxSelectorHandler(handler.ContentHandler):
    def __init__(self):
        self.topElementName = None
    def getTopElementName(self):
        return self.topElementName
    def startElement(self, name, attrs):
        self.topElementName = name
        raise StopIteration


def parseSelect(inFileName):
    infile = open(inFileName, 'r')
    topElementName = None
    parser = make_parser()
    documentHandler = SaxSelectorHandler()
    parser.setContentHandler(documentHandler)
    try:
        try:
            parser.parse(infile)
        except StopIteration:
            topElementName = documentHandler.getTopElementName()
        if topElementName is None:
            raise RuntimeError('no top level element')
        topElementName = topElementName.replace('-', '_').replace(':', '_')
        if topElementName not in globals():
            raise RuntimeError('no class for top element: %%s' %% topElementName)
        topElement = globals()[topElementName]
        infile.seek(0)
        doc = minidom.parse(infile)
    finally:
        infile.close()
    rootNode = doc.childNodes[0]
    rootObj = topElement.factory()
    rootObj.build(rootNode)
    # Enable Python to collect the space used by the DOM.
    doc = None
    sys.stdout.write('<?xml version="1.0" ?>\\n')
    rootObj.export(sys.stdout, 0)
    return rootObj


def saxParse(inFileName):
    parser = make_parser()
    documentHandler = Sax%(cap_name)sHandler()
    parser.setDocumentHandler(documentHandler)
    parser.parse('file:%%s' %% inFileName)
    root = documentHandler.getRoot()
    sys.stdout.write('<?xml version="1.0" ?>\\n')
    root.export(sys.stdout, 0)
    return root


def saxParseString(inString):
    parser = make_parser()
    documentHandler = Sax%(cap_name)sHandler()
    parser.setDocumentHandler(documentHandler)
    parser.feed(inString)
    parser.close()
    rootObj = documentHandler.getRoot()
    #sys.stdout.write('<?xml version="1.0" ?>\\n')
    #rootObj.export(sys.stdout, 0)
    return rootObj


def parse(inFileName):
    doc = minidom.parse(inFileName)
    rootNode = doc.documentElement
    rootObj = %(prefix)s%(root)s.factory()
    rootObj.build(rootNode)
    # Enable Python to collect the space used by the DOM.
    doc = None
    sys.stdout.write('<?xml version="1.0" ?>\\n')
    rootObj.export(sys.stdout, 0, name_="%(name)s")
    return rootObj


def parseString(inString):
    doc = minidom.parseString(inString)
    rootNode = doc.documentElement
    rootObj = %(prefix)s%(root)s.factory()
    rootObj.build(rootNode)
    # Enable Python to collect the space used by the DOM.
    doc = None
    sys.stdout.write('<?xml version="1.0" ?>\\n')
    rootObj.export(sys.stdout, 0, name_="%(name)s")
    return rootObj


def parseLiteral(inFileName):
    doc = minidom.parse(inFileName)
    rootNode = doc.documentElement
    rootObj = %(prefix)s%(root)s.factory()
    rootObj.build(rootNode)
    # Enable Python to collect the space used by the DOM.
    doc = None
    sys.stdout.write('from %(module_name)s import *\\n\\n')
    sys.stdout.write('rootObj = %(name)s(\\n')
    rootObj.exportLiteral(sys.stdout, 0, name_="%(name)s")
    sys.stdout.write(')\\n')
    return rootObj


def main():
    args = sys.argv[1:]
    if len(args) == 2 and args[0] == '-s':
        saxParse(args[1])
    elif len(args) == 1:
        parse(args[0])
    else:
        usage()


if __name__ == '__main__':
    main()
    #import pdb
    #pdb.run('main()')

"""


# Fool (and straighten out) the syntax highlighting.
# DUMMY = '''


def generateMain(outfile, prefix, root):
    name = root.getChildren()[0].getName()
    elType = cleanupName(root.getChildren()[0].getType())
    if RootElement:
        rootElement = RootElement
    else:
        rootElement = elType
    params = {
        "prefix": prefix,
        "cap_name": cleanupName(name.capitalize()),
        "name": cleanupName(name),
        "module_name": os.path.splitext(os.path.basename(outfile.name))[0],
        "root": rootElement,
    }
    s1 = TEMPLATE_MAIN % params
    outfile.write(s1)


def buildCtorParams(element):
    content = []
    add = content.append
    if element.isMixed():
        add(", mixedclass_")
        add(", content_")
    else:
        buildCtorParams_aux(add, element)
    s1 = "".join(content)
    return s1


def buildCtorParams_aux(add, element):
    attrDefs = element.getAttributeDefs()
    for key in attrDefs:
        attrDef = attrDefs[key]
        name = attrDef.getName()
        cleanName = cleanupName(mapName(name))
        add(", %s" % cleanName)
    for child in element.getChildren():
        add(", %s" % child.getCleanName())
    base = element.getBase()
    if base and base in ElementDict:
        parent = ElementDict[base]
        buildCtorParams_aux(add, parent)


def get_class_behavior_args(classBehavior):
    argList = []
    args = classBehavior.getArgs()
    args = args.getArg()
    # print '(get_class_behavior_args) args:', args
    for arg in args:
        argList.append(arg.getName())
    argString = ", ".join(argList)
    return argString


#
# Retrieve the implementation body via an HTTP request to a
#   URL formed from the concatenation of the baseImplUrl and the
#   implUrl.
# An alternative implementation of get_impl_body() that also
#   looks in the local file system is commented out below.
#
def get_impl_body(classBehavior, baseImplUrl, implUrl):
    impl = "        pass\n"
    if implUrl:
        if baseImplUrl:
            implUrl = "%s%s" % (baseImplUrl, implUrl)
        try:
            implFile = urlopen(implUrl)
            impl = implFile.read()
            implFile.close()
        except HTTPError:
            print("*** Implementation at %s not found." % implUrl)
    return impl


###
### This alternative implementation of get_impl_body() tries the URL
###   via http first, then, if that fails, looks in a directory on
###   the local file system (baseImplUrl) for a file (implUrl)
###   containing the implementation body.
###
##def get_impl_body(classBehavior, baseImplUrl, implUrl):
##    impl = '        pass\n'
##    if implUrl:
##        trylocal = 0
##        if baseImplUrl:
##            implUrl = '%s%s' % (baseImplUrl, implUrl)
##        try:
##            implFile = urlopen(implUrl)
##            impl = implFile.read()
##            implFile.close()
##        except:
##            trylocal = 1
##        if trylocal:
##            try:
##                implFile = open(implUrl)
##                impl = implFile.read()
##                implFile.close()
##            except:
##                print ('*** Implementation at %s not found.' % implUrl)
##    return impl


def generateClassBehaviors(wrt, classBehaviors, baseImplUrl):
    for classBehavior in classBehaviors:
        behaviorName = classBehavior.getName()
        #
        # Generate the core behavior.
        argString = get_class_behavior_args(classBehavior)
        if argString:
            wrt("    def %s(self, %s, *args):\n" % (behaviorName, argString))
        else:
            wrt("    def %s(self, *args):\n" % (behaviorName,))
        implUrl = classBehavior.getImpl_url()
        impl = get_impl_body(classBehavior, baseImplUrl, implUrl)
        wrt(impl)
        wrt("\n")
        #
        # Generate the ancillaries for this behavior.
        ancillaries = classBehavior.getAncillaries()
        if ancillaries:
            ancillaries = ancillaries.getAncillary()
        if ancillaries:
            for ancillary in ancillaries:
                argString = get_class_behavior_args(ancillary)
                if argString:
                    wrt("    def %s(self, %s, *args):\n" % (ancillary.getName(), argString))
                else:
                    wrt("    def %s(self, *args):\n" % (ancillary.getName(),))
                implUrl = ancillary.getImpl_url()
                impl = get_impl_body(classBehavior, baseImplUrl, implUrl)
                wrt(impl)
                wrt("\n")
        #
        # Generate the wrapper method that calls the ancillaries and
        #   the core behavior.
        argString = get_class_behavior_args(classBehavior)
        if argString:
            wrt("    def %s_wrapper(self, %s, *args):\n" % (behaviorName, argString))
        else:
            wrt("    def %s_wrapper(self, *args):\n" % (behaviorName,))
        if ancillaries:
            for ancillary in ancillaries:
                role = ancillary.getRole()
                if role == "DBC-precondition":
                    wrt("        if not self.%s(*args)\n" % (ancillary.getName(),))
                    wrt("            return False\n")
        if argString:
            wrt("        result = self.%s(%s, *args)\n" % (behaviorName, argString))
        else:
            wrt("        result = self.%s(*args)\n" % (behaviorName,))
        if ancillaries:
            for ancillary in ancillaries:
                role = ancillary.getRole()
                if role == "DBC-postcondition":
                    wrt("        if not self.%s(*args)\n" % (ancillary.getName(),))
                    wrt("            return False\n")
        wrt("        return result\n")
        wrt("\n")


def generateSubclass(outfile, element, prefix, xmlbehavior, behaviors, baseUrl):
    wrt = outfile.write
    if not element.isComplex():
        return
    if (not element.getChildren()) and (not element.getAttributeDefs()):
        return
    if element.getName() in AlreadyGenerated_subclass:
        return
    AlreadyGenerated_subclass.append(element.getName())
    name = element.getCleanName()
    wrt("class %s%s%s(supermod.%s):\n" % (prefix, name, SubclassSuffix, name))
    s1 = buildCtorArgs_multilevel(element)
    wrt("    def __init__(self%s):\n" % s1)
    s1 = buildCtorParams(element)
    wrt("        supermod.%s%s.__init__(self%s)\n" % (prefix, name, s1))
    if xmlbehavior and behaviors:
        wrt("\n")
        wrt("    #\n")
        wrt("    # XMLBehaviors\n")
        wrt("    #\n")
        # Get a list of behaviors for this class/subclass.
        classDictionary = behaviors.get_class_dictionary()
        if name in classDictionary:
            classBehaviors = classDictionary[name]
        else:
            classBehaviors = None
        if classBehaviors:
            generateClassBehaviors(wrt, classBehaviors, baseUrl)
    wrt("supermod.%s.subclass = %s%s\n" % (name, name, SubclassSuffix))
    wrt("# end class %s%s%s\n" % (prefix, name, SubclassSuffix))
    wrt("\n\n")


TEMPLATE_SUBCLASS_HEADER = """\
#!/usr/bin/env python

#
# Generated %s by generateDS.py.
#

import sys
from xml.dom import minidom
from xml.sax import handler, make_parser

import %s as supermod

"""

TEMPLATE_SUBCLASS_FOOTER = """\

#
# SAX handler used to determine the top level element.
#
class SaxSelectorHandler(handler.ContentHandler):
    def __init__(self):
        self.topElementName = None
    def getTopElementName(self):
        return self.topElementName
    def startElement(self, name, attrs):
        self.topElementName = name
        raise StopIteration


def parseSelect(inFileName):
    infile = open(inFileName, 'r')
    topElementName = None
    parser = make_parser()
    documentHandler = SaxSelectorHandler()
    parser.setContentHandler(documentHandler)
    try:
        try:
            parser.parse(infile)
        except StopIteration:
            topElementName = documentHandler.getTopElementName()
        if topElementName is None:
            raise RuntimeError, 'no top level element'
        topElementName = topElementName.replace('-', '_').replace(':', '_')
        if topElementName not in supermod.__dict__:
            raise RuntimeError, 'no class for top element: %%s' %% topElementName
        topElement = supermod.__dict__[topElementName]
        infile.seek(0)
        doc = minidom.parse(infile)
    finally:
        infile.close()
    rootNode = doc.childNodes[0]
    rootObj = topElement.factory()
    rootObj.build(rootNode)
    # Enable Python to collect the space used by the DOM.
    doc = None
    sys.stdout.write('<?xml version="1.0" ?>\\n')
    rootObj.export(sys.stdout, 0)
    return rootObj


def saxParse(inFileName):
    parser = make_parser()
    documentHandler = supermod.Sax%(cap_name)sHandler()
    parser.setDocumentHandler(documentHandler)
    parser.parse('file:%%s' %% inFileName)
    rootObj = documentHandler.getRoot()
    #sys.stdout.write('<?xml version="1.0" ?>\\n')
    #rootObj.export(sys.stdout, 0)
    return rootObj


def saxParseString(inString):
    parser = make_parser()
    documentHandler = supermod.SaxContentHandler()
    parser.setDocumentHandler(documentHandler)
    parser.feed(inString)
    parser.close()
    rootObj = documentHandler.getRoot()
    #sys.stdout.write('<?xml version="1.0" ?>\\n')
    #rootObj.export(sys.stdout, 0)
    return rootObj


def parse(inFilename):
    doc = minidom.parse(inFilename)
    rootNode = doc.documentElement
    rootObj = supermod.%(root)s.factory()
    rootObj.build(rootNode)
    # Enable Python to collect the space used by the DOM.
    doc = None
    sys.stdout.write('<?xml version="1.0" ?>\\n')
    rootObj.export(sys.stdout, 0, name_="%(name)s")
    doc = None
    return rootObj


def parseString(inString):
    doc = minidom.parseString(inString)
    rootNode = doc.documentElement
    rootObj = supermod.%(root)s.factory()
    rootObj.build(rootNode)
    # Enable Python to collect the space used by the DOM.
    doc = None
    sys.stdout.write('<?xml version="1.0" ?>\\n')
    rootObj.export(sys.stdout, 0, name_="%(name)s")
    return rootObj


def parseLiteral(inFilename):
    doc = minidom.parse(inFilename)
    rootNode = doc.documentElement
    rootObj = supermod.%(root)s.factory()
    rootObj.build(rootNode)
    # Enable Python to collect the space used by the DOM.
    doc = None
    sys.stdout.write('from %(super)s import *\\n\\n')
    sys.stdout.write('rootObj = %(name)s(\\n')
    rootObj.exportLiteral(sys.stdout, 0, name_="%(name)s")
    sys.stdout.write(')\\n')
    return rootObj


USAGE_TEXT = \"\"\"
Usage: python ???.py <infilename>
\"\"\"

def usage():
    print(USAGE_TEXT)
    sys.exit(-1)


def main():
    args = sys.argv[1:]
    if len(args) != 1:
        usage()
    infilename = args[0]
    root = parse(infilename)


if __name__ == '__main__':
    main()
    #import pdb
    #pdb.run('main()')


"""

##def isMember(item, lst):
##    for item1 in lst:
##        if item == item1:
##            print '(isMember) found name: %s' % item
##            return True
##    print '(isMember) did not find name: %s' % item
##    return False


def generateSubclasses(root, subclassFilename, behaviorFilename, prefix, superModule="xxx"):
    name = root.getChildren()[0].getName()
    subclassFile = makeFile(subclassFilename)
    if subclassFile:
        # Read in the XMLBehavior file.
        xmlbehavior = None
        behaviors = None
        baseUrl = None
        if behaviorFilename:
            try:
                # Add the correct working directory to the path so that
                #   we use the user/developers local copy.
                sys.path.insert(0, ".")
                import xmlbehavior_sub as xmlbehavior
            except ImportError:
                print("*** You have requested generation of extended methods.")
                print("*** But, no xmlbehavior module is available.")
                print("*** Generation of extended behavior methods is omitted.")
            if xmlbehavior:
                behaviors = xmlbehavior.parse(behaviorFilename)
                behaviors.make_class_dictionary(cleanupName)
                baseUrl = behaviors.getBase_impl_url()
        wrt = subclassFile.write
        wrt(TEMPLATE_SUBCLASS_HEADER % (time.ctime(), superModule))
        for element in ElementsForSubclasses:
            generateSubclass(subclassFile, element, prefix, xmlbehavior, behaviors, baseUrl)
        ##        processed = []
        ##        for element in root.getChildren():
        ##            name = element.getCleanName()
        ##            if name not in processed:
        ##                processed.append(name)
        ##                generateSubclass(subclassFile, element, prefix, xmlbehavior, behaviors, baseUrl)
        ##        while 1:
        ##            if len(DelayedElements_subclass) <= 0:
        ##                break
        ##            element = DelayedElements_subclass.pop()
        ##            name = element.getCleanName()
        ##            if name not in processed:
        ##                processed.append(name)
        ##                generateSubclass(subclassFile, element, prefix, xmlbehavior, behaviors, baseUrl)
        name = root.getChildren()[0].getName()
        elType = cleanupName(root.getChildren()[0].getType())
        if RootElement:
            rootElement = RootElement
        else:
            rootElement = elType
        params = {
            "cap_name": cleanupName(name).capitalize(),
            "name": cleanupName(name),
            "module_name": os.path.splitext(os.path.basename(subclassFilename))[0],
            "root": rootElement,
            "super": superModule,
        }
        wrt(TEMPLATE_SUBCLASS_FOOTER % params)
        subclassFile.close()


def generateFromTree(outfile, prefix, elements, processed):
    for element in elements:
        name = element.getCleanName()
        if 1:  # if name not in processed:
            processed.append(name)
            generateClasses(outfile, prefix, element, 0)
            children = element.getChildren()
            if children:
                generateFromTree(outfile, prefix, element.getChildren(), processed)


def generate(outfileName, subclassFilename, behaviorFilename, prefix, root, superModule):
    global DelayedElements, DelayedElements_subclass
    # Create an output file.
    # Note that even if the user does not request an output file,
    #   we still need to go through the process of generating classes
    #   because it produces data structures needed during generation of
    #   subclasses.
    outfile = None
    if outfileName:
        outfile = makeFile(outfileName)
    if not outfile:
        outfile = os.tmpfile()
    processed = []
    generateHeader(outfile, prefix)
    DelayedElements = []
    DelayedElements_subclass = []
    elements = root.getChildren()
    generateFromTree(outfile, prefix, elements, processed)
    while 1:
        if len(DelayedElements) <= 0:
            break
        element = DelayedElements.pop()
        name = element.getCleanName()
        if name not in processed:
            processed.append(name)
            generateClasses(outfile, prefix, element, 1)
    #
    # Generate the elements that were postponed because we had not
    #   yet generated their base class.
    idx = 0
    while 1:
        if len(PostponedExtensions) <= 0:
            break
        element = PostponedExtensions.pop()
        base = element.getBase()
        if base and base in ElementDict:
            parent = ElementDict[base]
            parentName = parent.getName()
            if parentName not in AlreadyGenerated:
                PostponedExtensions.insert(0, element)
            else:
                idx += 1
                generateClasses(outfile, prefix, element, 1)
    #
    # Disable the generation of SAX handler/parser.
    # It failed when we stopped putting simple types into ElementDict.
    # When there are duplicate names, the SAX parser probably does
    #   not work anyway.
    generateSAXHndlr(outfile, root)
    generateMain(outfile, prefix, root)
    outfile.close()
    if subclassFilename:
        generateSubclasses(root, subclassFilename, behaviorFilename, prefix, superModule)


def makeFile(outFileName):
    global Force
    outFile = None
    if (not Force) and os.path.exists(outFileName):
        reply = input("File %s exists.  Overwrite? (y/n): " % outFileName)
        if reply == "y":
            outFile = open(outFileName, "w")
    else:
        outFile = open(outFileName, "w")
    return outFile


def mapName(oldName):
    global NameTable
    newName = oldName
    if NameTable:
        if oldName in NameTable:
            newName = NameTable[oldName]
    return newName


def cleanupName(oldName):
    newName = oldName.replace(":", "_")
    newName = newName.replace("-", "_")
    return newName


## def mapName(oldName):
##     return '_X_%s' % oldName


def strip_namespace(val):
    return val.split(":")[-1]


def parseAndGenerate(
    outfileName,
    subclassFilename,
    prefix,
    xschemaFileName,
    behaviorFilename,
    superModule="???",
):
    global DelayedElements, DelayedElements_subclass, AlreadyGenerated, SaxDelayedElements, AlreadyGenerated_subclass
    DelayedElements = []
    DelayedElements_subclass = []
    AlreadyGenerated = []
    AlreadyGenerated_subclass = []
    ##    parser = saxexts.make_parser("xml.sax.drivers2.drv_pyexpat")
    parser = make_parser()
    ##    print 'dir(parser):', dir(parser)
    ##    print "Parser: %s" % parser
    dh = XschemaHandler()
    ##    parser.setDocumentHandler(dh)
    parser.setContentHandler(dh)
    parser.parse(xschemaFileName)
    root = dh.getRoot()
    root.annotate()
    ##    print 'ElementDict:', ElementDict
    ##    for name, obj in ElementDict.items():
    ##        print '    ', name, obj.getName(), obj.type
    ##    print '=' * 50
    ##    root.show(sys.stdout, 0)
    ##    print '=' * 50
    ##    response = input('Press Enter')
    ##    root.show(sys.stdout, 0)
    ##    print '=' * 50
    ##    print ']]] root: ', root, '[[['
    generate(outfileName, subclassFilename, behaviorFilename, prefix, root, superModule)


USAGE_TEXT = """
Usage: python generateDS.py [ options ] <in_xsd_file>
Options:
    -o <outfilename>         Output file name for data representation classes
    -s <subclassfilename>    Output file name for subclasses
    -p <prefix>              Prefix string to be prepended to the class names
    -n <mappingfilename>     Transform names with table in mappingfilename.
    -f                       Force creation of output files.  Do not ask.
    -a <namespaceabbrev>     Namespace abbreviation, e.g. "xsd:". Default = 'xs:'.
    -b <behaviorfilename>    Input file name for behaviors added to subclasses
    -m                       Generate properties for member variables
    --subclass-suffix="XXX"  Append XXX to the generated subclass names.  Default="Sub".
    --root-element="XXX"     Assume XXX is root element of instance docs.
                             Default is first element defined in schema.
    --super="XXX"            Super module name in subclass module. Default="???"

Example:
python generateDS.py -o generateModel_Module.py generateMetaModel_Module.xsd
"""


def usage():
    print(USAGE_TEXT)
    sys.exit(-1)


def main():
    global Force, GenerateProperties, SubclassSuffix, RootElement
    args = sys.argv[1:]
    options, args = getopt.getopt(
        args,
        "fyo:s:p:a:b:m",
        [
            "subclass-suffix=",
            "root-element=",
            "super=",
        ],
    )
    prefix = ""
    outFilename = None
    subclassFilename = None
    behaviorFilename = None
    nameSpace = "xs:"
    debug = 0
    superModule = "???"
    for option in options:
        if option[0] == "-p":
            prefix = option[1]
        elif option[0] == "-o":
            outFilename = option[1]
        elif option[0] == "-s":
            subclassFilename = option[1]
        elif option[0] == "-f":
            Force = 1
        elif option[0] == "-a":
            nameSpace = option[1]
        elif option[0] == "-b":
            behaviorFilename = option[1]
        elif option[0] == "-m":
            GenerateProperties = 1
        elif option[0] == "--subclass-suffix":
            SubclassSuffix = option[1]
        elif option[0] == "--root-element":
            RootElement = option[1]
        elif option[0] == "--super":
            superModule = option[1]
    set_type_constants(nameSpace)
    if behaviorFilename and not subclassFilename:
        print("\n*** Error.  -b requires -s")
        usage()
    if len(args) != 1:
        usage()
    xschemaFileName = args[0]
    if debug:
        pass
    else:
        parseAndGenerate(
            outFilename,
            subclassFilename,
            prefix,
            xschemaFileName,
            behaviorFilename,
            superModule=superModule,
        )


if __name__ == "__main__":
    main()
##    import pdb
##    pdb.run('main()')
