Generate code from plant UML

+2 votes
asked Aug 31, 2015 in Wanted features by anonymous
I need to be able to read a plant UML file into some DOM and iterate over it to create code files or to import or export from other formats. How can this be done is there a Model and parser in the existing Java API.
commented Mar 27, 2016 by anonymous
I am facing the same problem. Were you able to obtain such a structure with plant UML?

1 Answer

0 votes
answered Mar 29, 2016 by plantuml (294,960 points)
The best option seems to be XMI export (see http://plantuml.com/xmi.html )

Would this fit your needs ?

Support for XMI is very limited right now, but we are willing to enhance it, only if anyone would use it.
commented Dec 7, 2016 by plant-conn (120 points)
Just out of curiosity... The work on xmi is still goin on? I tried to output as xmi, kinda worked for me, but it would be a huge improvement if the output of namespaces would be supported (its just "model1" right now) - Unfortunately I'm not really good in Java so as much as I would, I cant help on this :-/
commented Dec 7, 2016 by plantuml (294,960 points)
We are really waiting for user requests on XMI, because it's difficult to know if this feature is used or not.
So do not hesitate to ask if you need something.

For example, in last beta
https://dl.dropboxusercontent.com/u/13064071/plantuml.jar

We've just added the following setting:
skinparam model FOO

This is probably not exactly what you are looking for, so do not hesitate to give us a concrete/simple example of your expectation.
Thanks!
commented Dec 9, 2016 by plant-conn (120 points)
True, thats not exactly what I'm looking for ;) - what I'm trying to use XMI for is to generate PHP classes from it. So, having the correct namespaces set in the XMI would be really great, since the PHP classes could be placed in the correct folders under their defined namespaces etc...

At the moment it looks like that:

PlantUML:

namespace User {
    class Person <Eloquent> {
        string #username
        string #email
        string #firstname
        string #lastname
        int #age
        Carbon #dateOfBirth
        Address #address
        Account #account
        Profile #profile
        Boolean #fraudulent

        update()
        create()
        delete()
    }
}

Will become:

<?xml version="1.0" encoding="UTF-8"?><XMI xmlns:UML="href://org.omg/UML/1.3" xmi.version="1.1">
<XMI.header>
<XMI.metamodel xmi.name="UML" xmi.version="1.3"/>
</XMI.header>
<XMI.content>
<UML:Model name="PlantUML" xmi.id="model1">
<UML:Namespace.ownedElement>
<UML:Class name="Person" namespace="model1" xmi.id="cl0003">
<UML:Classifier.feature>
<UML:Attribute name="string #username" xmi.id="att86"/>
<UML:Attribute name="string #email" xmi.id="att87"/>
<UML:Attribute name="string #firstname" xmi.id="att88"/>
<UML:Attribute name="string #lastname" xmi.id="att89"/>
<UML:Attribute name="int #age" xmi.id="att90"/>
<UML:Attribute name="Carbon #dateOfBirth" xmi.id="att91"/>
<UML:Attribute name="string #address" xmi.id="att92"/>
<UML:Attribute name="Account #account" xmi.id="att93"/>
<UML:Attribute name="Profile #profile" xmi.id="att94"/>
<UML:Attribute name="bool #fraudulent" xmi.id="att95"/>
<UML:Operation name="Person #update()" xmi.id="att96"/>
<UML:Operation name="Person #create()" xmi.id="att97"/>
<UML:Operation name="null #delete()" xmi.id="att98"/>


Whereas "model1" should be "User" -  or if theres a "namespace2 in namespace1" plantuml description, it should become "Namespace1.Namespace2" - or if namespace divider is set to something else, e.g. ::  "Namespace1::Namsepace2".

Also having extended relations in the XMI output would be a very useful and much needed feature :)
commented Dec 10, 2016 by plantuml (294,960 points)
We've made some change in last beta:
https://dl.dropboxusercontent.com/u/13064071/plantuml.jar

Now, the example:
@startuml
namespace User {
    class Person <Eloquent> {
        string #username
        string #email
        string #firstname
        string #lastname
        int #age
        Carbon #dateOfBirth
        Address #address
        Account #account
        Profile #profile
        Boolean #fraudulent

        update()
        create()
        delete()
    }
    
    class PersonRich extends Person
}
@enduml

Generates:
<?xml version="1.0" encoding="UTF-8"?><XMI xmlns:UML="href://org.omg/UML/1.3" xmi.version="1.1">
<XMI.header>
<XMI.metamodel xmi.name="UML" xmi.version="1.3"/>
</XMI.header>
<XMI.content>
<UML:Model name="PlantUML" xmi.id="model1">
<UML:Namespace.ownedElement>
<UML:Class name="Person" namespace="User" xmi.id="cl0002">
<UML:Classifier.feature>
<UML:Attribute name="string #username" xmi.id="att5"/>
<UML:Attribute name="string #email" xmi.id="att6"/>
<UML:Attribute name="string #firstname" xmi.id="att7"/>
<UML:Attribute name="string #lastname" xmi.id="att8"/>
<UML:Attribute name="int #age" xmi.id="att9"/>
<UML:Attribute name="Carbon #dateOfBirth" xmi.id="att10"/>
<UML:Attribute name="Address #address" xmi.id="att11"/>
<UML:Attribute name="Account #account" xmi.id="att12"/>
<UML:Attribute name="Profile #profile" xmi.id="att13"/>
<UML:Attribute name="Boolean #fraudulent" xmi.id="att14"/>
<UML:Operation name="update()" xmi.id="att15"/>
<UML:Operation name="create()" xmi.id="att16"/>
<UML:Operation name="delete()" xmi.id="att17"/>
</UML:Classifier.feature>
</UML:Class>
<UML:Class name="PersonRich" namespace="User" xmi.id="cl0003">
<UML:Classifier.feature/>
</UML:Class>
<UML:Generalization child="cl0003" name="" namespace="model1" parent="cl0002" xmi.id="ass18"/>
</UML:Namespace.ownedElement>
</UML:Model>
</XMI.content>
</XMI>

which is probably better.
About relations, there does not seems to be one standard way of exporting them (see http://plantuml.com/xmi ).
So by default, we do not export them.
You can use either -xmi:argo or -xmi:star to generate them (the posted example done with -xmi:star )
Probably some things are missing, so do not hesitate to post here with some simple examples. Thanks
commented Dec 11, 2016 by plant-conn (120 points)
Wow! Looks promising, will check it out soon.
commented Dec 12, 2016 by plant-conn (120 points)
So, checked it out and I like it so far. As you said, some things are probably missing - and they do ;)

consider following puml

@startuml
set namespaceSeparator ::

abstract class AbstractList {

}
abstract AbstractCollection

interface List
interface Collection

class List {
    #counter : int
}

namespace test {
    class List {
       +counter : string
    }
}

List <|-- AbstractList
Collection <|-- AbstractCollection

test::List --|> AbstractCollection

Collection <|- List
AbstractCollection <|- AbstractList
AbstractList <|-- ArrayList

class ArrayList {
 #elementData : Object[]
size()
}

enum TimeUnit {
DAYS
HOURS
MINUTES
}
@enduml

Generates (I use -xmi:star, since the ArgoUML xmi is... well... ;) ):

<?xml version="1.0" encoding="UTF-8"?>
<XMI xmlns:UML="href://org.omg/UML/1.3" xmi.version="1.1">
    <XMI.header>
        <XMI.metamodel xmi.name="UML" xmi.version="1.3"/>
    </XMI.header>
    <XMI.content>
        <UML:Model name="PlantUML" xmi.id="model1">
            <UML:Namespace.ownedElement>
                <UML:Class name="AbstractList" namespace="model1" xmi.id="cl0002">
                    <UML:Classifier.feature/>
                </UML:Class>
                <UML:Class name="AbstractCollection" namespace="model1" xmi.id="cl0003">
                    <UML:Classifier.feature/>
                </UML:Class>
                <UML:Class name="List" namespace="model1" xmi.id="cl0004">
                    <UML:Classifier.feature>
                        <UML:Attribute name="counter : int" xmi.id="att18"/>
                    </UML:Classifier.feature>
                </UML:Class>
                <UML:Class name="Collection" namespace="model1" xmi.id="cl0005">
                    <UML:Classifier.feature/>
                </UML:Class>
                <UML:Class name="List" namespace="test" xmi.id="cl0007">
                    <UML:Classifier.feature>
                        <UML:Attribute name="counter : string" xmi.id="att19"/>
                    </UML:Classifier.feature>
                </UML:Class>
                <UML:Class name="Object" namespace="model1" xmi.id="cl0008">
                    <UML:Classifier.feature/>
                </UML:Class>
                <UML:Class name="ArrayList" namespace="model1" xmi.id="cl0014">
                    <UML:Classifier.feature>
                        <UML:Attribute name="elementData : Object[]" xmi.id="att20"/>
                        <UML:Operation name="size()" xmi.id="att21"/>
                    </UML:Classifier.feature>
                </UML:Class>
                <UML:Class name="TimeUnit" namespace="model1" xmi.id="cl0017">
                    <UML:Classifier.feature>
                        <UML:Attribute name="DAYS" xmi.id="att22"/>
                        <UML:Attribute name="HOURS" xmi.id="att23"/>
                        <UML:Attribute name="MINUTES" xmi.id="att24"/>
                    </UML:Classifier.feature>
                </UML:Class>
                <UML:Generalization child="cl0002" name="" namespace="model1" parent="cl0004" xmi.id="ass25"/>
                <UML:Generalization child="cl0003" name="" namespace="model1" parent="cl0005" xmi.id="ass26"/>
                <UML:Generalization child="cl0007" name="" namespace="model1" parent="cl0003" xmi.id="ass27"/>
                <UML:Generalization child="cl0004" name="" namespace="model1" parent="cl0005" xmi.id="ass28"/>
                <UML:Generalization child="cl0002" name="" namespace="model1" parent="cl0003" xmi.id="ass29"/>
                <UML:Generalization child="cl0014" name="" namespace="model1" parent="cl0002" xmi.id="ass30"/>
                <UML:Association namespace="model1" xmi.id="ass31">
                    <UML:Association.connection>
                        <UML:AssociationEnd aggregation="aggregate" association="ass31" type="cl0014" xmi.id="end32">
                            <UML:AssociationEnd.participant/>
                        </UML:AssociationEnd>
                        <UML:AssociationEnd association="ass31" type="cl0008" xmi.id="end33">
                            <UML:AssociationEnd.participant/>
                        </UML:AssociationEnd>
                    </UML:Association.connection>
                </UML:Association>
            </UML:Namespace.ownedElement>
        </UML:Model>
    </XMI.content>
</XMI>



A few things that go wrong as far as I can see:

* the visibility of methods and fields gets lost - e.g. '+counter : string' becomes 'name="counter : string"' or look at the +size() method in ArrayList

Following missing information make it hard to find out about class inheritance or interface implementations:
* the information about a class being abstract gets lost - see abstract class AbstractList (cl0002)
* The information about a class being an interface gets lost - e.g. Interface Collection (cl0005)

Hope, I described those points so its understandable to you :)
commented Dec 13, 2016 by plantuml (294,960 points)
Ok, thanks for your tests.

Here is a new beta https://dl.dropboxusercontent.com/u/13064071/plantuml.jar
 
The following diagram:

@startuml
interface MyInterface {
}

abstract class AbstractList {
+counter : string
}
@enduml

Gives now:

<?xml version="1.0" encoding="UTF-8"?><XMI xmlns:UML="href://org.omg/UML/1.3" xmi.version="1.1">
<XMI.header>
<XMI.metamodel xmi.name="UML" xmi.version="1.3"/>
</XMI.header>
<XMI.content>
<UML:Model name="PlantUML" xmi.id="model1">
<UML:Namespace.ownedElement>
<UML:Class isInterface="true" name="MyInterface" namespace="model1" xmi.id="cl0001">
<UML:Classifier.feature/>
</UML:Class>
<UML:Class isAbstract="true" name="AbstractList" namespace="model1" xmi.id="cl0002">
<UML:Classifier.feature>
<UML:Attribute name="counter : string" visibility="public" xmi.id="att3"/>
</UML:Classifier.feature>
</UML:Class>
</UML:Namespace.ownedElement>
</UML:Model>
</XMI.content>
</XMI>

We have added a isInterface="true", not sure that this is really standard.
But probably some other things are missing, so do not hesitate to post again.

Thanks,
commented Dec 13, 2016 by plant-conn (120 points)
Its great! I can use it now how I want ;) https://github.com/mk-conn/plant2code - i can generate code from it. Problems solved :)
...