一步一步将PlantUML类图导出为自定义格式的XMI文件
说明:
- 首次发表日期:2024-09-08
- PlantUML官网: https://plantuml.com/zh/
- PlantUML命令行文档: https://plantuml.com/zh/command-line#6a26f548831e6a8c
- PlantUML XMI文档: https://plantuml.com/zh/xmi
- 进一步用处:根据导出的XMI文件生成代码
PlantUML(Java)中获取类图以及plantuml xmi代码是如何遍历实体并获取属性的
以下是来自 https://stackoverflow.com/questions/76599075/parse-uml-class-diagram-with-plantuml-java-api 的代码:
String source = "@startumln" + PUT YOUR CLASS DIAGRAM HERE "@enduml"; SourceStringReader r = new SourceStringReader(source); FileOutputStream file = new FileOutputStream("testGroovy2.png"); ClassDiagram cd = (ClassDiagram) r.getBlocks().get(0).getDiagram(); Collection<Quark<Entity>> classes = cd.getEntityFactory().root().getChildren(); classes.stream().forEach(c-> System.out.println(c));
从中知道如何获取ClassDiagram
查看 net.sourceforge.plantuml.xmi.XmiClassDiagramAbstract
中XmiClassDiagramStandard
的定义:
public class XmiClassDiagramStandard extends XmiClassDiagramAbstract implements XmlDiagramTransformer { public XmiClassDiagramStandard(ClassDiagram classDiagram) throws ParserConfigurationException { super(classDiagram); Iterator var2 = classDiagram.getEntityFactory().leafs().iterator(); while(var2.hasNext()) { Entity ent = (Entity)var2.next(); Element cla = this.createEntityNode(ent); if (cla != null) { this.ownedElementRoot.appendChild(cla); this.done.add(ent); } } } }
从中知道如何遍历entity
查看 net.sourceforge.plantuml.xmi.XmiClassDiagramStandard
中的createEntityNode
方法:
protected final Element createEntityNode(Entity entity) { Element cla = this.document.createElement("UML:Class"); if (entity.getLeafType() == LeafType.NOTE) { return null; } else { cla.setAttribute("xmi.id", entity.getUid()); cla.setAttribute("name", entity.getDisplay().get(0).toString()); Stereotype stereotype = entity.getStereotype(); if (stereotype != null) { Element stereo = this.document.createElement("UML:ModelElement.stereotype"); Iterator var5 = stereotype.getMultipleLabels().iterator(); while(var5.hasNext()) { String s = (String)var5.next(); Element name = this.document.createElement("UML:Stereotype"); name.setAttribute("name", s); stereo.appendChild(name); } cla.appendChild(stereo); } LeafType type = entity.getLeafType(); if (type == LeafType.ABSTRACT_CLASS) { cla.setAttribute("isAbstract", "true"); } else if (type == LeafType.INTERFACE) { cla.setAttribute("isInterface", "true"); } if (entity.isStatic()) { cla.setAttribute("isStatic", "true"); } if (entity.getVisibilityModifier() == VisibilityModifier.PRIVATE_FIELD || entity.getVisibilityModifier() == VisibilityModifier.PRIVATE_METHOD) { cla.setAttribute("visibility", entity.getVisibilityModifier().getXmiVisibility()); } Element feature = this.document.createElement("UML:Classifier.feature"); cla.appendChild(feature); Member m; Element operation; VisibilityModifier visibility; ListIterator var13; CharSequence cs; for(var13 = entity.getBodier().getFieldsToDisplay().iterator(); var13.hasNext(); feature.appendChild(operation)) { cs = (CharSequence)var13.next(); m = (Member)cs; operation = this.document.createElement("UML:Attribute"); operation.setAttribute("xmi.id", "att" + this.classDiagram.getUniqueSequence()); operation.setAttribute("name", m.getDisplay(false)); visibility = m.getVisibilityModifier(); if (visibility != null) { operation.setAttribute("visibility", visibility.getXmiVisibility()); } if (m.isStatic()) { operation.setAttribute("isStatic", "true"); } } for(var13 = entity.getBodier().getMethodsToDisplay().iterator(); var13.hasNext(); feature.appendChild(operation)) { cs = (CharSequence)var13.next(); m = (Member)cs; operation = this.document.createElement("UML:Operation"); operation.setAttribute("xmi.id", "att" + this.classDiagram.getUniqueSequence()); operation.setAttribute("name", m.getDisplay(false)); visibility = m.getVisibilityModifier(); if (visibility != null) { operation.setAttribute("visibility", visibility.getXmiVisibility()); } if (m.isStatic()) { operation.setAttribute("isStatic", "true"); } } return cla; } }
从中可以看出:
entity.getBodier().getFieldsToDisplay().iterator()
是获取entity的attribute的迭代器entity.getBodier().getMethodsToDisplay().iterator()
是获取entity的operation的迭代器name
,isAbstract
,isInterface
和isStatic
这些属性是如何获取的
还有 https://github.com/plantuml/plantuml/pull/1298/files 是2023年2月的一个PR(写本文时尚未Merge),可以作为参考(有待阅读)。
使用JAVA代码将PlantUML类图导出为XMI
通过调用exportDiagram方法
import net.sourceforge.plantuml.FileFormat; import net.sourceforge.plantuml.FileFormatOption; import net.sourceforge.plantuml.SourceStringReader; import java.io.FileOutputStream; public class Main { public static void main(String[] args) throws IOException { OutputStream output = new FileOutputStream("test.xmi"); FileFormatOption fileFormatOption = new FileFormatOption(FileFormat.XMI_ARGO); String content = new String(Files.readAllBytes(Paths.get("a.puml"))); SourceStringReader reader = new SourceStringReader(content); reader.getBlocks().get(0).getDiagram().exportDiagram(output, 0, fileFormatOption); } }
其中FileFormat
是一个枚举,定义了XMI_STANDARD
,XMI_STAR
和XMI_ARGO
等格式
分析getDiagram的调用链
getDiagram
方法来自net.sourceforge.plantuml.core.Diagram
提供的exportDiagram
接口方法,其实现:
public final ImageData exportDiagram(OutputStream os, int index, FileFormatOption fileFormatOption) throws IOException { long now = System.currentTimeMillis(); ImageData var6; try { var6 = this.exportDiagramNow(os, index, fileFormatOption); } finally { if (OptionFlags.getInstance().isEnableStats()) { StatsUtilsIncrement.onceMoreGenerate(System.currentTimeMillis() - now, this.getClass(), fileFormatOption.getFileFormat()); } } return var6; }
其中主要是调用了net.sourceforge.plantuml.AbstractPSystem
中的exportDiagramNow
接口方法。而其在net.sourceforge.plantuml.UmlDiagram
中的实现如下:
protected final ImageData exportDiagramNow(OutputStream os, int index, FileFormatOption fileFormatOption) throws IOException { fileFormatOption = fileFormatOption.withTikzFontDistortion(this.getSkinParam().getTikzFontDistortion()); if (fileFormatOption.getFileFormat() == FileFormat.PDF) { return this.exportDiagramInternalPdf(os, index); } else { try { ImageData imageData = this.exportDiagramInternal(os, index, fileFormatOption); this.lastInfo = new XDimension2D((double)imageData.getWidth(), (double)imageData.getHeight()); return imageData; } catch (NoStyleAvailableException var5) { this.exportDiagramError(os, var5, fileFormatOption, (String)null); return ImageDataSimple.error(var5); } catch (UnparsableGraphvizException var6) { Logme.error(var6); this.exportDiagramError(os, var6.getCause(), fileFormatOption, var6.getGraphvizVersion()); return ImageDataSimple.error(var6); } catch (Throwable var7) { this.exportDiagramError(os, var7, fileFormatOption, (String)null); return ImageDataSimple.error(var7); } } }
可以看出其主要是调用了net.sourceforge.plantuml.UmlDiagram.exportDiagramInternal
接口方法,由于当前的类是ClassDiagram
,其将调用net.sourceforge.plantuml.classdiagram.ClassDiagram
实现的exportDiagramInternal
方法:
protected final ImageData exportDiagramInternal(OutputStream os, int index, FileFormatOption fileFormatOption) throws IOException { return this.useLayoutExplicit != 0 ? this.exportLayoutExplicit(os, index, fileFormatOption) : super.exportDiagramInternal(os, index, fileFormatOption); }
其中net.sourceforge.plantuml.classdiagram.ClassDiagram
继承net.sourceforge.plantuml.objectdiagram.AbstractClassOrObjectDiagram
继承net.sourceforge.plantuml.classdiagram.AbstractEntityDiagram
继承net.atmp.CucaDiagram
而net.atmp.CucaDiagram.exportDiagramInternal
方法中涉及XMI的部分如下:
this.createFilesXmi(os, fileFormat); return ImageDataSimple.ok();
其调用了net.atmp.CucaDiagram.createFilesXmi
方法,其定义如下:
private void createFilesXmi(OutputStream suggestedFile, FileFormat fileFormat) throws IOException { CucaDiagramXmiMaker maker = new CucaDiagramXmiMaker(this, fileFormat); maker.createFiles(suggestedFile); }
其中调用了net.sourceforge.plantuml.xmi.CucaDiagramXmiMaker
的createFiles
方法,其定义如下:
public void createFiles(OutputStream fos) throws IOException { try { Object xmi; if (this.diagram instanceof StateDiagram) { xmi = new XmiStateDiagram((StateDiagram)this.diagram); } else if (this.diagram instanceof DescriptionDiagram) { xmi = this.createDescriptionDiagram(); } else { if (!(this.diagram instanceof ClassDiagram)) { throw new UnsupportedOperationException("Diagram type " + this.diagram.getUmlDiagramType() + " is not supported in XMI"); } xmi = this.createClassDiagram(); } ((XmlDiagramTransformer)xmi).transformerXml(fos); } catch (ParserConfigurationException var3) { Log.error(var3.toString()); Logme.error(var3); throw new IOException(var3.toString()); } catch (TransformerException var4) { Log.error(var4.toString()); Logme.error(var4); throw new IOException(var4.toString()); } }
可以看出涉及创建xmi文件的关键2行为:
xmi = this.createClassDiagram(); ((XmlDiagramTransformer)xmi).transformerXml(fos);
而createClassDiagram
的定义如下:
private XmlDiagramTransformer createClassDiagram() throws ParserConfigurationException { if (this.fileFormat == FileFormat.XMI_STANDARD) { return new XmiClassDiagramStandard((ClassDiagram)this.diagram); } else if (this.fileFormat == FileFormat.XMI_ARGO) { return new XmiClassDiagramArgo((ClassDiagram)this.diagram); } else if (this.fileFormat == FileFormat.XMI_SCRIPT) { return new XmiClassDiagramScript((ClassDiagram)this.diagram); } else if (this.fileFormat == FileFormat.XMI_STAR) { return new XmiClassDiagramStar((ClassDiagram)this.diagram); } else { throw new UnsupportedOperationException(); } }
分析getDiagram方法后,调用内部API导出XMI
import net.sourceforge.plantuml.FileFormat; import net.sourceforge.plantuml.FileFormatOption; import net.sourceforge.plantuml.SourceStringReader; import net.sourceforge.plantuml.xmi.XmiClassDiagramArgo; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import java.io.FileOutputStream; public class Main { public static void main(String[] args) throws IOException, ParserConfigurationException, TransformerException { OutputStream fos = new FileOutputStream("test2.xmi"); FileFormatOption fileFormatOption = new FileFormatOption(FileFormat.XMI_ARGO); String content = new String(Files.readAllBytes(Paths.get("a.puml"))); SourceStringReader reader = new SourceStringReader(content); ClassDiagram classDiagram = (ClassDiagram) reader.getBlocks().get(0).getDiagram(); Object xmi = new XmiClassDiagramArgo(classDiagram); ((XmlDiagramTransformer)xmi).transformerXml(fos); } }
读取一个uml文件并打印其中的属性信息
现在了解了一些后,使用以下Java代码来查看UML文件的信息
package org.example; import net.sourceforge.plantuml.SourceStringReader; import net.sourceforge.plantuml.abel.Entity; import net.sourceforge.plantuml.abel.LeafType; import net.sourceforge.plantuml.abel.Link; import net.sourceforge.plantuml.classdiagram.ClassDiagram; import net.sourceforge.plantuml.cucadiagram.Member; import net.sourceforge.plantuml.skin.VisibilityModifier; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Iterator; import java.util.ListIterator; public class Main { public static void main(String[] args) throws IOException, ParserConfigurationException, TransformerException { OutputStream output = new FileOutputStream("test.xmi"); // String source = "@startumln"; // source += "Bob -> Alice : hellon"; // source += "@endumln"; String content = new String(Files.readAllBytes(Paths.get("a.puml"))); SourceStringReader reader = new SourceStringReader(content); ClassDiagram classDiagram = (ClassDiagram) reader.getBlocks().get(0).getDiagram(); String titleName = classDiagram.getTitleDisplay().get(0).toString(); System.out.println("title: " + titleName); Iterator var2 = classDiagram.getEntityFactory().leafs().iterator(); while(var2.hasNext()) { Entity entity = (Entity)var2.next(); System.out.println("----------------------------------"); System.out.println("uid: " + entity.getUid()); if (entity.getLeafType() == LeafType.NOTE) { // entity.isAloneAndUnlinked(); // System.out.println("Entity type: " + entity.getLeafType()); } else { Iterator var1 = classDiagram.getLinks().iterator(); while(var1.hasNext()) { Link link = (Link)var1.next(); if (link.contains(entity)) { Entity other = link.getOther(entity); if (other.getLeafType() == LeafType.NOTE) { System.out.println("Note: " + other.getDisplay().get(0).toString()); } } } System.out.println("Entity type: " + entity.getLeafType()); String entityName = entity.getDisplay().get(0).toString(); System.out.println("Entity name: " + entityName); System.out.println("Package: " + entity.getQuark().getParent().toString()); LeafType type = entity.getLeafType(); if (type == LeafType.ABSTRACT_CLASS) { System.out.println("isAbstract"); } else if (type == LeafType.INTERFACE) { System.out.println("isInterface"); } if (entity.isStatic()) { System.out.println(("isStatic")); } if (entity.getVisibilityModifier() == VisibilityModifier.PRIVATE_FIELD || entity.getVisibilityModifier() == VisibilityModifier.PRIVATE_METHOD) { System.out.println("visibility: " + entity.getVisibilityModifier().getXmiVisibility()); } Member m; VisibilityModifier visibility; ListIterator var13; CharSequence cs; for (var13 = entity.getBodier().getFieldsToDisplay().iterator(); var13.hasNext();) { cs = (CharSequence)var13.next(); m = (Member) cs; System.out.println("field name: " + m.getDisplay(false)); visibility = m.getVisibilityModifier(); if (visibility != null) { System.out.println("visibility: " + visibility.getXmiVisibility()); } if (m.isStatic()) { System.out.println("isStatic"); } } for (var13 = entity.getBodier().getMethodsToDisplay().iterator(); var13.hasNext();) { cs = (CharSequence)var13.next(); m = (Member) cs; System.out.println("operation name: " + m.getDisplay(false)); visibility = m.getVisibilityModifier(); if (visibility != null) { System.out.println("visibility: " + visibility.getXmiVisibility()); } if (m.isStatic()) { System.out.println("isStatic"); } } } } // Write the first image to "png" // String desc = reader.outputImage(output).getDescription(); // Return a null string if no generation } }
创建JAVA项目并打包为JAR包:将PlantUML导出为自定义格式的XMI文件
创建项目
使用IDEA创建一个maven项目,然后打开plantuml的maven仓库页面: https://mvnrepository.com/artifact/net.sourceforge.plantuml/plantuml/1.2024.6 将dependency标签拷贝到pom.xml中
添加用于自定义XMI格式的类
由于不能引用XmiClassDiagramAbstract
(提示 is not public in 'net.sourceforge.plantuml.xmi'. Cannot be accessed from outside package),所以在src/main/java
下新建package net.sourceforge.plantuml.xmi
然后添加类XmiClassDiagramCustom
(extends XmiClassDiagramAbstract):
package net.sourceforge.plantuml.xmi; import java.util.Iterator; import java.util.ListIterator; import javax.xml.parsers.ParserConfigurationException; import net.sourceforge.plantuml.abel.Entity; import net.sourceforge.plantuml.abel.LeafType; import net.sourceforge.plantuml.abel.Link; import net.sourceforge.plantuml.classdiagram.ClassDiagram; import net.sourceforge.plantuml.cucadiagram.Member; import net.sourceforge.plantuml.decoration.LinkDecor; import net.sourceforge.plantuml.klimt.creole.Display; import net.sourceforge.plantuml.skin.VisibilityModifier; import net.sourceforge.plantuml.stereo.Stereotype; import org.w3c.dom.Element; public class XmiClassDiagramCustom extends XmiClassDiagramAbstract implements XmlDiagramTransformer { public XmiClassDiagramCustom(ClassDiagram classDiagram) throws ParserConfigurationException { super(classDiagram); Iterator var2 = classDiagram.getEntityFactory().leafs().iterator(); Element titleElement = this.document.createElement("UML:Title"); titleElement.setAttribute("name", classDiagram.getTitleDisplay().get(0).toString()); this.ownedElementRoot.appendChild(titleElement); while(var2.hasNext()) { Entity ent = (Entity)var2.next(); Element cla = this.createEntityNodeCustom(ent, classDiagram); if (cla != null) { this.ownedElementRoot.appendChild(cla); this.done.add(ent); } } var2 = classDiagram.getLinks().iterator(); while(var2.hasNext()) { Link link = (Link)var2.next(); this.addLink(link); } } protected final Element createEntityNodeCustom(Entity entity, ClassDiagram classDiagram) { Element cla = this.document.createElement("UML:Class"); if (entity.getLeafType() == LeafType.NOTE) { return null; } else { cla.setAttribute("xmi.id", entity.getUid()); cla.setAttribute("name", entity.getDisplay().get(0).toString()); // Get Note: Iterator var1 = classDiagram.getLinks().iterator(); while(var1.hasNext()) { Link link = (Link)var1.next(); if (link.contains(entity)) { Entity other = link.getOther(entity); if (other.getLeafType() == LeafType.NOTE) { cla.setAttribute("note", other.getDisplay().get(0).toString()); // System.out.println("Note: " + other.getDisplay().get(0).toString()); } } } cla.setAttribute("package", entity.getQuark().getParent().toString()); Stereotype stereotype = entity.getStereotype(); if (stereotype != null) { Element stereo = this.document.createElement("UML:ModelElement.stereotype"); Iterator var5 = stereotype.getMultipleLabels().iterator(); while(var5.hasNext()) { String s = (String)var5.next(); Element name = this.document.createElement("UML:Stereotype"); name.setAttribute("name", s); stereo.appendChild(name); } cla.appendChild(stereo); } LeafType type = entity.getLeafType(); if (type == LeafType.ABSTRACT_CLASS) { cla.setAttribute("isAbstract", "true"); } else if (type == LeafType.INTERFACE) { cla.setAttribute("isInterface", "true"); } if (entity.isStatic()) { cla.setAttribute("isStatic", "true"); } if (entity.getVisibilityModifier() == VisibilityModifier.PRIVATE_FIELD || entity.getVisibilityModifier() == VisibilityModifier.PRIVATE_METHOD) { cla.setAttribute("visibility", entity.getVisibilityModifier().getXmiVisibility()); } Element feature = this.document.createElement("UML:Classifier.feature"); cla.appendChild(feature); Member m; Element operation; VisibilityModifier visibility; ListIterator var13; CharSequence cs; for(var13 = entity.getBodier().getFieldsToDisplay().iterator(); var13.hasNext(); feature.appendChild(operation)) { cs = (CharSequence)var13.next(); m = (Member)cs; operation = this.document.createElement("UML:Attribute"); operation.setAttribute("xmi.id", "att" + this.classDiagram.getUniqueSequence()); operation.setAttribute("name", m.getDisplay(false)); visibility = m.getVisibilityModifier(); if (visibility != null) { operation.setAttribute("visibility", visibility.getXmiVisibility()); } if (m.isStatic()) { operation.setAttribute("isStatic", "true"); } } for(var13 = entity.getBodier().getMethodsToDisplay().iterator(); var13.hasNext(); feature.appendChild(operation)) { cs = (CharSequence)var13.next(); m = (Member)cs; operation = this.document.createElement("UML:Operation"); operation.setAttribute("xmi.id", "att" + this.classDiagram.getUniqueSequence()); operation.setAttribute("name", m.getDisplay(false)); visibility = m.getVisibilityModifier(); if (visibility != null) { operation.setAttribute("visibility", visibility.getXmiVisibility()); } if (m.isStatic()) { operation.setAttribute("isStatic", "true"); } } return cla; } } // copy from XmiClassDiagramStar private void addLink(Link link) { if (!link.isHidden() && !link.isInvis()) { String assId = "ass" + this.classDiagram.getUniqueSequence(); if (link.getType().getDecor1() != LinkDecor.EXTENDS && link.getType().getDecor2() != LinkDecor.EXTENDS) { Element association = this.document.createElement("UML:Association"); association.setAttribute("xmi.id", assId); association.setAttribute("namespace", CucaDiagramXmiMaker.getModel(this.classDiagram)); if (!Display.isNull(link.getLabel())) { association.setAttribute("name", this.forXMI(link.getLabel())); } Element connection = this.document.createElement("UML:Association.connection"); Element end1 = this.document.createElement("UML:AssociationEnd"); end1.setAttribute("xmi.id", "end" + this.classDiagram.getUniqueSequence()); end1.setAttribute("association", assId); end1.setAttribute("type", link.getEntity1().getUid()); if (link.getQuantifier1() != null) { end1.setAttribute("name", this.forXMI(link.getQuantifier1())); } Element endparticipant1 = this.document.createElement("UML:AssociationEnd.participant"); if (link.getType().getDecor2() == LinkDecor.COMPOSITION) { end1.setAttribute("aggregation", "composite"); } if (link.getType().getDecor2() == LinkDecor.AGREGATION) { end1.setAttribute("aggregation", "aggregate"); } end1.appendChild(endparticipant1); connection.appendChild(end1); Element end2 = this.document.createElement("UML:AssociationEnd"); end2.setAttribute("xmi.id", "end" + this.classDiagram.getUniqueSequence()); end2.setAttribute("association", assId); end2.setAttribute("type", link.getEntity2().getUid()); if (link.getQuantifier2() != null) { end2.setAttribute("name", this.forXMI(link.getQuantifier2())); } Element endparticipant2 = this.document.createElement("UML:AssociationEnd.participant"); if (link.getType().getDecor1() == LinkDecor.COMPOSITION) { end2.setAttribute("aggregation", "composite"); } if (link.getType().getDecor1() == LinkDecor.AGREGATION) { end2.setAttribute("aggregation", "aggregate"); } end2.appendChild(endparticipant2); connection.appendChild(end2); association.appendChild(connection); this.ownedElementRoot.appendChild(association); } else { this.addExtension(link, assId); } } } // copy from XmiClassDiagramStar private void addExtension(Link link, String assId) { Element association = this.document.createElement("UML:Generalization"); association.setAttribute("xmi.id", assId); association.setAttribute("namespace", CucaDiagramXmiMaker.getModel(this.classDiagram)); if (link.getLabel() != null) { association.setAttribute("name", this.forXMI(link.getLabel())); } if (link.getType().getDecor1() == LinkDecor.EXTENDS) { association.setAttribute("child", link.getEntity1().getUid()); association.setAttribute("parent", link.getEntity2().getUid()); } else { if (link.getType().getDecor2() != LinkDecor.EXTENDS) { throw new IllegalStateException(); } association.setAttribute("child", link.getEntity2().getUid()); association.setAttribute("parent", link.getEntity1().getUid()); } this.ownedElementRoot.appendChild(association); } }
添加导出类(入口)
添加package org.export
,并添加类UML2XMIExporter
:
package org.export; import net.sourceforge.plantuml.SourceStringReader; import net.sourceforge.plantuml.classdiagram.ClassDiagram; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Paths; import net.sourceforge.plantuml.xmi.XmiClassDiagramCustom; import net.sourceforge.plantuml.xmi.XmlDiagramTransformer; public class UML2XMIExporter { public static void main(String[] args) throws IOException, ParserConfigurationException, TransformerException { String content = new String(Files.readAllBytes(Paths.get(args[0]))); OutputStream outputCustom = Files.newOutputStream(Paths.get(args[1])); SourceStringReader reader = new SourceStringReader(content); ClassDiagram classDiagram = (ClassDiagram) reader.getBlocks().get(0).getDiagram(); // 导出XMI XmlDiagramTransformer xmi = new XmiClassDiagramCustom(classDiagram); xmi.transformerXml(outputCustom); } }
打包
接下来,参考 https://blog.csdn.net/weixin_41229430/article/details/138963215 打包为jar包
创建文件: src/main/assembly/assembly.xml, 内容如下:
<assembly> <id>assembly</id> <formats> <format>zip</format> <format>jar</format> <format>tar.gz</format> </formats> <includeBaseDirectory>false</includeBaseDirectory> <fileSets> <!-- --> <fileSet> <directory>src/main/resources</directory> <outputDirectory>conf</outputDirectory> <includes> <include>*.xml</include> <include>*.properties</include> <include>**/*.xml</include> <include>**/*.properties</include> </includes> <fileMode>0644</fileMode> </fileSet> <fileSet> <directory>assembly/bin</directory> <outputDirectory>bin</outputDirectory> <fileMode>0755</fileMode> </fileSet> </fileSets> <dependencySets> <dependencySet> <outputDirectory>lib</outputDirectory> </dependencySet> </dependencySets> </assembly>
然后在pom.xml中添加
<build> <plugins> <!--主要用于将 Maven 项目打包成可执行的程序或分发包 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>3.3.0</version> <executions> <execution> <id>make-assembly2</id><!--名字任意 --> <phase>package</phase><!-- 绑定到package生命周期阶段上 --> <goals> <goal>single</goal><!-- 只运行一次 --> </goals> <configuration> <descriptors> <descriptor>${basedir}/src/main/assembly/assembly.xml</descriptor> </descriptors> <archive> <manifest> <mainClass>org.export.UML2XMIExporter</mainClass> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> <useUniqueVersions>false</useUniqueVersions> </manifest> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build>
点击IDEA右侧的m图标(maven),双击Lifecycle下的package。然后在target目录下可以看到已经生成了jar包。
打开command prompt命令行(不要使用powershell)运行:
java -Dfile.encoding=UTF-8 -jar custom-plantuml-xmi-export-1.0-SNAPSHOT-jar-with-dependencies.jar input.puml output.xmi