# -*- coding: iso-8859-15 -*- # copyright 2003 Logilab # distributed under the terms of the GNU GPL """Python code generation from XMI document""" __revision__ = '$Id: xmi2py.py,v 1.1 2004/01/08 13:48:46 alf Exp $' import sys from xml.sax.handler import ContentHandler from xml.sax.xmlreader import InputSource from string import maketrans TRANS_TABLE = maketrans('éèêëàâôùüîï', 'eeeeaaouuii') del maketrans def toIdentifier(ustring): return (ustring or u'').encode('iso-8859-15').translate(TRANS_TABLE, ' \t\n\r,;.:!/?$%"\'') def attrs2dict(attrs): d = {} for k, v in attrs.items(): try: v = int(v) except ValueError: v = v.encode('iso-8859-15') d[k] = v return d class Method: def __init__(self, name=None): self.setName(name) self.parameters = ['self'] self.setCodeLines([]) def setCodeLines(self, lines): self.code = lines def addCodeLines(self, lines): self.code += lines def setName(self, name): self.name = toIdentifier(name) def addParameter(self, parmName, atBeginning=False): parmName = toIdentifier(parmName) if parmName != 'return': if atBeginning: self.parameters.insert(1, parmName) else: self.parameters.append(parmName) def serialize(self, out): self.code = self.code or ['pass'] indent = ' ' * 4 out.write('%sdef %s(%s):\n' % (indent, self.name, ', '.join(self.parameters))) for line in self.code: out.write('%s%s%s\n' % (indent, indent, line)) out.write('\n') class Class: """Representation of a Python class""" def __init__(self, name=None): self.setName(name) self.attributes = [] self.methods = [] self.constructor = Method(u'__init__') self.addMethod(self.constructor) self.parent = None def setName(self, name): self.name = toIdentifier(name) def addAttribute(self, attrName): attrName = toIdentifier(attrName) self.attributes.append(attrName) self.constructor.addParameter('%s=None' % attrName) self.constructor.addCodeLines(['%s = %s' % (attrName, attrName)]) def addMethod(self, method): self.methods.append(method) def extends(self, parentClass): self.parent = parentClass myOwnAttributes = [attr for attr in self.attributes if attr not in parentClass.attributes] constrParms = ', '.join(['self'] + parentClass.attributes) codeLines = ['%s.__init__(%s)' % (parentClass.name, constrParms)] for attr in myOwnAttributes: codeLines.append('%s = %s' % (attr, attr)) self.constructor.parameters=['self'] for attr in parentClass.attributes + myOwnAttributes: self.constructor.addParameter('%s=None' % attr) self.constructor.setCodeLines(codeLines) def serialize(self, out): if self.parent: extends = '(%s)' % self.parent.name else: extends = '' out.write('class %s%s:\n' % (self.name, extends)) for meth in self.methods: meth.serialize(out) out.flush() class XmiHandler(ContentHandler): classTag = u"Foundation.Core.Class" nameTag = u'Foundation.Core.ModelElement.name' attributeTag = u'Foundation.Core.Attribute' generalizationTag = u'Foundation.Core.Generalization' genChildTag = u'Foundation.Core.Generalization.child' genParentTag = u'Foundation.Core.Generalization.parent' genElementTag = u'Foundation.Core.GeneralizableElement' methodTag = u'Foundation.Core.Operation' parameterTag = u'Foundation.Core.Parameter' def __init__(self): self.classes = {} self._inclass = None self._inmethod = None self._stack = [] self._buff = u'' self._generalisations = {} self.tmpGenChild = None self.tmpGenParent = None def startElement(self, name, attrs): attr_dict = attrs2dict(attrs) self._stack.append(name) self._buff = u'' if name == self.classTag: id = attr_dict[u'xmi.id'] self._inclass = Class() self.classes[id] = self._inclass elif name == self.genElementTag: if self._stack[-2].endswith(u'.parent'): self.tmpGenParent = attr_dict[u'xmi.idref'] else: self.tmpGenChild = attr_dict[u'xmi.idref'] elif name == self.methodTag: self._inmethod = Method() self._inclass.addMethod(self._inmethod) def endElement(self, name): self._stack.pop() if name == self.classTag: self._inclass = None elif name == self.nameTag: prevElement = self._stack[-1] if prevElement == self.classTag: self._inclass.setName(self._buff) elif prevElement == self.attributeTag: self._inclass.addAttribute(self._buff) elif prevElement == self.methodTag: self._inmethod.setName(self._buff) elif prevElement == self.parameterTag : self._inmethod.addParameter(self._buff) elif name == self.generalizationTag: if self.tmpGenChild is not None and self.tmpGenParent is not None: self._generalisations[self.tmpGenChild] = self.tmpGenParent self.tmpGenChild = None self.tmpGenParent = None def characters(self, chars): self._buff += chars def endDocument(self): for childId, parentId in self._generalisations.iteritems(): self.classes[childId].extends(self.classes[parentId]) def buildClass(inputsource, outstream): from xml.sax import make_parser, ErrorHandler from xml.sax.handler import feature_external_pes parser = make_parser() handler = XmiHandler() parser.setContentHandler(handler) parser.setErrorHandler(ErrorHandler()) parser.setFeature(feature_external_pes, 0) parser.parse(inputsource) for aClass in handler.classes.itervalues(): aClass.serialize(outstream) if __name__ == '__main__': import sys import os argument = sys.argv[1] if argument.endswith('.zargo'): import zipfile archive = zipfile.ZipFile(argument, 'r') xmifilename = argument.replace('.zargo', '.xmi') data = archive.read(xmifilename) f = open(xmifilename, 'wb') f.write(data) f.close() argument = xmifilename source = InputSource("file://"+os.path.abspath(argument)) buildClass(source, sys.stdout)