Generating a graph from your C4 source files and exporting it as GraphML

Using the report goal will gather the information contained in your C4 source files and aggregate them into a graph, that will be exported as a GraphML file.

The generated file follows the GraphML standard, but does not hold any graphical information (such as nodes positions, etc.) as you are already doing this when generating your diagrams!

The purpose of all of this is to allow other programs that are not aware of the C4 PlantUML grammar to process the data contained in your graphs easily, to generate other files, reports, documentation and even import that data into your enterprise architecture repository.

Below are some examples of configurations with explanations. You can find more about the report goal on the report goal page.

An example of such generated GraphML file would be:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.1/graphml.xsd">
    <key attr.name="aspect" attr.type="string" for="graph" id="attr00"/>
    <key attr.name="c4_level" attr.type="string" for="edge" id="attr01"/>
    <key attr.name="description" attr.type="string" for="node" id="attr02"/>
    <key attr.name="entity_type" attr.type="string" for="node" id="attr03"/>
    <key attr.name="label" attr.type="string" for="edge" id="attr05"/>
    <key attr.name="name" attr.type="string" for="node" id="attr06"/>
    <key attr.name="protocol" attr.type="string" for="edge" id="attr07"/>
    <key attr.name="technological_stack" attr.type="string" for="node" id="attr08"/>
    <key attr.name="title" attr.type="string" for="graph" id="attr09"/>
    <graph edgedefault="directed" id="c4l1">
        <data key="attr09"><![CDATA[Some test title]]></data>
        <node id="c4l1::person">
            <data key="attr06"><![CDATA[Person name]]></data>
            <data key="attr02"><![CDATA[Person description]]></data>
            <data key="attr03"><![CDATA[Person]]></data>
        </node>
        <node id="c4l1::system">
            <data key="attr06"><![CDATA[System name]]></data>
            <data key="attr02"><![CDATA[System description]]></data>
            <data key="attr03"><![CDATA[System]]></data>
        </node>
        <edge id="c4l1__person__system__C4_L1__e9dbe2f07feec62742572f8afb955bb44359d6a2f3c8677add4fb32b11a7750a" source="c4l1::person" target="c4l1::system">
            <data key="attr01"><![CDATA[C4_L1]]></data>
            <data key="attr05"><![CDATA[Uses the system]]></data>
        </edge>
    </graph>
    <graph edgedefault="directed" id="c4l2">
        <data key="attr09"><![CDATA[Some test title]]></data>
        <node id="c4l2::person">
            <data key="attr06"><![CDATA[Person name]]></data>
            <data key="attr02"><![CDATA[Person description]]></data>
            <data key="attr03"><![CDATA[Person]]></data>
        </node>
        <node id="c4l2::system">
            <graph edgedefault="directed" id="c4l2::system:">
                <data key="attr09"><![CDATA[System name]]></data>
                <node id="c4l2::system::container1">
                    <data key="attr06"><![CDATA[Container name]]></data>
                    <data key="attr02"><![CDATA[Container description]]></data>
                    <data key="attr03"><![CDATA[Container]]></data>
                    <data key="attr08"><![CDATA[container stack]]></data>
                </node>
                <node id="c4l2::system::container2">
                    <data key="attr06"><![CDATA[Container name 2]]></data>
                    <data key="attr02"><![CDATA[Container description 2]]></data>
                    <data key="attr03"><![CDATA[ContainerDb]]></data>
                    <data key="attr08"><![CDATA[container stack 2]]></data>
                </node>
            </graph>
        </node>
        <node id="c4l2::systemExt">
            <data key="attr06"><![CDATA[System ext name]]></data>
            <data key="attr02"><![CDATA[System ext description]]></data>
            <data key="attr03"><![CDATA[SystemExt]]></data>
        </node>
        <edge id="c4l2__c4l2::person__c4l2::system__C4_L2__e9dbe2f07feec62742572f8afb955bb44359d6a2f3c8677add4fb32b11a7750a" source="c4l2::person" target="c4l2::system">
            <data key="attr01"><![CDATA[C4_L2]]></data>
            <data key="attr05"><![CDATA[Uses the system]]></data>
        </edge>
        <edge id="c4l2__c4l2::system::container2__c4l2::systemExt__C4_L2__6e0d190c847ecfe3c49229dcfd9caa90444cb1565c1459b736142822a647f963" source="c4l2::system::container2" target="c4l2::systemExt">
            <data key="attr01"><![CDATA[C4_L2]]></data>
            <data key="attr05"><![CDATA[Description]]></data>
            <data key="attr07"><![CDATA[protocol]]></data>
        </edge>
    </graph>
</graphml>

Let’s start with the given directory structure:

.
├── pom.xml
└── src
    └── main
        └── resources
            ├── c4l1_test.puml
            └── c4l2_test.puml

Basic usage

The following configuration snippet will parse every .puml file found in the project.build.outputDirectory, and output a GraphML file named c4graph.graphml to the project.build.outputDirectory:

<build>
    <plugins>
        <plugin>
            <groupId>org.thewonderlemming.c4plantuml</groupId>
            <artifactId>c4plantuml-maven-plugin</artifactId>
            <version>1.0.0-RC1</version>
            <executions>
                <execution>
                    <id>reporting-c4-files</id>
                    <goals>
                        <goal>report</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

After the execution, your directory will look like:

.
├── pom.xml
├── src
│   └── main
│       └── resources
│           ├── c4l1_test.puml
│           └── c4l2_test.puml
└── target
    └── classes
        ├── c4graph.graphml
        ├── c4l1_test.puml
        └── c4l2_test.puml

Failing the build on parsing errors

The following configuration snippet will parse every .puml file found in the project.build.outputDirectory, fail the build if any parsing error occurs:

<build>
    <plugins>
        <plugin>
            <groupId>org.thewonderlemming.c4plantuml</groupId>
            <artifactId>c4plantuml-maven-plugin</artifactId>
            <version>1.0.0-RC1</version>
            <executions>
                <execution>
                    <id>reporting-c4-files</id>
                    <goals>
                        <goal>report</goal>
                    </goals>
                    <configuration>
                        <failOnParseErrors>true</failOnParseErrors>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

If one of our C4 file has any syntax error, then the build will fail with the following messsage:

[ERROR] Parse error in file '/path/to/my/project/target/classes/c4l1_has_invalid_syntax.puml': [@1,11:11='!',<22>,3:0]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------

Using a custom filename extension for C4 source files

The following configuration snippet will parse every .c4 file found in the project.build.outputDirectory, and output a GraphML file named c4graph.graphml to the project.build.outputDirectory. It will ignore any .puml file:

<build>
    <plugins>
        <plugin>
            <groupId>org.thewonderlemming.c4plantuml</groupId>
            <artifactId>c4plantuml-maven-plugin</artifactId>
            <version>1.0.0-RC1</version>
            <executions>
                <execution>
                    <id>reporting-c4-files</id>
                    <goals>
                        <goal>report</goal>
                    </goals>
                    <configuration>
                        <sourceFileExtension>.c4</sourceFileExtension>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

After the execution, your directory will look like:

.
├── pom.xml
├── src
│   └── main
│       └── resources
│           └── c4l1_test.c4
└── target
    └── classes
        ├── c4graph.graphml
        └── c4l1_test.c4

Removing output formatting in the generated GraphML file

The following configuration snippet will remove any formatting from the generated GraphML file:

<build>
    <plugins>
        <plugin>
            <groupId>org.thewonderlemming.c4plantuml</groupId>
            <artifactId>c4plantuml-maven-plugin</artifactId>
            <version>1.0.0-RC1</version>
            <executions>
                <execution>
                    <id>reporting-c4-files</id>
                    <goals>
                        <goal>report</goal>
                    </goals>
                    <configuration>
                        <formatOutput>false</formatOutput>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Now, the generated GraphML file could look like:

<?xml version="1.0" encoding="UTF-8" standalone="no"?><graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.1/graphml.xsd"><key attr.name="aspect" attr.type="string" for="graph" id="attr00"/><key attr.name="c4_level" attr.type="string" for="edge" id="attr01"/><key attr.name="description" attr.type="string" for="node" id="attr02"/><key attr.name="entity_type" attr.type="string" for="node" id="attr03"/><key attr.name="label" attr.type="string" for="edge" id="attr05"/><key attr.name="name" attr.type="string" for="node" id="attr06"/><key attr.name="protocol" attr.type="string" for="edge" id="attr07"/><key attr.name="technological_stack" attr.type="string" for="node" id="attr08"/><key attr.name="title" attr.type="string" for="graph" id="attr09"/><graph edgedefault="directed" id="c4l1"><data key="attr09"><![CDATA[Some test title]]></data><data key="attr00"><![CDATA[Some aspect]]></data><node id="c4l1::personExt"><data key="attr06"><![CDATA[External person]]></data><data key="attr02"><![CDATA[External person description]]></data><data key="attr03"><![CDATA[PersonExt]]></data></node></graph></graphml>

It is only useful if you are dealing with huge XML files and want to reduce their size a bit.


Changing the GraphML filename

The following configuration snippet will change the name of the generated GraphML file:

<build>
    <plugins>
        <plugin>
            <groupId>org.thewonderlemming.c4plantuml</groupId>
            <artifactId>c4plantuml-maven-plugin</artifactId>
            <version>1.0.0-RC1</version>
            <executions>
                <execution>
                    <id>reporting-c4-files</id>
                    <goals>
                        <goal>report</goal>
                    </goals>
                    <configuration>
                        <outputFilename>report.graphml</outputFilename>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

After the execution, your directory will look like:

.
├── pom.xml
├── src
│   └── main
│       └── resources
│           └── c4l1_test.c4
└── target
    └── classes
        ├── report.graphml
        └── c4l1_test.c4