diff --git a/alib2data/src/graph/GraphFromStringLexer.cpp b/alib2data/src/graph/GraphFromStringLexer.cpp
index 422de855366b2c0ad0118e018f57a45140b9a9b7..9dc82b1abbb11015a8deead10a52e121de073aa5 100644
--- a/alib2data/src/graph/GraphFromStringLexer.cpp
+++ b/alib2data/src/graph/GraphFromStringLexer.cpp
@@ -39,12 +39,42 @@ L0:
 		token.value += character;
 		token.raw += character;
 		return token;
+	} else if (character == '=') {
+		token.type = TokenType::EQUAL;
+		token.value += character;
+		token.raw += character;
+		return token;
+	} else if (character >= '0' && character <= '9') {
+		token.type = TokenType::INTEGER;
+		token.value += character;
+		token.raw += character;
+		goto L1;
 	} else {
 		in.putback(character);
 		putback(in, std::move(token));
 		token.type = TokenType::ERROR;
 		return token;
 	}
+
+L1:
+	character = in.get();
+	if (in.eof()) {
+		return token;
+	} else if (character >= '0' && character <= '9') {
+		token.value += character;
+		token.raw += character;
+		goto L1;
+	} else {
+		in.unget();
+		return token;
+	}
+}
+
+GraphFromStringLexer::Token GraphFromStringLexer::peek(std::istream &in) const
+{
+	Token token = next(in);
+	putback(in, token);
+	return token;
 }
 
 void GraphFromStringLexer::putback(std::istream &input, GraphFromStringLexer::Token token) const
diff --git a/alib2data/src/graph/GraphFromStringLexer.h b/alib2data/src/graph/GraphFromStringLexer.h
index 5246f9795d2e160370a81108f49f0a78aad0f161..92e7d3f6da485b667b7312ddf98f1c30697d914a 100644
--- a/alib2data/src/graph/GraphFromStringLexer.h
+++ b/alib2data/src/graph/GraphFromStringLexer.h
@@ -14,6 +14,8 @@ public:
 		RPAR,
 		COLON,
 		COMMA,
+		EQUAL,
+		INTEGER,
 		TEOF,
 		ERROR
 	};
@@ -25,6 +27,7 @@ public:
 	};
 
 	Token next(std::istream &input) const;
+	Token peek(std::istream &input) const;
 	void putback(std::istream &input, Token token) const;
 
 	std::string getString(std::istream &input) const;
diff --git a/alib2data/src/graph/GraphFromStringParser.cpp b/alib2data/src/graph/GraphFromStringParser.cpp
index b7941294e43e60dea5c5c943a70ba2fae3acc164..c341ea9fb2c508b878eec443bf736d1a71a3f556 100644
--- a/alib2data/src/graph/GraphFromStringParser.cpp
+++ b/alib2data/src/graph/GraphFromStringParser.cpp
@@ -41,6 +41,10 @@ DirectedGraph GraphFromStringParser::parseDirectedGraph(std::istream &input) con
 	parseNodes(input, graph);
 	parseDelimiter(input); // :
 	parseDirectedEdges(input, graph);
+	parseDelimiter(input); // :
+	parseNodeValues(input, graph);
+	parseDelimiter(input); // :
+	parseDirectedEdgeValues(input, graph);
 	return graph;
 }
 
@@ -51,6 +55,10 @@ UndirectedGraph GraphFromStringParser::parseUndirectedGraph(std::istream &input)
 	parseNodes(input, graph);
 	parseDelimiter(input); // :
 	parseUndirectedEdges(input, graph);
+	parseDelimiter(input); // :
+	parseNodeValues(input, graph);
+	parseDelimiter(input); // :
+	parseUndirectedEdgeValues(input, graph);
 	return graph;
 }
 
@@ -116,7 +124,6 @@ void GraphFromStringParser::parseDirectedEdges(std::istream &input, DirectedGrap
 	}
 	lexer.putback(input, token);
 
-
 	while (true) {
 		graph.addEdge(parseDirectedEdge(input));
 
@@ -157,4 +164,86 @@ void GraphFromStringParser::parseDelimiter(std::istream &input) const
 	}
 }
 
+int GraphFromStringParser::parseValue(std::istream &input) const
+{
+	GraphFromStringLexer::Token token = lexer.next(input);
+	if (token.type != GraphFromStringLexer::TokenType::EQUAL) {
+		throw exception::AlibException("Invalid input. Expected EQUAL");
+	}
+
+	token = lexer.next(input);
+	if (token.type != GraphFromStringLexer::TokenType::INTEGER) {
+		throw exception::AlibException("Invalid input. Expected INTEGER");
+	}
+
+	return std::stoi(token.value);
+}
+
+template<typename T>
+void GraphFromStringParser::parseNodeValues(std::istream &input, T &graph) const
+{
+	GraphFromStringLexer::Token token = lexer.peek(input);
+
+	// Empty values?
+	if (token.type == GraphFromStringLexer::TokenType::COLON) {
+		return;
+	}
+
+	while (true) {
+		graph::Node node = parseNode(input);
+		int value = parseValue(input);
+		graph.setNodeValue(node, value);
+
+		token = lexer.next(input);
+		if (token.type != GraphFromStringLexer::TokenType::COMMA) {
+			lexer.putback(input, token);
+			return;
+		}
+	}
+}
+
+void GraphFromStringParser::parseDirectedEdgeValues(std::istream &input, DirectedGraph &graph) const
+{
+	GraphFromStringLexer::Token token = lexer.peek(input);
+
+	// Empty values?
+	if (token.type == GraphFromStringLexer::TokenType::RPAR) {
+		return;
+	}
+
+	while (true) {
+		graph::DirectedEdge node = parseDirectedEdge(input);
+		int value = parseValue(input);
+		graph.setEdgeValue(node, value);
+
+		token = lexer.next(input);
+		if (token.type != GraphFromStringLexer::TokenType::COMMA) {
+			lexer.putback(input, token);
+			return;
+		}
+	}
+}
+
+void GraphFromStringParser::parseUndirectedEdgeValues(std::istream &input, UndirectedGraph &graph) const
+{
+	GraphFromStringLexer::Token token = lexer.peek(input);
+
+	// Empty values?
+	if (token.type == GraphFromStringLexer::TokenType::RPAR) {
+		return;
+	}
+
+	while (true) {
+		graph::UndirectedEdge node = parseUndirectedEdge(input);
+		int value = parseValue(input);
+		graph.setEdgeValue(node, value);
+
+		token = lexer.next(input);
+		if (token.type != GraphFromStringLexer::TokenType::COMMA) {
+			lexer.putback(input, token);
+			return;
+		}
+	}
+}
+
 } // namespace graph
diff --git a/alib2data/src/graph/GraphFromStringParser.h b/alib2data/src/graph/GraphFromStringParser.h
index 48e979b143f146080c071a42e963c55eb3ad9924..379ac016f89adfa3b36f7987e184100b15641f4d 100644
--- a/alib2data/src/graph/GraphFromStringParser.h
+++ b/alib2data/src/graph/GraphFromStringParser.h
@@ -36,6 +36,12 @@ private:
 	void parseDirectedEdges(std::istream &input, DirectedGraph &graph) const;
 	void parseUndirectedEdges(std::istream &input, UndirectedGraph &graph) const;
 	void parseDelimiter(std::istream &input) const;
+	int parseValue(std::istream &input) const;
+
+	template<typename T>
+	void parseNodeValues(std::istream &input, T &graph) const;
+	void parseDirectedEdgeValues(std::istream &input, DirectedGraph &graph) const;
+	void parseUndirectedEdgeValues(std::istream &input, UndirectedGraph &graph) const;
 
 	GraphFromStringLexer lexer;
 
diff --git a/alib2data/src/graph/GraphFromXMLParser.cpp b/alib2data/src/graph/GraphFromXMLParser.cpp
index c3bc16786bf123b9362869903de62ce508a07852..cb35275417e9c27886c7251b7d60a76cb2c4efdd 100644
--- a/alib2data/src/graph/GraphFromXMLParser.cpp
+++ b/alib2data/src/graph/GraphFromXMLParser.cpp
@@ -32,6 +32,8 @@ DirectedGraph GraphFromXMLParser::parseDirectedGraph(std::list<sax::Token> &inpu
 	DirectedGraph graph(parseRepresentation(input));
 	parseNodes(input, graph);
 	parseDirectedEdges(input, graph);
+	parseNodeValues(input, graph);
+	parseDirectedEdgeValues(input, graph);
 
 	popToken(input, sax::Token::TokenType::END_ELEMENT, alib::Names::GRAPH_DIRECTED_GRAPH);
 	return graph;
@@ -44,6 +46,8 @@ UndirectedGraph GraphFromXMLParser::parseUndirectedGraph(std::list<sax::Token> &
 	UndirectedGraph graph(parseRepresentation(input));
 	parseNodes(input, graph);
 	parseUndirectedEdges(input, graph);
+	parseNodeValues(input, graph);
+	parseUndirectedEdgeValues(input, graph);
 
 	popToken(input, sax::Token::TokenType::END_ELEMENT, alib::Names::GRAPH_UNDIRECTED_GRAPH);
 	return graph;
@@ -105,6 +109,16 @@ UndirectedEdge GraphFromXMLParser::parseUndirectedEdge(std::list<sax::Token> &in
 	return UndirectedEdge(first, second, name);
 }
 
+int GraphFromXMLParser::parseValue(std::list<sax::Token> &input) const
+{
+	popToken(input, sax::Token::TokenType::START_ELEMENT, "value");
+
+	int value = std::stoi(popTokenData(input, sax::Token::TokenType::CHARACTER));
+
+	popToken(input, sax::Token::TokenType::END_ELEMENT, "value");
+	return value;
+}
+
 template<typename T>
 void GraphFromXMLParser::parseNodes(std::list<sax::Token> &input, T &graph) const
 {
@@ -139,5 +153,48 @@ void GraphFromXMLParser::parseUndirectedEdges(std::list<sax::Token> &input, Undi
 	popToken(input, sax::Token::TokenType::END_ELEMENT, "edges");
 }
 
+template<typename T>
+void GraphFromXMLParser::parseNodeValues(std::list<sax::Token> &input, T &graph) const
+{
+	popToken(input, sax::Token::TokenType::START_ELEMENT, "nodevalues");
+
+	while (isTokenType(input, sax::Token::TokenType::START_ELEMENT)) {
+		graph::Node node = parseNode(input);
+		int value = parseValue(input);
+
+		graph.setNodeValue(node, value);
+	}
+
+	popToken(input, sax::Token::TokenType::END_ELEMENT, "nodevalues");
+}
+
+void GraphFromXMLParser::parseDirectedEdgeValues(std::list<sax::Token> &input, DirectedGraph &graph) const
+{
+	popToken(input, sax::Token::TokenType::START_ELEMENT, "edgevalues");
+
+	while (isTokenType(input, sax::Token::TokenType::START_ELEMENT)) {
+		graph::DirectedEdge edge = parseDirectedEdge(input);
+		int value = parseValue(input);
+
+		graph.setEdgeValue(edge, value);
+	}
+
+	popToken(input, sax::Token::TokenType::END_ELEMENT, "edgevalues");
+}
+
+void GraphFromXMLParser::parseUndirectedEdgeValues(std::list<sax::Token> &input, UndirectedGraph &graph) const
+{
+	popToken(input, sax::Token::TokenType::START_ELEMENT, "edgevalues");
+
+	while (isTokenType(input, sax::Token::TokenType::START_ELEMENT)) {
+		graph::UndirectedEdge edge = parseUndirectedEdge(input);
+		int value = parseValue(input);
+
+		graph.setEdgeValue(edge, value);
+	}
+
+	popToken(input, sax::Token::TokenType::END_ELEMENT, "edgevalues");
+}
+
 } // namespace graph
 
diff --git a/alib2data/src/graph/GraphFromXMLParser.h b/alib2data/src/graph/GraphFromXMLParser.h
index 472dfc921cd65e18a6e5033da649e1e16d607219..6dff7588316f8e958f8666a078a1443de3b3f096 100644
--- a/alib2data/src/graph/GraphFromXMLParser.h
+++ b/alib2data/src/graph/GraphFromXMLParser.h
@@ -33,12 +33,18 @@ private:
 	Node parseNode(std::list<sax::Token> &input) const;
 	DirectedEdge parseDirectedEdge(std::list<sax::Token> &input) const;
 	UndirectedEdge parseUndirectedEdge(std::list<sax::Token> &input) const;
+	int parseValue(std::list<sax::Token> &input) const;
 
 	template<typename T>
 	void parseNodes(std::list<sax::Token> &input, T &graph) const;
 	void parseDirectedEdges(std::list<sax::Token> &input, DirectedGraph &graph) const;
 	void parseUndirectedEdges(std::list<sax::Token> &input, UndirectedGraph &graph) const;
 
+	template<typename T>
+	void parseNodeValues(std::list<sax::Token> &input, T &graph) const;
+	void parseDirectedEdgeValues(std::list<sax::Token> &input, DirectedGraph &graph) const;
+	void parseUndirectedEdgeValues(std::list<sax::Token> &input, UndirectedGraph &graph) const;
+
 	template<typename T> friend class alib::xmlApi;
 };
 
diff --git a/alib2data/src/graph/GraphToStringComposer.cpp b/alib2data/src/graph/GraphToStringComposer.cpp
index 226da7fd5588e2b1046e09b4e29475c477465270..83ffdb679ea0f759c01c8c9593f57034fc2d5cbe 100644
--- a/alib2data/src/graph/GraphToStringComposer.cpp
+++ b/alib2data/src/graph/GraphToStringComposer.cpp
@@ -22,6 +22,10 @@ void GraphToStringComposer::Visit(void *data, const DirectedGraph &graph) const
 	composeNodes(out, graph.getNodes());
 	out << ":";
 	composeDirectedEdges(out, graph.getEdges());
+	out << ":";
+	composeNodeValues(out, graph);
+	out << ":";
+	composeEdgeValues(out, graph);
 }
 
 void GraphToStringComposer::Visit(void *data, const UndirectedGraph &graph) const
@@ -34,6 +38,10 @@ void GraphToStringComposer::Visit(void *data, const UndirectedGraph &graph) cons
 	composeNodes(out, graph.getNodes());
 	out << ":";
 	composeUndirectedEdges(out, graph.getEdges());
+	out << ":";
+	composeNodeValues(out, graph);
+	out << ":";
+	composeEdgeValues(out, graph);
 }
 
 void GraphToStringComposer::Visit(void *data, const Node &node) const
@@ -108,4 +116,36 @@ void GraphToStringComposer::composeUndirectedEdges(std::ostream &out, const std:
 	}
 }
 
+template<typename T>
+void GraphToStringComposer::composeNodeValues(std::ostream &out, const T &graph) const
+{
+	bool first = true;
+
+	for (auto i : graph.nodeValues) {
+		if (first) {
+			first = false;
+		} else {
+			out << ",";
+		}
+		i.first.Accept(static_cast<void*>(&out), *this);
+		out << "=" << i.second;
+	}
+}
+
+template<typename T>
+void GraphToStringComposer::composeEdgeValues(std::ostream &out, const T &graph) const
+{
+	bool first = true;
+
+	for (auto i : graph.edgeValues) {
+		if (first) {
+			first = false;
+		} else {
+			out << ",";
+		}
+		i.first.Accept(static_cast<void*>(&out), *this);
+		out << "=" << i.second;
+	}
+}
+
 } // namespace graph
diff --git a/alib2data/src/graph/GraphToStringComposer.h b/alib2data/src/graph/GraphToStringComposer.h
index 6a7c211b9917dcb353ba4f7db1b4727e7c71df25..54ecda9ddcefb01f28f7079bb143b166ad2c904c 100644
--- a/alib2data/src/graph/GraphToStringComposer.h
+++ b/alib2data/src/graph/GraphToStringComposer.h
@@ -31,6 +31,12 @@ private:
 	void composeNodes(std::ostream &out, const std::set<Node> &nodes) const;
 	void composeDirectedEdges(std::ostream &out, const std::set<DirectedEdge> &edges) const;
 	void composeUndirectedEdges(std::ostream &out, const std::set<UndirectedEdge> &edges) const;
+
+	template<typename T>
+	void composeNodeValues(std::ostream &out, const T &graph) const;
+	template<typename T>
+	void composeEdgeValues(std::ostream &out, const T &graph) const;
+
 };
 
 } // namespace graph
diff --git a/alib2data/src/graph/GraphToXMLComposer.cpp b/alib2data/src/graph/GraphToXMLComposer.cpp
index 5421105b43c6ec6dfa1b687df465e46a8979ccae..47b8bcde2dfd3c2ad302508e56aa7ef6d50411ed 100644
--- a/alib2data/src/graph/GraphToXMLComposer.cpp
+++ b/alib2data/src/graph/GraphToXMLComposer.cpp
@@ -2,6 +2,7 @@
 #include "GraphRepresentation.h"
 
 #include "../XmlApi.hpp"
+#include "../std/itos.h"
 
 namespace graph {
 
@@ -68,7 +69,9 @@ void GraphToXMLComposer::compose(std::list<sax::Token> &out, const DirectedGraph
 
 	composeRepresentation(out, representationToString(graph.getRepresentation()));
 	composeNodes(out, graph.getNodes());
-	composeDirectedEdges(out, graph.getEdges());
+	composeEdges(out, graph.getEdges());
+	composeNodeValues(out, graph);
+	composeEdgeValues(out, graph);
 
 	out.push_back(sax::Token(alib::Names::GRAPH_DIRECTED_GRAPH, sax::Token::TokenType::END_ELEMENT));
 }
@@ -79,7 +82,9 @@ void GraphToXMLComposer::compose(std::list<sax::Token> &out, const UndirectedGra
 
 	composeRepresentation(out, representationToString(graph.getRepresentation()));
 	composeNodes(out, graph.getNodes());
-	composeUndirectedEdges(out, graph.getEdges());
+	composeEdges(out, graph.getEdges());
+	composeNodeValues(out, graph);
+	composeEdgeValues(out, graph);
 
 	out.push_back(sax::Token(alib::Names::GRAPH_UNDIRECTED_GRAPH, sax::Token::TokenType::END_ELEMENT));
 }
@@ -100,22 +105,40 @@ void GraphToXMLComposer::composeNodes(std::list<sax::Token> &out, const std::set
 	out.push_back(sax::Token("nodes", sax::Token::TokenType::END_ELEMENT));
 }
 
-void GraphToXMLComposer::composeDirectedEdges(std::list<sax::Token> &out, const std::set<DirectedEdge> &edges) const
+template<typename T>
+void GraphToXMLComposer::composeEdges(std::list<sax::Token> &out, const std::set<T> &edges) const
 {
 	out.push_back(sax::Token("edges", sax::Token::TokenType::START_ELEMENT));
-	for (const DirectedEdge &edge : edges) {
+	for (const auto &edge : edges) {
 		edge.Accept(static_cast<void*>(&out), *this);
 	}
 	out.push_back(sax::Token("edges", sax::Token::TokenType::END_ELEMENT));
 }
 
-void GraphToXMLComposer::composeUndirectedEdges(std::list<sax::Token> &out, const std::set<UndirectedEdge> &edges) const
+template<typename T>
+void GraphToXMLComposer::composeNodeValues(std::list<sax::Token> &out, const T &graph) const
 {
-	out.push_back(sax::Token("edges", sax::Token::TokenType::START_ELEMENT));
-	for (const UndirectedEdge &edge : edges) {
-		edge.Accept(static_cast<void*>(&out), *this);
+	out.push_back(sax::Token("nodevalues", sax::Token::TokenType::START_ELEMENT));
+	for (auto i : graph.nodeValues) {
+		i.first.Accept(static_cast<void*>(&out), *this);
+		out.push_back(sax::Token("value", sax::Token::TokenType::START_ELEMENT));
+		out.push_back(sax::Token(std::itos(i.second), sax::Token::TokenType::CHARACTER));
+		out.push_back(sax::Token("value", sax::Token::TokenType::END_ELEMENT));
 	}
-	out.push_back(sax::Token("edges", sax::Token::TokenType::END_ELEMENT));
+	out.push_back(sax::Token("nodevalues", sax::Token::TokenType::END_ELEMENT));
+}
+
+template<typename T>
+void GraphToXMLComposer::composeEdgeValues(std::list<sax::Token> &out, const T &graph) const
+{
+	out.push_back(sax::Token("edgevalues", sax::Token::TokenType::START_ELEMENT));
+	for (auto &i : graph.edgeValues) {
+		i.first.Accept(static_cast<void*>(&out), *this);
+		out.push_back(sax::Token("value", sax::Token::TokenType::START_ELEMENT));
+		out.push_back(sax::Token(std::itos(i.second), sax::Token::TokenType::CHARACTER));
+		out.push_back(sax::Token("value", sax::Token::TokenType::END_ELEMENT));
+	}
+	out.push_back(sax::Token("edgevalues", sax::Token::TokenType::END_ELEMENT));
 }
 
 } // namespace graph
diff --git a/alib2data/src/graph/GraphToXMLComposer.h b/alib2data/src/graph/GraphToXMLComposer.h
index 0fd0e1d8c543cf03d26e6453f9385d1ea94786d6..79bd1df88259d41893bb7bb211d87c9662de1742 100644
--- a/alib2data/src/graph/GraphToXMLComposer.h
+++ b/alib2data/src/graph/GraphToXMLComposer.h
@@ -35,8 +35,14 @@ private:
 
 	void composeRepresentation(std::list<sax::Token> &out, const std::string &representation) const;
 	void composeNodes(std::list<sax::Token> &out, const std::set<Node> &nodes) const;
-	void composeDirectedEdges(std::list<sax::Token> &out, const std::set<DirectedEdge> &edges) const;
-	void composeUndirectedEdges(std::list<sax::Token> &out, const std::set<UndirectedEdge> &edges) const;
+
+	template<typename T>
+	void composeEdges(std::list<sax::Token> &out, const std::set<T> &edges) const;
+
+	template<typename T>
+	void composeNodeValues(std::list<sax::Token> &out, const T &graph) const;
+	template<typename T>
+	void composeEdgeValues(std::list<sax::Token> &out, const T &graph) const;
 
 	template<typename T> friend class alib::xmlApi;
 };
diff --git a/alib2data/src/graph/directed/DirectedGraph.cpp b/alib2data/src/graph/directed/DirectedGraph.cpp
index af07c466a6cbfb4c6262b7ce46d4c61744b2ebd5..c7b2349c384ab2a5463068e2a338c6224de40ba2 100644
--- a/alib2data/src/graph/directed/DirectedGraph.cpp
+++ b/alib2data/src/graph/directed/DirectedGraph.cpp
@@ -23,6 +23,8 @@ DirectedGraph::~DirectedGraph() noexcept
 
 DirectedGraph::DirectedGraph(const DirectedGraph &other)
 	: representation(other.representation)
+	, nodeValues(other.nodeValues)
+	, edgeValues(other.edgeValues)
 {
 	init();
 	impl->copy(other.impl);
@@ -31,6 +33,8 @@ DirectedGraph::DirectedGraph(const DirectedGraph &other)
 DirectedGraph::DirectedGraph(DirectedGraph &&other) noexcept
 	: representation(other.representation)
 	, impl(other.impl)
+	, nodeValues(std::move(other.nodeValues))
+	, edgeValues(std::move(other.edgeValues))
 {
 	other.impl = 0;
 }
@@ -49,6 +53,8 @@ DirectedGraph &DirectedGraph::operator=(DirectedGraph &&other) noexcept
 {
 	this->representation = other.representation;
 	std::swap(this->impl, other.impl);
+	std::swap(this->nodeValues, other.nodeValues);
+	std::swap(this->edgeValues, other.edgeValues);
 	return *this;
 }
 
@@ -184,6 +190,16 @@ int DirectedGraph::compare(const DirectedGraph &other) const
 		return static_cast<int>(representation) - static_cast<int>(other.representation);
 	}
 
+	auto first = std::tie(nodeValues, edgeValues);
+	auto second = std::tie(other.nodeValues, other.edgeValues);
+
+	std::compare<decltype(first)> comp;
+	int res = comp(first, second);
+
+	if (res != 0) {
+		return res;
+	}
+
 	return impl->compare(other.impl);
 }
 
diff --git a/alib2data/src/graph/directed/DirectedGraph.h b/alib2data/src/graph/directed/DirectedGraph.h
index 0844695284751cc0ffa3ee0c367b358a1dd7128a..5aa24d57037e10b397dc4f0f42b427785a8eb883 100644
--- a/alib2data/src/graph/directed/DirectedGraph.h
+++ b/alib2data/src/graph/directed/DirectedGraph.h
@@ -79,6 +79,9 @@ private:
 
 	std::unordered_map<Node, int> nodeValues;
 	std::unordered_map<DirectedEdge, int> edgeValues;
+
+	friend class GraphToXMLComposer;
+	friend class GraphToStringComposer;
 };
 
 } // namespace graph
diff --git a/alib2data/src/graph/undirected/UndirectedGraph.cpp b/alib2data/src/graph/undirected/UndirectedGraph.cpp
index 4209cf1674ebfc5a4783795c3abc8b998c851ac8..2c35fa860067ff8372d6c1fd0496a0e9b0118fde 100644
--- a/alib2data/src/graph/undirected/UndirectedGraph.cpp
+++ b/alib2data/src/graph/undirected/UndirectedGraph.cpp
@@ -23,6 +23,8 @@ UndirectedGraph::~UndirectedGraph() noexcept
 
 UndirectedGraph::UndirectedGraph(const UndirectedGraph &other)
 	: representation(other.representation)
+	, nodeValues(other.nodeValues)
+	, edgeValues(other.edgeValues)
 {
 	init();
 	impl->copy(other.impl);
@@ -31,6 +33,8 @@ UndirectedGraph::UndirectedGraph(const UndirectedGraph &other)
 UndirectedGraph::UndirectedGraph(UndirectedGraph &&other) noexcept
 	: representation(other.representation)
 	, impl(other.impl)
+	, nodeValues(std::move(other.nodeValues))
+	, edgeValues(std::move(other.edgeValues))
 {
 	other.impl = 0;
 }
@@ -49,6 +53,8 @@ UndirectedGraph &UndirectedGraph::operator=(UndirectedGraph &&other) noexcept
 {
 	this->representation = other.representation;
 	std::swap(this->impl, other.impl);
+	std::swap(this->nodeValues, other.nodeValues);
+	std::swap(this->edgeValues, other.edgeValues);
 	return *this;
 }
 
@@ -184,6 +190,16 @@ int UndirectedGraph::compare(const UndirectedGraph &other) const
 		return static_cast<int>(representation) - static_cast<int>(other.representation);
 	}
 
+	auto first = std::tie(nodeValues, edgeValues);
+	auto second = std::tie(other.nodeValues, other.edgeValues);
+
+	std::compare<decltype(first)> comp;
+	int res = comp(first, second);
+
+	if (res != 0) {
+		return res;
+	}
+
 	return impl->compare(other.impl);
 }
 
diff --git a/alib2data/src/graph/undirected/UndirectedGraph.h b/alib2data/src/graph/undirected/UndirectedGraph.h
index 8476e4d970da18c58af4892c0b1e34cbf50b9a1c..0fc7dad5f07921653342426c61bcf69aa97c928e 100644
--- a/alib2data/src/graph/undirected/UndirectedGraph.h
+++ b/alib2data/src/graph/undirected/UndirectedGraph.h
@@ -79,6 +79,9 @@ private:
 
 	std::unordered_map<Node, int> nodeValues;
 	std::unordered_map<UndirectedEdge, int> edgeValues;
+
+	friend class GraphToXMLComposer;
+	friend class GraphToStringComposer;
 };
 
 } // namespace graph
diff --git a/alib2data/test-src/graph/GraphTest.cpp b/alib2data/test-src/graph/GraphTest.cpp
index 5352db77fd15008461115bfebe10abbfea391b24..f39266d61acc9703e15bbef2ec3844989dd40cd3 100644
--- a/alib2data/test-src/graph/GraphTest.cpp
+++ b/alib2data/test-src/graph/GraphTest.cpp
@@ -182,6 +182,14 @@ void GraphTest::testXMLParser_impl(graph::REPRESENTATION representation)
 	graph::Graph dg2 = alib::XmlDataFactory::fromString<graph::Graph>(tmp);
 	CPPUNIT_ASSERT(dg1 == dg2);
 
+	dg.setEdgeValue(graph::DirectedEdge(n1, n2), 1);
+	dg.setEdgeValue(graph::DirectedEdge(n1, n3), 2);
+
+	graph::Graph dg1_2(dg);
+	tmp = alib::XmlDataFactory::toString(dg1_2);
+	graph::Graph dg2_2 = alib::XmlDataFactory::fromString<graph::Graph>(tmp);
+	CPPUNIT_ASSERT(dg1_2 == dg2_2);
+
 	// Undirected
 	graph::UndirectedGraph ug(representation);
 	ug.addNode(n1);
@@ -194,6 +202,14 @@ void GraphTest::testXMLParser_impl(graph::REPRESENTATION representation)
 	tmp = alib::XmlDataFactory::toString(ug1);
 	graph::Graph ug2 = alib::XmlDataFactory::fromString<graph::Graph>(tmp);
 	CPPUNIT_ASSERT(ug1 == ug2);
+
+	ug.setEdgeValue(graph::UndirectedEdge(n1, n2), 1);
+	ug.setEdgeValue(graph::UndirectedEdge(n1, n3), 2);
+
+	graph::Graph ug1_2(ug);
+	tmp = alib::XmlDataFactory::toString(ug1_2);
+	graph::Graph ug2_2 = alib::XmlDataFactory::fromString<graph::Graph>(tmp);
+	CPPUNIT_ASSERT(ug1_2 == ug2_2);
 }
 
 void GraphTest::testStringParser_impl(graph::REPRESENTATION representation)
@@ -216,6 +232,14 @@ void GraphTest::testStringParser_impl(graph::REPRESENTATION representation)
 	graph::Graph dg2 = alib::StringDataFactory::fromString<graph::Graph>(tmp);
 	CPPUNIT_ASSERT(dg1 == dg2);
 
+	dg.setEdgeValue(graph::DirectedEdge(n1, n2), 1);
+	dg.setEdgeValue(graph::DirectedEdge(n1, n3), 2);
+
+	graph::Graph dg1_2(dg);
+	tmp = alib::StringDataFactory::toString(dg1_2);
+	graph::Graph dg2_2 = alib::StringDataFactory::fromString<graph::Graph>(tmp);
+	CPPUNIT_ASSERT(dg1_2 == dg2_2);
+
 	// Undirected
 	graph::UndirectedGraph ug(representation);
 	ug.addNode(n1);
@@ -228,6 +252,14 @@ void GraphTest::testStringParser_impl(graph::REPRESENTATION representation)
 	tmp = alib::StringDataFactory::toString(ug1);
 	graph::Graph ug2 = alib::StringDataFactory::fromString<graph::Graph>(tmp);
 	CPPUNIT_ASSERT(ug1 == ug2);
+
+	ug.setEdgeValue(graph::UndirectedEdge(n1, n2), 1);
+	ug.setEdgeValue(graph::UndirectedEdge(n1, n3), 2);
+
+	graph::Graph ug1_2(ug);
+	tmp = alib::StringDataFactory::toString(ug1_2);
+	graph::Graph ug2_2 = alib::StringDataFactory::fromString<graph::Graph>(tmp);
+	CPPUNIT_ASSERT(ug1_2 == ug2_2);
 }
 
 void GraphTest::testAddEdge_impl(graph::REPRESENTATION representation)