diff --git a/src/main/java/kieker/analysis/graph/GraphTester.java b/src/main/java/kieker/analysis/graph/GraphTester.java
index 91a804922c3d8a61807f0a664a17d11ae11ed115..04871d1a860eda5bdb3396e256bbfc6f93b4d7cd 100644
--- a/src/main/java/kieker/analysis/graph/GraphTester.java
+++ b/src/main/java/kieker/analysis/graph/GraphTester.java
@@ -4,7 +4,6 @@ import java.io.OutputStreamWriter;
 import java.util.ArrayList;
 
 import kieker.analysis.graph.export.dot.DotExporter;
-import kieker.analysis.graph.export.graphml.GraphMLExporter;
 import kieker.analysis.graph.impl.GraphImpl;
 
 public class GraphTester {
@@ -96,14 +95,11 @@ public class GraphTester {
 			vertex.setProperty("xyzprop", new ArrayList<Boolean>());
 		}
 
-		GraphMLExporter graphMLExporter = new GraphMLExporter();
-		graphMLExporter.export(graph, System.out);
-
 		DotExporter dotWriter = new DotExporter(graph, new OutputStreamWriter(System.out));
 		dotWriter.transform();
 
-		// DotExporter dotExporter = new DotExporter();
-		// dotExporter.export(graph, System.out);
+		DotExporter dotExporter = new DotExporter(graph, new OutputStreamWriter(System.out));
+		dotExporter.transform();
 
 		// Could be useful for testing
 		//
diff --git a/src/main/java/kieker/analysis/graph/export/blueprints/BlueprintsTransformerStage.java b/src/main/java/kieker/analysis/graph/export/blueprints/BlueprintsTransformerStage.java
index 4c0b434cce04d927f8c9d3237c1c7ce9a0ddcfb7..63d57f0627e7c9c203c38dbae091912e60c7e3cb 100644
--- a/src/main/java/kieker/analysis/graph/export/blueprints/BlueprintsTransformerStage.java
+++ b/src/main/java/kieker/analysis/graph/export/blueprints/BlueprintsTransformerStage.java
@@ -6,10 +6,6 @@ import teetime.stage.basic.AbstractTransformation;
 
 public class BlueprintsTransformerStage extends AbstractTransformation<Graph, com.tinkerpop.blueprints.Graph> {
 
-	public BlueprintsTransformerStage() {
-		super();
-	}
-
 	@Override
 	protected void execute(final Graph graph) {
 		BlueprintsTransformer transformer = new BlueprintsTransformer(graph);
diff --git a/src/main/java/kieker/analysis/graph/export/graphml/GraphMLExporter.java b/src/main/java/kieker/analysis/graph/export/graphml/GraphMLExporter.java
deleted file mode 100644
index 2e121c011cec9cc8ec0f35004085fc338845b782..0000000000000000000000000000000000000000
--- a/src/main/java/kieker/analysis/graph/export/graphml/GraphMLExporter.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package kieker.analysis.graph.export.graphml;
-
-import java.io.OutputStream;
-
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Marshaller;
-
-import org.graphdrawing.graphml.GraphType;
-import org.graphdrawing.graphml.GraphmlType;
-import org.graphdrawing.graphml.ObjectFactory;
-
-import kieker.analysis.graph.Graph;
-
-//TODO remove
-public class GraphMLExporter {
-
-	private static final Boolean FORMATTED_OUTPUT = Boolean.TRUE;
-
-	public void export(final Graph graph, final OutputStream outputStream) {
-
-		GraphmlType graphmlType = new GraphmlType();
-
-		GraphTypeTransformer graphTypeTransformer = new GraphTypeTransformer(graph);
-		GraphType graphType = graphTypeTransformer.transform();
-
-		graphmlType.getGraphOrData().add(graphType);
-
-		try {
-			ObjectFactory objectFactory = new ObjectFactory();
-			JAXBElement<GraphmlType> rootElement = objectFactory.createGraphml(graphmlType);
-
-			JAXBContext context = JAXBContext.newInstance(rootElement.getDeclaredType());
-			Marshaller marshaller = context.createMarshaller();
-			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, FORMATTED_OUTPUT);
-
-			marshaller.marshal(rootElement, outputStream);
-		} catch (JAXBException e) {
-			// TODO Auto-generated catch block
-			// TODO wrap exception
-			e.printStackTrace();
-		}
-
-	}
-
-}
diff --git a/src/main/java/kieker/analysis/graph/export/graphml/GraphMLFileWriterComposite.java b/src/main/java/kieker/analysis/graph/export/graphml/GraphMLFileWriterComposite.java
new file mode 100644
index 0000000000000000000000000000000000000000..e91e7e73c75c795c48cac39f19f38896f85ba3b2
--- /dev/null
+++ b/src/main/java/kieker/analysis/graph/export/graphml/GraphMLFileWriterComposite.java
@@ -0,0 +1,25 @@
+package kieker.analysis.graph.export.graphml;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+
+import kieker.analysis.graph.Graph;
+import kieker.analysis.graph.mapping.GraphMapper;
+
+public class GraphMLFileWriterComposite extends GraphMLWriterComposite {
+
+	public GraphMLFileWriterComposite(final GraphMapper<String> fileNameMapper) {
+		super(new GraphMapper<OutputStream>() {
+			@Override
+			public OutputStream map(final Graph graph) {
+				try {
+					return new FileOutputStream(fileNameMapper.map(graph));
+				} catch (FileNotFoundException e) {
+					throw new IllegalArgumentException(e);
+				}
+			}
+		});
+	}
+
+}
diff --git a/src/main/java/kieker/analysis/graph/export/graphml/GraphMLTransformationStage.java b/src/main/java/kieker/analysis/graph/export/graphml/GraphMLTransformationStage.java
new file mode 100644
index 0000000000000000000000000000000000000000..539d9217ffce77329f26aa57798cd76d8dd38f80
--- /dev/null
+++ b/src/main/java/kieker/analysis/graph/export/graphml/GraphMLTransformationStage.java
@@ -0,0 +1,40 @@
+package kieker.analysis.graph.export.graphml;
+
+import java.io.OutputStream;
+
+import javax.xml.bind.JAXBElement;
+
+import org.graphdrawing.graphml.GraphmlType;
+import org.graphdrawing.graphml.ObjectFactory;
+
+import kieker.analysis.graph.Graph;
+import kieker.analysis.graph.mapping.GraphMapper;
+import kieker.analysis.util.JAXBMarshalElement;
+
+import teetime.stage.basic.AbstractTransformation;
+
+public class GraphMLTransformationStage extends AbstractTransformation<Graph, JAXBMarshalElement<GraphmlType>> {
+
+	private final ObjectFactory objectFactory = new ObjectFactory();
+	private final GraphMapper<OutputStream> outputStreamMapper;
+
+	public GraphMLTransformationStage(final GraphMapper<OutputStream> outputStreamMapper) {
+		this.outputStreamMapper = outputStreamMapper;
+	}
+
+	@Override
+	protected void execute(final Graph graph) {
+
+		final GraphTypeTransformer graphTypeTransformer = new GraphTypeTransformer(graph);
+		final GraphmlType graphmlType = new GraphmlType();
+		graphmlType.getGraphOrData().add(graphTypeTransformer.transform());
+		final JAXBElement<GraphmlType> jaxbElement = objectFactory.createGraphml(graphmlType);
+
+		final OutputStream outputStream = outputStreamMapper.map(graph);
+		final JAXBMarshalElement<GraphmlType> marshalElement = new JAXBMarshalElement<>(jaxbElement, outputStream);
+
+		this.getOutputPort().send(marshalElement);
+
+	}
+
+}
diff --git a/src/main/java/kieker/analysis/graph/export/graphml/GraphMLWriterComposite.java b/src/main/java/kieker/analysis/graph/export/graphml/GraphMLWriterComposite.java
new file mode 100644
index 0000000000000000000000000000000000000000..db75adf952baa2e3a87257be0db342dc44a4e1ae
--- /dev/null
+++ b/src/main/java/kieker/analysis/graph/export/graphml/GraphMLWriterComposite.java
@@ -0,0 +1,34 @@
+package kieker.analysis.graph.export.graphml;
+
+import java.io.OutputStream;
+
+import org.graphdrawing.graphml.GraphmlType;
+
+import kieker.analysis.graph.Graph;
+import kieker.analysis.graph.mapping.GraphMapper;
+import kieker.analysis.util.JAXBMarshalStage;
+
+import teetime.framework.CompositeStage;
+import teetime.framework.InputPort;
+
+public class GraphMLWriterComposite extends CompositeStage {
+
+	private final InputPort<Graph> inputPort;
+
+	public GraphMLWriterComposite(final GraphMapper<OutputStream> outputStreamMapper) {
+		final GraphMLTransformationStage graphTypeTransformer;
+		final JAXBMarshalStage<GraphmlType> jaxbMarshaller;
+
+		graphTypeTransformer = new GraphMLTransformationStage(outputStreamMapper);
+		jaxbMarshaller = new JAXBMarshalStage<GraphmlType>(GraphmlType.class);
+
+		this.inputPort = graphTypeTransformer.getInputPort();
+
+		super.connectPorts(graphTypeTransformer.getOutputPort(), jaxbMarshaller.getInputPort());
+	}
+
+	public InputPort<Graph> getInputPort() {
+		return this.inputPort;
+	}
+
+}
diff --git a/src/main/java/kieker/analysis/graph/mapping/GraphMapper.java b/src/main/java/kieker/analysis/graph/mapping/GraphMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..7b874af38e14bba89edd66e16412c3505c7d87fc
--- /dev/null
+++ b/src/main/java/kieker/analysis/graph/mapping/GraphMapper.java
@@ -0,0 +1,8 @@
+package kieker.analysis.graph.mapping;
+
+import kieker.analysis.graph.Graph;
+import kieker.analysis.graph.util.IMapper;
+
+public interface GraphMapper<O> extends IMapper<Graph, O> {
+
+}
diff --git a/src/main/java/kieker/analysis/graph/util/IMapper.java b/src/main/java/kieker/analysis/graph/util/IMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..fdfd9108b018951b7318a7eefb1fdb8716ee6f48
--- /dev/null
+++ b/src/main/java/kieker/analysis/graph/util/IMapper.java
@@ -0,0 +1,7 @@
+package kieker.analysis.graph.util;
+
+public interface IMapper<I, O> {
+
+	public O map(I object);
+
+}
diff --git a/src/main/java/kieker/analysis/util/JAXBMarshalElement.java b/src/main/java/kieker/analysis/util/JAXBMarshalElement.java
new file mode 100644
index 0000000000000000000000000000000000000000..7b5b88c28d202f197a8de0188b76ea93eba86ee7
--- /dev/null
+++ b/src/main/java/kieker/analysis/util/JAXBMarshalElement.java
@@ -0,0 +1,34 @@
+package kieker.analysis.util;
+
+import java.io.OutputStream;
+
+import javax.xml.bind.JAXBElement;
+
+public class JAXBMarshalElement<T> {
+
+	private JAXBElement<T> element;
+
+	private OutputStream outputStream;
+
+	public JAXBMarshalElement(final JAXBElement<T> element, final OutputStream outputStream) {
+		this.element = element;
+		this.outputStream = outputStream;
+	}
+
+	public JAXBElement<T> getElement() {
+		return element;
+	}
+
+	public void setElement(final JAXBElement<T> element) {
+		this.element = element;
+	}
+
+	public OutputStream getOutputStream() {
+		return outputStream;
+	}
+
+	public void setOutputStream(final OutputStream outputStream) {
+		this.outputStream = outputStream;
+	}
+
+}
diff --git a/src/main/java/kieker/analysis/util/JAXBMarshalStage.java b/src/main/java/kieker/analysis/util/JAXBMarshalStage.java
index 7f6997b9517b117bd4220bc4f794c721bb47277d..cf97904b89e2995abc1d4548028ac17e402f4e0f 100644
--- a/src/main/java/kieker/analysis/util/JAXBMarshalStage.java
+++ b/src/main/java/kieker/analysis/util/JAXBMarshalStage.java
@@ -1,7 +1,5 @@
 package kieker.analysis.util;
 
-import java.io.OutputStream;
-
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.Marshaller;
@@ -12,33 +10,26 @@ import teetime.framework.AbstractConsumerStage;
  * This stage marshals the content tree rooted at an incoming element into an
  * output stream.
  *
- * A class object has to be passed at creation. Only elements of this type or
- * elements of this type wrapped in a {@code JAXBElement} could be marshaled.
- *
- * Incoming elements have to be an instance of {@code JAXBElement} or are
- * annotated with {@code @XmlRootElement}.
+ * A class object has to be passed at creation. Only elements of this type
+ * wrapped in a {@code JAXBElement} could be marshaled.
  *
- * Marshaling with this stage is faster than using
- * {@link UniversalJAXBMarshalStage}. So It should be used if the type of the
- * incoming elements is known.
+ * Incoming elements must be {@code JAXBMarshalElement} which stores the
+ * {@code JAXBElement} and an output stream.
  *
  * @author Sören Henning
  *
  */
-public class JAXBMarshalStage extends AbstractConsumerStage<Object> {
+public class JAXBMarshalStage<T> extends AbstractConsumerStage<JAXBMarshalElement<T>> {
 
 	private static final Boolean FORMATTED_OUTPUT_DEFAULT = Boolean.TRUE;
 
 	private final Marshaller marshaller;
-	private final OutputStream outputStream;
 
-	public JAXBMarshalStage(final Class<?> elementsClass, final OutputStream outputStream) {
-		this(elementsClass, outputStream, FORMATTED_OUTPUT_DEFAULT);
+	public JAXBMarshalStage(final Class<T> elementsClass) {
+		this(elementsClass, FORMATTED_OUTPUT_DEFAULT);
 	}
 
-	public JAXBMarshalStage(final Class<?> elementsClass, final OutputStream outputStream, final Boolean formattedOutput) {
-		this.outputStream = outputStream;
-
+	public JAXBMarshalStage(final Class<T> elementsClass, final Boolean formattedOutput) {
 		try {
 			this.marshaller = JAXBContext.newInstance(elementsClass).createMarshaller();
 			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, formattedOutput);
@@ -49,10 +40,9 @@ public class JAXBMarshalStage extends AbstractConsumerStage<Object> {
 	}
 
 	@Override
-	protected void execute(final Object element) {
-
+	protected void execute(final JAXBMarshalElement<T> element) {
 		try {
-			marshaller.marshal(element, outputStream);
+			marshaller.marshal(element.getElement(), element.getOutputStream());
 		} catch (JAXBException e) {
 			// TODO Exception
 			throw new IllegalStateException("The received element could not be marshalled.", e);
diff --git a/src/main/java/kieker/analysis/util/UniversalJAXBMarshalStage.java b/src/main/java/kieker/analysis/util/UniversalJAXBMarshalStage.java
deleted file mode 100644
index b08db05601941a09fcaa525d1cfdd65b55d23110..0000000000000000000000000000000000000000
--- a/src/main/java/kieker/analysis/util/UniversalJAXBMarshalStage.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package kieker.analysis.util;
-
-import java.io.OutputStream;
-
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Marshaller;
-
-import teetime.framework.AbstractConsumerStage;
-
-/**
- * This stage marshals the content tree rooted at an incoming element into an
- * output stream.
- *
- * Incoming elements have to be an instance of {@code JAXBElement} or are
- * annotated with {@code @XmlRootElement}.
- *
- * {@link JAXBMarshalStage} should be preferred if all incoming elements have
- * the same type and the type is known, because {@link JAXBMarshalStage} is
- * faster.
- *
- * @author Sören Henning
- *
- */
-public class UniversalJAXBMarshalStage extends AbstractConsumerStage<Object> {
-
-	private static final Boolean FORMATTED_OUTPUT_DEFAULT = Boolean.TRUE;
-
-	private final OutputStream outputStream;
-	private final Boolean formattedOutput;
-
-	public UniversalJAXBMarshalStage(final OutputStream outputStream) {
-		this(outputStream, FORMATTED_OUTPUT_DEFAULT);
-	}
-
-	public UniversalJAXBMarshalStage(final OutputStream outputStream, final Boolean formattedOutput) {
-		this.outputStream = outputStream;
-		this.formattedOutput = formattedOutput;
-	}
-
-	@Override
-	protected void execute(final Object element) {
-
-		// Determine whether the incoming object is wrapped in a JAXBElement
-		Class<?> elementClass;
-		if (element instanceof JAXBElement) {
-			elementClass = ((JAXBElement<?>) element).getDeclaredType();
-		} else {
-			elementClass = element.getClass();
-		}
-
-		try {
-			final Marshaller marshaller = JAXBContext.newInstance(elementClass).createMarshaller();
-			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, formattedOutput);
-			marshaller.marshal(element, outputStream);
-		} catch (JAXBException e) {
-			// TODO Exception
-			throw new IllegalStateException("The received element could not be marshalled.", e);
-		}
-
-	}
-
-}