Re: [Modeling-users] Re: Implementing inheritance through vertical mapping
Status: Abandoned
Brought to you by:
sbigaret
From: Yannick G. <yan...@sa...> - 2003-10-01 14:19:36
|
=2D----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On September 29, 2003 06:20 pm, SoaF-BSD wrote: > > As I said some time ago, we use Datadesigner [1] to make our XML model > > and than we pass it to a DOM transformation tool to have a Modeling > > friendly document. > > Perhaps you can provide this tool ? add this to the CVS .. this could be > great. no ? Sure ! I already posted it some time ago but it didn't seems to generate a lot of interests. Since it's more a convenient internal tool for us than a generic model converter it's a bit tainted by our usage of the framework : public keys are public (we serialize them to cross a XML-RPC bridge), only to-many relations and their inverse are merged and a few points like that. It might be better to swith to a XSLT transform instead. Anyway, if it can help someone, I'm willing to make it more generic. #!/usr/bin/python # Copyright (C) 2003 Savoir-faire Linux <in...@sa...> # by Yannick Gingras <yan...@sa...> # This is dd2pm. # dd2pm is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # dd2pm is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Open Beat Box; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 U= SA """dd2pm.py : Datadesigner to Python Modeling convertion tool. """ from xml.dom.minidom import parseString from xml.dom.ext import PrettyPrint from xml import xpath from xml.xpath import Evaluate import xml import sys DOC_SKEL =3D """<?xml version=3D'1.0' encoding=3D'iso-8859-1'?> <model name= =3D'' />""" DEF_DB =3D "MySQL" DEF_NEEDED_ENTITIES =3D [] DEF_CONNECTION =3D {} DD_PM_TYPE_MAP =3D {"bool": "int", "integer": "int", "int": "int", "varchar": "string", "numeric": "string", "real": "float", "float": "float", "time": "DateTime", "char": "string", "text": "string", "date": "DateTime"} DD_PM_EXT_TYPE_MAP =3D {"tinyint": "int", "smallint": "int", "decimal": "numeric"} def getSourceDom(filename): return parseString(open(filename).read()) def createDoc(): return parseString(DOC_SKEL) class ModelingDDImporter: """Convert a Data Designer shema to PyModeling Model""" def __init__(self, srcDoc, targetDoc, onlyNeededEnts=3D0): """both srcDoc and targetDoc are DOM compliant instances""" self.srcDoc =3D srcDoc self.destDoc =3D targetDoc self.onlyNeededEnts =3D onlyNeededEnts def startConvertion(self): self.model =3D self.destDoc.getElementsByTagName("model")[0] self.project =3D self.srcDoc.getElementsByTagName("project")[0] self.addModelDefAttrs() self.convPrjAttrs() self.extractPrjEntities() self.mutateEntities() self.extractRelations() self.mutateRelations() def addModelDefAttrs(self): self.model.setAttribute("adaptorName", DEF_DB) self.model.setAttribute("connectionDictionary", str(DEF_CONNECTION)) def convPrjAttrs(self): name =3D self.project.getAttribute("name") =20 self.model.setAttribute("name", name) self.model.setAttribute("packageName", name) def extractPrjEntities(self): entitiesNode =3D self.srcDoc.getElementsByTagName("entities")[0] self.prjEntities =3D entitiesNode.getElementsByTagName("entity") def extractRelations(self): relationsNode =3D self.srcDoc.getElementsByTagName("relations")[0] self.relations =3D relationsNode.getElementsByTagName("relation") def mutateEntities(self): for entity in self.prjEntities: needed =3D 1 if self.onlyNeededEnts: if entity.getAttribute("name") not in DEF_NEEDED_ENTITIES: needed =3D 0 if needed: newEntity =3D self.destDoc.createElement('entity') self.model.appendChild(newEntity) self.mutateEntity(entity, newEntity) def mutateRelations(self): for relation in self.relations: needed =3D 1 if self.onlyNeededEnts: parent =3D Evaluate("./parent/text()", relation)[0].nodeVal= ue if parent not in DEF_NEEDED_ENTITIES: needed =3D 0 if needed: newRelation =3D self.destDoc.createElement('relation') self.mutateRelation(relation, newRelation) def getModelEntityWithName(self, name): modelEntities =3D self.model.getElementsByTagName("entity") =20 for modelEntity in modelEntities: if modelEntity.getAttribute("name") =3D=3D name: return modelEntity =20 return None =20 def mutateEntity(self, sourceEntity, destEntity): # mutate names=20 mapping =3D {"name": ["moduleName", "className", "name"], "pname": ["externalName"]} for mapEntry in mapping.items(): val =3D sourceEntity.getAttribute(mapEntry[0]) for attrName in mapEntry[1]: destEntity.setAttribute(attrName, val) # set defaults defaults =3D self.makeDefaults(isReadOnly =3D'0', isAbstract =3D '0', typeName =3D '', parentEntity =3D '') for attrName, val in defaults.items(): destEntity.setAttribute(attrName, val) # mutate misc attrs self.mutateEntAttrs(sourceEntity, destEntity) def mutateEntAttrs(self, sourceEntity, destEntity): entAttrsNode =3D sourceEntity.getElementsByTagName("attributes")[0] entAttrs =3D entAttrsNode.getElementsByTagName("attribute") for entAttr in entAttrs: newEntAttr =3D self.destDoc.createElement("attribute") destEntity.appendChild(newEntAttr) self.mutateEntAttr(entAttr, newEntAttr) def mutateEntAttr(self, sourceEntAttr, destEntAttr): # mutate name name =3D sourceEntAttr.getAttribute("name") destEntAttr.setAttribute("name", name) pname =3D sourceEntAttr.getAttribute("pname") destEntAttr.setAttribute("columnName", pname) # set defaults defaults =3D self.makeDefaults( isClassProperty =3D '1', width =3D '0', isRequired =3D '0', precision =3D '0', defaultValue =3D 'None', scale =3D '0', displayLabel =3D "") for attrName, val in defaults.items(): destEntAttr.setAttribute(attrName, val) # mutate real values mapping =3D {"type": "externalType", "length": "width"} for node in sourceEntAttr.childNodes: if node.nodeType =3D=3D node.ELEMENT_NODE: tagName =3D node.tagName try: value =3D node.firstChild.nodeValue except AttributeError: value =3D "" self.mutateEntAttrType(tagName, value, sourceEntAttr, destEntAttr) def strToBool(self, str): if str =3D=3D "true": return 1 elif str =3D=3D "false": return 0 else: raise Exception("String '%s' cannot be converted to bool" % str) def mutateEntAttrType(self, tagName, value, sourceEntAttr, destEntAttr): if tagName =3D=3D "type": if DD_PM_EXT_TYPE_MAP.has_key(value): value =3D DD_PM_EXT_TYPE_MAP[value] destEntAttr.setAttribute("externalType", value) destEntAttr.setAttribute("type", DD_PM_TYPE_MAP[value]) elif tagName =3D=3D "nullable": destEntAttr.setAttribute("isRequired", str(not self.strToBool(value))) elif tagName =3D=3D "unique": pass elif tagName =3D=3D "primarykey": if self.strToBool(value): newElem =3D self.destDoc.createElement("primaryKey") newElem.setAttribute("attributeName", destEntAttr.getAttribute("name")) destEntAttr.parentNode.appendChild(newElem) destEntAttr.setAttribute("isRequired", '1') destEntAttr.setAttribute("defaultValue", '0') destEntAttr.setAttribute("isClassProperty", '1') elif tagName =3D=3D "foreignkey": if self.strToBool(value): destEntAttr.setAttribute("isClassProperty", '0') elif tagName =3D=3D "isarray": pass elif tagName =3D=3D "imported": pass elif tagName =3D=3D "description": pass elif tagName =3D=3D "default": destEntAttr.setAttribute("defaultValue", value) elif tagName =3D=3D "length": # tricky, converted to width only if there is no precision if sourceEntAttr.getElementsByTagName("decimals"): # use precision destEntAttr.setAttribute("precision", value) else: # use width destEntAttr.setAttribute("width", value) elif tagName =3D=3D "decimals": destEntAttr.setAttribute("scale", value) else: raise Exception("Unknowed node type : %s" % tagName) def mutateRelation(self, sourceRelation, destRelation): # set defaults defaults =3D self.makeDefaults(deleteRule=3D'nullify', isClassProperty=3D'1', multiplicityUpperBound=3D'-1', multiplicityLowerBound=3D'0', displayLabel=3D'', joinSemantic=3D'0') for attrName, value in defaults.items(): destRelation.setAttribute(attrName, value) type =3D xpath.Evaluate("./type/text()", sourceRelation)[0].nodeVal= ue if type =3D=3D "ident": pass # keep the defaults elif type =3D=3D "inform": # reverse relation of a to-many destRelation.setAttribute("multiplicityUpperBound", "1") destRelation.setAttribute("multiplicityLowerBound", "0") else: raise Exception("Can't handle relation type : '%s'" % type) =20 # append relation to master entity parentElem =3D sourceRelation.getElementsByTagName("parent")[0] fromEntity =3D parentElem.firstChild.nodeValue self.getModelEntityWithName(fromEntity).appendChild(destRelation) # set the receiver childElem =3D sourceRelation.getElementsByTagName("child")[0] toEntity =3D childElem.firstChild.nodeValue destRelation.setAttribute("destinationEntity", toEntity) destRelation.setAttribute("name", sourceRelation.getAttribute("name= ")) relAttrsNode =3D sourceRelation.getElementsByTagName("relationattrs= ")[0] bindingNode =3D relAttrsNode.getElementsByTagName("attributebind")[= 0] fromAttr =3D bindingNode.getAttribute("parent") toAttr =3D bindingNode.getAttribute("child") joinElem =3D self.destDoc.createElement("join") joinElem.setAttribute("sourceAttribute", fromAttr) joinElem.setAttribute("destinationAttribute", toAttr) destRelation.appendChild(joinElem) =20 =20 def makeDefaults(self, **kwargs): return kwargs if __name__ =3D=3D '__main__': if len(sys.argv) not in [3, 4]: print """usage : %s [-o] <SOURCE> <DESTINATION> where <SOURCE> is the path of the source XML model and <DESTINATION> is where to save the PyModeling XML model Options : -o : only convert needed entities""" % (sys.argv[0]) sys.exit(1) onlyNeededEnts =3D "-o" in sys.argv =20 srcDoc =3D getSourceDom(sys.argv[-2]) newDoc =3D createDoc() importer =3D ModelingDDImporter(srcDoc, newDoc, onlyNeededEnts) importer.startConvertion() PrettyPrint(newDoc, stream=3Dopen(sys.argv[-1], "w")) # The END ! =2D --=20 Yannick Gingras Byte Gardener, Savoir-faire Linux inc. http://www.savoirfairelinux.com/ =2D----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.2 (GNU/Linux) iD8DBQE/euJzrhy5Fqn/MRARAt/jAJ0eABfJZURbCLulDyX5oFRaR7DQvgCggzaz mNqOp1fTT8LkjVcH+KEnqIQ=3D =3Ds43u =2D----END PGP SIGNATURE----- |