#!/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(' -- 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 = "" 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\\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\\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\\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\\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\\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\\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\\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\\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('\\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(' -- 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('&', '&') s1 = s1.replace('<', '<') s1 = s1.replace('"', '"') 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' %% (self.name, self.value, self.name)) elif self.content_type == MixedContainer.TypeInteger or \\ self.content_type == MixedContainer.TypeBoolean: outfile.write('<%%s>%%d' %% (self.name, self.value, self.name)) elif self.content_type == MixedContainer.TypeFloat or \\ self.content_type == MixedContainer.TypeDecimal: outfile.write('<%%s>%%f' %% (self.name, self.value, self.name)) elif self.content_type == MixedContainer.TypeDouble: outfile.write('<%%s>%%g' %% (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 ] 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('\\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('\\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('\\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('\\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('\\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('\\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('\\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('\\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('\\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('\\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 \"\"\" 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 ] Options: -o Output file name for data representation classes -s Output file name for subclasses -p Prefix string to be prepended to the class names -n Transform names with table in mappingfilename. -f Force creation of output files. Do not ask. -a Namespace abbreviation, e.g. "xsd:". Default = 'xs:'. -b 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()')