# Copyright (c) 2002-2004 LOGILAB S.A. (Paris, FRANCE). # http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This program 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. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. """ library to create DOM tree conforming to the XMI 1.0 UML 1.3 DTD """ __revision__ = "$Id: xmiutils.py,v 1.10 2005/04/15 11:00:46 syt Exp $" try: from xml.dom import EMPTY_NAMESPACE as NO_NS except: NO_NS = None from pyreverse.utils import get_visibility as _get_visibility __all__ = ('xmi_document', 'xmi_content', 'xmi_package', 'xmi_interface', 'xmi_signal', 'xmi_class', 'xmi_attribute', 'xmi_operation', 'xmi_parameter', 'xmi_abstraction', 'xmi_generalization', 'xmi_association', 'xmi_dependency', 'xmi_stereotype', 'xmi_stereotype_ref', 'xmi_X_ref', 'add_me_dependency', 'add_idref') # XMI-UML constantes ########################################################### CORE = 'Foundation.Core' XMI_MM_MODEL = 'Model_Management.Model' XMI_MM_PACKAGE = 'Model_Management.Package' XMI_OWNED_ELMT = '%s.Namespace.ownedElement' % CORE XMI_MODEL_ELMT = '%s.ModelElement' % CORE XMI_MODEL_ELMT_NAME = '%s.name' % XMI_MODEL_ELMT XMI_MODEL_ELMT_VISI = '%s.visibility' % XMI_MODEL_ELMT XMI_MODEL_ELMT_SPEC = '%s.isSpecification' % XMI_MODEL_ELMT XMI_MODEL_ELMT_STYPE = '%s.stereotype' % XMI_MODEL_ELMT XMI_MODEL_ELMT_CD = '%s.clientDependency' % XMI_MODEL_ELMT XMI_MODEL_ELMT_SD = '%s.supplierDependency' % XMI_MODEL_ELMT XMI_G_ELMT = '%s.GeneralizableElement' % CORE XMI_G_ELMT_SPEC = '%s.specialization' % XMI_G_ELMT XMI_G_ELMT_GENE = '%s.generalization' % XMI_G_ELMT XMI_INTERFACE = '%s.Interface' % CORE XMI_CLASS = '%s.Class' % CORE XMI_CLASS_ACTIV = '%s.isActive' % XMI_CLASS XMI_ATTRIBUTE = '%s.Attribute' % CORE XMI_ATTRIBUTE_INIT_VAL = '%s.initialValue' % XMI_ATTRIBUTE XMI_OPERATION = '%s.Operation' % CORE XMI_PARAMETER = '%s.Parameter' % CORE XMI_PARAMETER_KIND = '%s.kind' % XMI_PARAMETER XMI_ASSOCIATION = '%s.Association' % CORE XMI_ASSOCIATION_CNX = '%s.connection' % XMI_ASSOCIATION XMI_ASSOCIATIONEND = '%s.AssociationEnd' % CORE XMI_ASSOCIATIONEND_NAVIG = '%s.isNavigable' % XMI_ASSOCIATIONEND XMI_ASSOCIATIONEND_AGGREG = '%s.aggregation' % XMI_ASSOCIATIONEND XMI_ASSOCIATIONEND_MULT = '%s.multiplicity'% XMI_ASSOCIATIONEND XMI_ASSOCIATIONEND_TYPE = '%s.type' % XMI_ASSOCIATIONEND XMI_ABSTRACTION = '%s.Abstraction' % CORE XMI_GENERALIZATION = '%s.Generalization' % CORE XMI_GENERALIZATION_CHILD = '%s.child' % XMI_GENERALIZATION XMI_GENERALIZATION_PARENT = '%s.parent' % XMI_GENERALIZATION XMI_DEPENDENCY = '%s.Dependency'% CORE XMI_DEPENDENCY_C = '%s.client'% XMI_DEPENDENCY XMI_DEPENDENCY_S = '%s.supplier'% XMI_DEPENDENCY XMI_FEATURE = '%s.Classifier.feature' % CORE XMI_OWNER_SCOPE = '%s.Feature.ownerScope' % CORE XMI_BF = '%s.BehavioralFeature'% CORE XMI_BF_PARAM = '%s.parameter' % XMI_BF XMI_BF_QUERY = '%s.isQuery' % XMI_BF XMI_MULTIPLICITY = 'Foundation.Data_Types.Multiplicity' XMI_MULTIPLICITY_RANGE = '%s.range' % XMI_MULTIPLICITY XMI_MULTIPLICITYRANGE = 'Foundation.Data_Types.MultiplicityRange' XMI_MULTIPLICITYRANGE_UPPER = '%s.upper' % XMI_MULTIPLICITYRANGE XMI_MULTIPLICITYRANGE_LOWER = '%s.lower' % XMI_MULTIPLICITYRANGE XMI_BE_SIGNAL = 'Behavioral_Elements.Common_Behavior.Signal' XMI_BE_SIGNAL_CONT = '%s.context' % XMI_BE_SIGNAL XMI_EXPRESSION = 'Foundation.Data_Types.Expression' XMI_EXPRESSION_LANG = '%s.language' XMI_EXPRESSION_BODY = '%s.body' XMI_STEREOTYPE = 'Foundation.Extension_Mechanisms.Stereotype' XMI_STEREOTYPE_EXTEND = '%s.extendedElement' % XMI_STEREOTYPE # methods to create base XMI-UML elements ###################################### def xmi_document(doc_factory): """return an XMI document with standard headers """ doc = doc_factory(NO_NS, 'XMI', '', 'uml13.dtd') root = doc.documentElement root.setAttributeNS(NO_NS, 'xmi.version', '1.0') n1 = doc.createElementNS(NO_NS, 'XMI.header') root.appendChild(n1) docu = doc.createElementNS(NO_NS, 'XMI.documentation') n1.appendChild(docu) from pyreverse.__pkginfo__ import version, modname n = doc.createElementNS(NO_NS, 'XMI.exporter') n.appendChild(doc.createTextNode(modname)) docu.appendChild(n) n = doc.createElementNS(NO_NS, 'XMI.exporterVersion') n.appendChild(doc.createTextNode(version)) docu.appendChild(n) meta = doc.createElementNS(NO_NS, 'XMI.metamodel') n1.appendChild(meta) meta.setAttributeNS(NO_NS, 'xmi.name', 'UML') meta.setAttributeNS(NO_NS, 'xmi.version', '1.3') return doc def xmi_content(doc, n_id, n_uuid, n_name): """return a XMI content dom with standard elements and attributes """ content = doc.createElementNS(NO_NS, 'XMI.content') root = doc.documentElement root.appendChild(content) model = _createModelElement(doc, XMI_MM_MODEL, n_id, n_uuid, n_name) _add_std_attrs(model) content.appendChild(model) owner = doc.createElementNS(NO_NS, XMI_OWNED_ELMT) model.appendChild(owner) return owner def xmi_package(doc, n_id, n_uuid, n_name): """return a XMI package definition dom """ package = _createModelElement(doc, XMI_MM_PACKAGE, n_id, n_uuid, n_name, 1) _add_std_attrs(package, 'false', 'false') content = doc.createElementNS(NO_NS, XMI_OWNED_ELMT) package.appendChild(content) return package, content def xmi_interface(doc, n_id, n_uuid, n_name, n_final, n_abstract): """return a XMI interface definition dom """ interface = _createModelElement(doc, XMI_INTERFACE, n_id, n_uuid, n_name, 1) _add_std_attrs(interface, n_final, n_abstract) return interface def xmi_signal(doc, n_id, n_uuid, n_name, n_final, n_abstract): """return a XMI signal definition dom """ signal = _createModelElement(doc, XMI_BE_SIGNAL, n_id, n_uuid, n_name, 1) _add_std_attrs(signal, n_final, n_abstract) return signal def xmi_class(doc, n_id, n_uuid, n_name, n_final, n_abstract, n_active='false'): """return a XMI class definition dom """ klass = _createModelElement(doc, XMI_CLASS, n_id, n_uuid, n_name, 1) _add_std_attrs(klass, n_final, n_abstract) _add_value(klass, XMI_CLASS_ACTIV, n_active) return klass def xmi_attribute(doc, generate_id, n_id, n_uuid, n_name, n_type, n_default=None): """return a XMI class attribute definition dom """ attr = _createModelElement(doc, XMI_ATTRIBUTE, n_id, n_uuid, n_name, 1) if n_type == 'class': _add_value(attr, XMI_FEATURE, 'classifier') if n_default is not None: el = doc.createElementNS(NO_NS, XMI_ATTRIBUTE_INIT_VAL) attr.appendChild(el) el2 = _id_element(doc, XMI_EXPRESSION, generate_id(), el) el = doc.createElementNS(NO_NS, XMI_EXPRESSION_LANG) el2.appendChild(el) el.appendChild(doc.createTextNode('Java')) el = doc.createElementNS(NO_NS, XMI_EXPRESSION_BODY) el2.appendChild(el) el.appendChild(doc.createTextNode(n_default)) return attr def xmi_operation(doc, n_id, n_uuid, n_name, n_final, class_method): """return a XMI class operation definition dom """ op = _createModelElement(doc, XMI_OPERATION, n_id, n_uuid, n_name, 1) if class_method: _add_value(op, XMI_FEATURE, 'classifier') _add_value(op, XMI_BF_QUERY, 'false') _add_std_attrs(op, n_final) return op def xmi_parameter(doc, n_id, n_name): """return a XMI class parameter definition dom """ param = _createModelElement(doc, XMI_PARAMETER, n_id, None, n_name, 1) _add_value(param, XMI_PARAMETER_KIND, "in") return param def xmi_abstraction(doc, base_id, base_uuid): """return a XMI class abstraction definition dom """ abstraction = _id_element(doc, XMI_ABSTRACTION, base_id) abstraction.setAttributeNS(NO_NS, 'xmi.uuid', base_uuid) _add_value(abstraction, XMI_MODEL_ELMT_SPEC, 'false') return abstraction def xmi_generalization(doc, base_id, base_uuid): """return a XMI class generalization definition dom """ generalization = _id_element(doc, XMI_GENERALIZATION, base_id) generalization.setAttributeNS(NO_NS, 'xmi.uuid', base_uuid) _add_value(generalization, XMI_MODEL_ELMT_SPEC, 'false') return generalization def xmi_association(doc, generate_id, n_id, n_uuid, a1_name, a1_class_type, a1_class_id, a2_name, a2_class_type, a2_class_id, navigable=0, aggreg='none', lower=1, upper=1): """return a XMI association definition dom """ assoc = _id_element(doc, XMI_ASSOCIATION, n_id) assoc.setAttributeNS(NO_NS, 'xmi.uuid', n_uuid) _add_value(assoc, XMI_MODEL_ELMT_SPEC, 'false') _add_std_attrs(assoc, 'false', 'false') content = doc.createElementNS(NO_NS, XMI_ASSOCIATION_CNX) assoc.appendChild(content) content.appendChild(_xmi_association_end( doc, generate_id, a1_name, a1_class_type, a1_class_id)) navigable = navigable and 'true' or 'false' content.appendChild(_xmi_association_end( doc, generate_id, a2_name, a2_class_type, a2_class_id, navigable=navigable)) ## navigable.appendChild(doc, generate_id, name, end, lower=1, upper=1, ## navigable='true', aggreg='none') return assoc def xmi_dependency(doc, n_id, n_uuid, module_id, dependency_id, content_root): """return a XMI dependency definition dom """ d = _id_element(doc, XMI_DEPENDENCY, n_id, content_root) _add_value(d, XMI_MODEL_ELMT_SPEC, 'false') c = _add_dependency(d, client=1) add_idref(c, XMI_MODEL_ELMT, module_id) c = _add_dependency(d, client=0) add_idref(c, XMI_MODEL_ELMT, dependency_id) return d def xmi_stereotype(doc, base_id, n_id): """return a XMI stereotype definition dom """ ext = _id_element(doc, XMI_STEREOTYPE, n_id) me = doc.createElementNS(NO_NS, XMI_MODEL_ELMT_NAME) ext.appendChild(me) me.appendChild(doc.createTextNode('realize')) _add_value(ext, XMI_MODEL_ELMT_SPEC, 'false') _add_std_attrs(ext) el = doc.createElementNS(NO_NS, XMI_STEREOTYPE_EXTEND) ext.appendChild(el) add_idref(el, XMI_ABSTRACTION, base_id) return ext def xmi_stereotype_ref(doc, n_id): """return a XMI stereotype reference dom """ ext = doc.createElementNS( NO_NS, XMI_MODEL_ELMT_STYPE) add_idref(ext, XMI_STEREOTYPE, n_id) return ext def xmi_X_ref(doc, parent, interface, root_id, dependency_id): """create a XMI cross link reference """ if dependency_id: if not interface: d = doc.createElementNS(NO_NS, XMI_GENERALIZATION_CHILD) else: d = doc.createElementNS(NO_NS, XMI_DEPENDENCY_C) add_idref(d, XMI_CLASS, dependency_id) if parent.nodeName == XMI_ABSTRACTION: parent.insertBefore(d, parent.firstChild.nextSibling.nextSibling) else: parent.insertBefore(d, parent.firstChild.nextSibling) else: if not interface: d = doc.createElementNS(NO_NS, XMI_GENERALIZATION_PARENT) a_name = XMI_CLASS else: d = doc.createElementNS(NO_NS, XMI_DEPENDENCY_S) a_name = XMI_INTERFACE add_idref(d, a_name, root_id) parent.appendChild(d) # generic funtions ############################################################# def add_me_dependency(parent, client, before=None): """create a dependancy between two package if client is true, client dependency else, supplier dependency """ if client: pe = parent.ownerDocument.createElementNS(NO_NS, XMI_MODEL_ELMT_CD) else: pe = parent.ownerDocument.createElementNS(NO_NS, XMI_MODEL_ELMT_SD) if before is None: parent.appendChild(pe) else: parent.insertBefore(pe, before) return pe def add_idref(parent, name, id): """add an XMI idref element """ me_spec = parent.ownerDocument.createElementNS(NO_NS, name) me_spec.setAttributeNS(NO_NS, 'xmi.idref', _id_format(id)) parent.appendChild(me_spec) # private funtions ############################################################# def _xmi_association_end(doc, generate_id, a_name, end_type, end_id, lower=1, upper=1, navigable='true', aggreg='none'): """return a XMI association end definition dom """ el = _id_element(doc, XMI_ASSOCIATIONEND, generate_id()) me = doc.createElementNS(NO_NS, XMI_MODEL_ELMT_NAME) el.appendChild(me) me.appendChild(doc.createTextNode(a_name)) _add_value(el, XMI_MODEL_ELMT_SPEC, 'false') _add_value(el, XMI_ASSOCIATIONEND_NAVIG, navigable) _add_value(el, XMI_ASSOCIATIONEND_AGGREG, aggreg) n = doc.createElementNS(NO_NS, XMI_ASSOCIATIONEND_MULT) el.appendChild(n) me = _id_element(doc, XMI_MULTIPLICITY, generate_id(), n) range = doc.createElementNS(NO_NS, XMI_MULTIPLICITY_RANGE) me.appendChild(range) me = _id_element(doc, XMI_MULTIPLICITYRANGE, generate_id(), range) n = doc.createElementNS(NO_NS, XMI_MULTIPLICITYRANGE_LOWER) n.appendChild(doc.createTextNode(str(lower))) me.appendChild(n) n = doc.createElementNS(NO_NS, XMI_MULTIPLICITYRANGE_UPPER) n.appendChild(doc.createTextNode(str(upper))) me.appendChild(n) me = doc.createElementNS(NO_NS, XMI_ASSOCIATIONEND_TYPE) el.appendChild(me) if end_type == 'interface': add_idref(me, XMI_INTERFACE, end_id) elif end_type == 'signal': add_idref(me, XMI_BE_SIGNAL, end_id) else: add_idref(me, XMI_CLASS, end_id) return el def _createModelElement(doc, n_type, n_id, n_uuid, n_name, visibility=None): """create a XMI ModelElement dom do not add 'xmi.uuid' attribute if uuid=None """ n_id = int(n_id) el = _id_element(doc, n_type, n_id) if n_uuid is not None: el.setAttributeNS(NO_NS, 'xmi.uuid', n_uuid) me = doc.createElementNS(NO_NS, XMI_MODEL_ELMT_NAME) el.appendChild(me) me.appendChild(doc.createTextNode(n_name)) if visibility is not None: _add_value(el, XMI_MODEL_ELMT_VISI, _get_visibility(n_name)) _add_value(el, XMI_MODEL_ELMT_SPEC, 'false') return el def _add_std_attrs(ge, final=0, abstract=0): """add some standards attributes to a node """ abstract = abstract and 'true' or 'false' final = final and 'true' or 'false' if ge.nodeName == XMI_OPERATION: elmt = XMI_OPERATION else: elmt = XMI_G_ELMT _add_value(ge, '%s.isRoot'%(elmt), 'false') _add_value(ge, '%s.isLeaf'%(elmt), final) _add_value(ge, '%s.isAbstract'%(elmt), abstract) def _add_dependency(parent, client): """create a XMI dependency client or supplier dom """ if client: pe = parent.ownerDocument.createElementNS(NO_NS, XMI_DEPENDENCY_C) else: pe = parent.ownerDocument.createElementNS(NO_NS, XMI_DEPENDENCY_S) parent.appendChild(pe) return pe def _add_value(parent, n_name, value): """add an XMI value element """ me_spec = parent.ownerDocument.createElementNS(NO_NS, n_name) me_spec.setAttributeNS(NO_NS, 'xmi.value', value) parent.appendChild(me_spec) def _id_element(doc, name, id, parent=None): """add an XMI id element """ e = doc.createElementNS(NO_NS, name) e.setAttributeNS(NO_NS, 'xmi.id', _id_format(id)) if parent is not None: parent.appendChild(e) return e def _id_format(id): """format XMI identifiers """ return 'xmi.%s' % id