Archi Forum

Archi => General Archi Discussion => Topic started by: Bata on December 08, 2015, 18:35:04 PM

Title: How do I Merge two Archi models into one model?
Post by: Bata on December 08, 2015, 18:35:04 PM
Hi I would like to merge two Archi models into one model so that I can re-use my objects and their defintions without having to redo them for every model I use. Is this possible? I would very much like to know how.
Title: Re: How do I Merge two Archi models into one model?
Post by: Jean-Baptiste Sarrodie on December 08, 2015, 19:15:26 PM
Hi,

The short answer to your question is: you can't :-)

The long answer is: it may be possible if all your models are created through the exact same template (so that internal ID for elements are the same accross files) and through GRAFICO plugin. I've written a wiki topic about this use case (https://github.com/archi-contribs/archi-grafico-plugin/wiki/Merge-two-%28or-more%29-models).

There should also be some ways through the Open Group Open Exchange format and some XML merge tools but I have never tested it.

Regards,

JB
Title: Re: How do I Merge two Archi models into one model?
Post by: amicone on December 20, 2015, 15:43:18 PM
 :) Heya, new ArchiMate user here. Yes, XML is the way to go. I haven't tried to merge two ArchiMate models in Archi, but I just merged all the artifacts from another non-standard sub-architecture with an ArchiMate architecture model through a Python script using xml.

The only issue I've noticed is that the folder organization falls apart on export/import. If you ask it to export the folder structure, it will not import it afterwards, even if you didn't change it at all.

I don't think my python script would help you much, but I can give you some pointers with some code snippets. If you aren't a python hacker, hopefully some of this will help you using your toolset, whatever that might be.

First, xpath is your friend.

Second, you want to import the elements of interest from the XML export.

For example, this snippet will get you all the business actors, here mine also has a property I added that abberviates the actor name:
import xml.etree.ElementTree as ET

ns = {'am': 'http://www.opengroup.org/xsd/archimate',
      'xsi': 'http://www.w3.org/2001/XMLSchema-instance'}

tree = ET.parse(dataDir + "archi_export.xml")
root = tree.getroot()
ID(root)

modelOrgs = {}
for e in root.findall("./am:elements/am:element[@xsi:type='BusinessActor']", ns):
    ou = e.find("am:label",ns)
    abbr = e.find("am:properties/am:property/am:value", ns)
    modelOrgs[abbr.text] = (e.get('identifier'), ou.text)


Third, you need to manage the ID's so they are all consistent and generate new ones as needed. That's what the ID(root) call above does, it finds all the identifiers already in the XML export and stores them, so when you generate new ones there's no accidental replicated ID's (improbable, I know, but the improbable ocassionally happens). The ID.get() method here generates new ID's in the Archi format and stores them in a table so they don't get re-used:


class ID:
    ids = set()
    def __init__(self, root):
        for i in root.findall(".//*[@identifier]",ns):
            self.ids.update([i.get('identifier')])
    def getID():
         id = 'id-{:08x}'.format(random.getrandbits(32))
         while id in ID.ids:
            id = 'id-{:08x}'.format(random.getrandbits(32))
         ID.ids.update(id)
         return(id)


Fourth, you'll need a way to keep track of all the relationships, here's a sample of how I do that (don't expect to be able to follow all this, there is code that is not present here, but it should give you an idea).


relationships = []

lemRoot = root.find('./am:elements', ns)
for d in departments.keys():
    for service in departments[d].responsiblities:
        bsID = ID.getID()
        attrs = {'xsi:type' : 'BusinessService', 'identifier': bsID}
        elem  = ET.SubElement(elemRoot, 'element', attrs)
        label = ET.SubElement(elem,'label', {'xml:lang' : 'en'})
        label.text = service
        doc = ET.SubElement(elem,'documentation', {'xml:lang' : 'en'})
        doc.text = serviceDocumentation[service]
        relationships.append((ID.getID(), "AssignmentRelationship", bsID, modelOrgs[d][0]))

elemRoot = root.find('./am:relationships', ns)
for r in relationships:
    attrs = { 'identifier':r[0],
              'xsi:type':r[1],
              'source':r[2],
              'target':r[3]}
    elem = ET.SubElement(elemRoot, 'relationship', attrs)


Fifth, a python tip, you need to change the archimate xsd as the default xml namespace. Archi's XML parser kind of gets thrown for a loop if archimate isn't the default namespace.


ns = {'am': 'http://www.opengroup.org/xsd/archimate',
      'xsi': 'http://www.w3.org/2001/XMLSchema-instance'}

ET.register_namespace('', ns['am'])
ET.register_namespace('xsi', ns['xsi']);
tree.write(dataDir + "archi_import.xml")


Hopefully, this is helpful.
Title: Re: How do I Merge two Archi models into one model?
Post by: Phil Beauvoir on January 06, 2016, 10:56:25 AM
Thanks for sharing this Python snippet! Hopefully someone will find it useful.

Phil