diff --git a/repos/os/run/xml_node.run b/repos/os/run/xml_node.run
new file mode 100644
index 0000000000..48325dda53
--- /dev/null
+++ b/repos/os/run/xml_node.run
@@ -0,0 +1,26 @@
+build "core init test/xml_node"
+
+create_boot_directory
+
+install_config {
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+build_boot_image "core init test-xml_node"
+
+append qemu_args "-nographic -m 64"
+
+run_genode_until {.*child "test-xml_node" exited with exit value 0.*\n} 10
+
+puts "Test succeeded"
diff --git a/repos/os/src/test/xml_node/target.mk b/repos/os/src/test/xml_node/target.mk
new file mode 100644
index 0000000000..df60e0de15
--- /dev/null
+++ b/repos/os/src/test/xml_node/target.mk
@@ -0,0 +1,3 @@
+TARGET = test-xml_node
+SRC_CC = test.cc
+LIBS += base
diff --git a/repos/os/src/test/xml_node/test.cc b/repos/os/src/test/xml_node/test.cc
new file mode 100644
index 0000000000..191f63a1c3
--- /dev/null
+++ b/repos/os/src/test/xml_node/test.cc
@@ -0,0 +1,244 @@
+/*
+ * \brief Test for XML parser
+ * \author Norman Feske
+ * \date 2007-08-21
+ */
+
+#include
+#include
+
+using namespace Genode;
+
+
+/****************
+ ** Test cases **
+ ****************/
+
+/* valid example of XML structure */
+static const char *xml_test_valid =
+ ""
+ " "
+ " init"
+ " 16M"
+ " "
+ " "
+ " "
+ " timer"
+ " 64K"
+ " "
+ " "
+ " "
+ " framebuffer"
+ " 8M"
+ " "
+ "";
+
+/* the first 'program' tag is broken */
+static const char *xml_test_broken_tag =
+ ""
+ " "
+ " init"
+ " 16M"
+ " "
+ " "
+ " "
+ " timer"
+ " 64K"
+ " "
+ " "
+ " framebuffer"
+ " 8M"
+ " "
+ "";
+
+/* end tag is missing */
+static const char *xml_test_truncated =
+ ""
+ " "
+ " init"
+ " 16M"
+ " "
+ " "
+ " "
+ " timer"
+ " 64K"
+ " "
+ " "
+ " framebuffer"
+ " 8M"
+ " ";
+
+/* comment end tag is missing */
+static const char *xml_test_truncated_comment =
+ ""
+ " "
+ " init"
+ " 16M"
+ " "
+ " "
+ " "
+ " timer"
+ " 64K"
+ " "
+ " "
+ " \"unfinished string"
+ " 64K"
+ " "
+ " "
+ " framebuffer"
+ " 8M"
+ " "
+ "";
+
+/* valid XML structure attributes */
+static const char *xml_test_attributes =
+ ""
+ " "
+ " init"
+ " 16M"
+ " "
+ " "
+ " "
+ "";
+
+
+/******************
+ ** Test program **
+ ******************/
+
+/**
+ * Print attributes of XML node
+ */
+static void print_xml_attr_info(Xml_node xml_node, int indent = 0)
+{
+ try {
+ for (Xml_node::Attribute a = xml_node.attribute(0U); ; a = a.next()) {
+
+ /* indentation */
+ for (int i = 0; i < indent; i++)
+ printf(" ");
+
+ /* read attribute name and value */
+ char name[32]; name[0] = 0;
+ a.value(name, sizeof(name));
+ char value[32]; value[0] = 0;
+ a.value(value, sizeof(value));
+
+ printf("attribute name=\"%s\", value=\"%s\"\n", name, value);
+ }
+ } catch (Xml_node::Nonexistent_attribute) { }
+}
+
+
+/**
+ * Print information about XML node and its sub nodes
+ *
+ * \param xml_node root fo XML sub tree to print
+ * \param indent current indentation level
+ */
+static void print_xml_node_info(Xml_node xml_node, int indent = 0)
+{
+ char buf[128];
+ xml_node.type_name(buf, sizeof(buf));
+
+ /* indentation */
+ for (int i = 0; i < indent; i++)
+ printf(" ");
+
+ /* print node information */
+ printf("XML node: name = \"%s\", ", buf);
+ if (xml_node.num_sub_nodes() == 0) {
+ xml_node.value(buf, sizeof(buf));
+ printf("leaf content = \"%s\"\n", buf);
+ } else
+ printf("number of subnodes = %d\n",
+ xml_node.num_sub_nodes());
+
+ print_xml_attr_info(xml_node, indent + 2);
+
+ /* print information of sub nodes */
+ for (unsigned i = 0; i < xml_node.num_sub_nodes(); i++) {
+ try {
+ Xml_node sub_node = xml_node.sub_node(i);
+ print_xml_node_info(sub_node, indent + 2);
+ } catch (Xml_node::Invalid_syntax) {
+ printf("invalid syntax of sub node %d\n", i);
+ }
+ }
+}
+
+
+/**
+ * Print content of sub node with specified type
+ */
+static void print_key(Xml_node node, const char *key)
+{
+ try {
+ Xml_node sub_node = node.sub_node(key);
+ char buf[32];
+ sub_node.value(buf, sizeof(buf));
+ printf("content of sub node \"%s\" = \"%s\"\n", key, buf);
+ } catch (Xml_node::Nonexistent_sub_node) {
+ printf("sub node \"%s\" is not defined\n", key);
+ } catch (Xml_node::Invalid_syntax) {
+ printf("invalid syntax of node \"%s\"\n", key);
+ }
+}
+
+
+static void print_xml_info(const char *xml_string)
+{
+ try {
+ print_xml_node_info(Xml_node(xml_string));
+ } catch (Xml_node::Invalid_syntax) {
+ printf("string has invalid XML syntax\n");
+ }
+}
+
+
+int main()
+{
+ printf("--- XML-parser test ---\n");
+
+ printf("-- Test valid XML structure --\n");
+ print_xml_info(xml_test_valid);
+
+ printf("-- Test invalid XML structure (broken tag) --\n");
+ print_xml_info(xml_test_broken_tag);
+
+ printf("-- Test invalid XML structure (truncated) --\n");
+ print_xml_info(xml_test_truncated);
+
+ printf("-- Test invalid XML structure (truncated comment) --\n");
+ print_xml_info(xml_test_truncated_comment);
+
+ printf("-- Test invalid XML structure (unfinished string) --\n");
+ print_xml_info(xml_test_unfinished_string);
+
+ printf("-- Test node access by key --\n");
+ Xml_node prg(Xml_node(xml_test_valid).sub_node(0U));
+ print_key(prg, "filename");
+ print_key(prg, "quota");
+ print_key(prg, "info");
+
+ printf("-- Test access to XML attributes --\n");
+ print_xml_info(xml_test_attributes);
+
+ printf("--- End of XML-parser test ---\n");
+ return 0;
+}