diff --git a/appveyor.yml b/appveyor.yml
index d76ebe2..c3fcdaf 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,21 +1,32 @@
+version: 1.4.{build}
+
+image: Visual Studio 2017
+
 environment:
   matrix:
     - PYTHON: "C:\\Python27"
-      PYVER: "2.7"
-    - PYTHON: "C:\\Python35"
-      PYVER: "3.5"
+      PYVER: 2
+      BITS: 32
     - PYTHON: "C:\\Python36"
-      PYVER: "3.6"
+      PYVER: 3
+      BITS: 32
     - PYTHON: "C:\\Python37"
-      PYVER: "3.7"
+      PYVER: 3
+      BITS: 32
     - PYTHON: "C:\\Python27-x64"
-      PYVER: "2.7"
-    - PYTHON: "C:\\Python35-x64"
-      PYVER: "3.5"
+      PYVER: 2
+      BITS: 64
     - PYTHON: "C:\\Python36-x64"
-      PYVER: "3.6"
+      PYVER: 3
+      BITS: 64
     - PYTHON: "C:\\Python37-x64"
-      PYVER: "3.7"
+      PYVER: 3
+      BITS: 64
+
+init:
+  - "ECHO %PYTHON% %vcvars% (%bits%)"
+  - ps: $env:PATH = "$env:PYTHON;$env:PATH;"
+  - python -c "import sys;print('Python version is {}'.format(sys.version))"
 
 build: false
 
diff --git a/doc/tools.rst b/doc/tools.rst
index 754b0af..3fa9cda 100644
--- a/doc/tools.rst
+++ b/doc/tools.rst
@@ -14,44 +14,50 @@ Tools
 =====
 Several tools are provided with the :py:mod:`odml.tools` package.
 
-ODMLParser
+DictParser
 ----------
-.. automodule:: odml.tools.odmlparser
+.. automodule:: odml.tools.dict_parser
    :members:
    :inherited-members:
    :undoc-members:
 
-XMLParser
----------
-.. automodule:: odml.tools.xmlparser
+ODMLParser
+----------
+.. automodule:: odml.tools.odmlparser
    :members:
    :inherited-members:
    :undoc-members:
 
-DictParser
-----------
-.. automodule:: odml.tools.dict_parser
+RDFConverter
+----------------
+.. automodule:: odml.tools.rdf_converter
    :members:
    :inherited-members:
    :undoc-members:
 
-FormatConverter
-----------------
-.. automodule:: odml.tools.format_converter
+XMLParser
+---------
+.. automodule:: odml.tools.xmlparser
    :members:
    :inherited-members:
    :undoc-members:
 
-VersionConverter
+.. _converters:
+
+Convenience converters
+======================
+Several convenience converters are provided with the :py:mod:`odml.tools.converters` package.
+
+FormatConverter
 ----------------
-.. automodule:: odml.tools.version_converter
+.. automodule:: odml.tools.converters.format_converter
    :members:
    :inherited-members:
    :undoc-members:
 
-RDFConverter
+VersionConverter
 ----------------
-.. automodule:: odml.tools.rdf_converter
+.. automodule:: odml.tools.converters.version_converter
    :members:
    :inherited-members:
    :undoc-members:
diff --git a/odml/rdf/__init__.py b/odml/rdf/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/odml/tools/fuzzy_finder.py b/odml/rdf/fuzzy_finder.py
similarity index 99%
rename from odml/tools/fuzzy_finder.py
rename to odml/rdf/fuzzy_finder.py
index 97538db..12ec197 100644
--- a/odml/tools/fuzzy_finder.py
+++ b/odml/rdf/fuzzy_finder.py
@@ -1,4 +1,4 @@
-from odml.tools.query_creator import QueryCreator, QueryParser, QueryParserFuzzy
+from .query_creator import QueryCreator, QueryParser, QueryParserFuzzy
 
 
 class FuzzyFinder(object):
diff --git a/odml/tools/query_creator.py b/odml/rdf/query_creator.py
similarity index 100%
rename from odml/tools/query_creator.py
rename to odml/rdf/query_creator.py
diff --git a/odml/scripts/odml_convert.py b/odml/scripts/odml_convert.py
index d52f5a5..7c36901 100644
--- a/odml/scripts/odml_convert.py
+++ b/odml/scripts/odml_convert.py
@@ -35,7 +35,7 @@ except ImportError:
 
 import odml
 
-from odml.tools.version_converter import VersionConverter as VerConf
+from odml.tools.converters import VersionConverter as VerConf
 
 try:
     unicode = unicode
diff --git a/odml/scripts/odml_to_rdf.py b/odml/scripts/odml_to_rdf.py
index 4eae0be..f12f32a 100644
--- a/odml/scripts/odml_to_rdf.py
+++ b/odml/scripts/odml_to_rdf.py
@@ -37,7 +37,7 @@ except ImportError:
 import odml
 
 from odml.tools.odmlparser import ODMLReader, ODMLWriter
-from odml.tools.version_converter import VersionConverter as VerConf
+from odml.tools.converters import VersionConverter as VerConf
 
 try:
     unicode = unicode
diff --git a/odml/tools/__init__.py b/odml/tools/__init__.py
index e69de29..e649d26 100644
--- a/odml/tools/__init__.py
+++ b/odml/tools/__init__.py
@@ -0,0 +1,4 @@
+from .dict_parser import DictReader, DictWriter
+from .odmlparser import ODMLReader, ODMLWriter
+from .rdf_converter import RDFReader, RDFWriter
+from .xmlparser import XMLReader, XMLWriter
diff --git a/odml/tools/converters/__init__.py b/odml/tools/converters/__init__.py
new file mode 100644
index 0000000..218caa5
--- /dev/null
+++ b/odml/tools/converters/__init__.py
@@ -0,0 +1,3 @@
+from .version_converter import VersionConverter
+# FormatConverter depends on VersionConverter
+from .format_converter import FormatConverter
diff --git a/odml/tools/format_converter.py b/odml/tools/converters/format_converter.py
similarity index 86%
rename from odml/tools/format_converter.py
rename to odml/tools/converters/format_converter.py
index 3ae8d91..e4670d8 100644
--- a/odml/tools/format_converter.py
+++ b/odml/tools/converters/format_converter.py
@@ -1,12 +1,14 @@
 import argparse
+import copy
 import os
 import re
 import sys
 
 import odml
-from .rdf_converter import RDFWriter
-from .version_converter import VersionConverter
-from .utils import ConversionFormats
+
+from .. import RDFWriter
+from . import VersionConverter
+from ..parser_utils import RDF_CONVERSION_FORMATS
 
 try:
     unicode = unicode
@@ -14,6 +16,13 @@ except NameError:
     unicode = str
 
 
+CONVERSION_FORMATS = copy.deepcopy(RDF_CONVERSION_FORMATS)
+CONVERSION_FORMATS.update({
+    'v1_1': '.xml',
+    'odml': '.odml'
+})
+
+
 class FormatConverter(object):
 
     @classmethod
@@ -21,20 +30,20 @@ class FormatConverter(object):
         """
         Enable usage of the argparse for calling convert_dir(...)
         Example:
-            1) >> python format_converter.py ./..path../input_dir v1_1 -out ./..path../output_dir -r
+            1) >> python -m odml.tools.converters.format_converter ./..path../input_dir v1_1 -out ./..path../output_dir -r
             
                Convert files from the path <./..path../input_dir> to .xml odml version 1.1,
                writes them into <./..path../output_dir> including subdirectories 
                and its files from the input path.
             
-            2) >> python format_converter.py ./..path../input_dir odml
+            2) >> python -m odml.tools.converters.format_converter ./..path../input_dir odml
             
                Converts files from path <./..path../input_dir> to .odml,
                writes them into <./..path../input_dir_odml> not including subdirectories.
         """
         parser = argparse.ArgumentParser(description="Convert directory with odml files to another format")
         parser.add_argument("input_dir", help="Path to input directory")
-        parser.add_argument("result_format", choices=list(ConversionFormats),
+        parser.add_argument("result_format", choices=list(CONVERSION_FORMATS),
                             help="Format of output files")
         parser.add_argument("-out", "--output_dir", help="Path for output directory")
         parser.add_argument("-r", "--recursive", action="store_true",
@@ -54,11 +63,11 @@ class FormatConverter(object):
                            Possible choices: "v1_1" (converts to version 1.1 from version 1 xml)
                                              "odml" (converts to .odml from version 1.1 .xml files)
                                              "turtle", "nt" etc. (converts to rdf formats from version 1.1 .odml files)
-                                             (see full list of rdf serializers in utils.ConversionFormats)
+                                             (see full list of rdf serializers in CONVERSION_FORMATS)
         """
-        if res_format not in ConversionFormats:
+        if res_format not in CONVERSION_FORMATS:
             raise ValueError("Format for output files is incorrect. "
-                             "Please choose from the list: {}".format(list(ConversionFormats)))
+                             "Please choose from the list: {}".format(list(CONVERSION_FORMATS)))
 
         cls._check_input_output_directory(input_dir, output_dir)
         input_dir = os.path.join(input_dir, '')
@@ -98,14 +107,14 @@ class FormatConverter(object):
                 p, _ = os.path.splitext(output_path)
                 output_path = p + ".odml"
             odml.save(odml.load(input_path), output_path)
-        elif res_format in ConversionFormats:
-            if not output_path.endswith(ConversionFormats[res_format]):
+        elif res_format in CONVERSION_FORMATS:
+            if not output_path.endswith(CONVERSION_FORMATS[res_format]):
                 p, _ = os.path.splitext(output_path)
-                output_path = p + ConversionFormats[res_format]
+                output_path = p + CONVERSION_FORMATS[res_format]
             RDFWriter(odml.load(input_path)).write_file(output_path, res_format)
         else:
             raise ValueError("Format for output files is incorrect. "
-                             "Please choose from the list: {}".format(list(ConversionFormats)))
+                             "Please choose from the list: {}".format(list(CONVERSION_FORMATS)))
 
     @staticmethod
     def _create_sub_directory(dir_path):
diff --git a/odml/tools/converters/version_converter.py b/odml/tools/converters/version_converter.py
new file mode 100644
index 0000000..cc99709
--- /dev/null
+++ b/odml/tools/converters/version_converter.py
@@ -0,0 +1,505 @@
+import io
+import json
+import os
+import sys
+import yaml
+
+from lxml import etree as ET
+
+from ... import format
+from ...info import FORMAT_VERSION
+from ...terminology import Terminologies, REPOSITORY_BASE
+
+import uuid
+
+try:
+    unicode = unicode
+except NameError:
+    unicode = str
+
+
+class VersionConverter(object):
+    """
+    Class for converting odml xml files from version 1.0 to 1.1
+    """
+    _version_map = {
+        'filename': 'value_origin',
+        'dtype': 'type'
+    }
+
+    def __init__(self, filename):
+        self.filename = filename
+        self.conversion_log = []
+
+    def _parse_xml(self):
+        """
+        _parse_xml checks whether the provided file object can be parsed
+        and returns the parsed lxml tree.
+        :return: ElementTree
+        """
+        # Make pretty print available by resetting format
+        parser = ET.XMLParser(remove_blank_text=True)
+        if isinstance(self.filename, io.StringIO):
+            doc = self.filename.getvalue()
+            tree = ET.ElementTree(ET.fromstring(doc, parser))
+
+        elif os.path.exists(self.filename) and os.path.getsize(self.filename) > 0:
+            tree = ET.parse(self.filename, parser)
+        else:
+            msg = "Cannot parse provided file object '%s'." % self.filename
+            raise Exception(msg)
+
+        return tree
+
+    def _parse_json(self):
+        with open(self.filename) as file:
+            parsed_doc = json.load(file)
+
+        return self._parse_dict_document(parsed_doc)
+
+    def _parse_yaml(self):
+        with open(self.filename) as file:
+            parsed_doc = yaml.load(file)
+
+        return self._parse_dict_document(parsed_doc)
+
+    @classmethod
+    def _parse_dict_document(cls, parsed_doc):
+        """
+        _parse_dict_document parses a python dictionary containing a valid
+        v1.0 odML document into an lxml.ElementTree XML equivalent and returns
+        the resulting lxml ElementTree.
+        :param parsed_doc: python dictionary containing a valid v1.0 odML document.
+        :return: lxml ElementTree
+        """
+        root = ET.Element("odML")
+
+        parsed_doc = parsed_doc['Document']
+
+        for elem in parsed_doc:
+            if elem == 'sections':
+                cls._parse_dict_sections(root, parsed_doc['sections'])
+            elif elem:
+                curr_element = ET.Element(elem)
+                curr_element.text = parsed_doc[elem]
+                root.append(curr_element)
+
+        return ET.ElementTree(root)
+
+    @classmethod
+    def _parse_dict_sections(cls, parent_element, section_list):
+        """
+        _parse_dict_sections parses a list containing python dictionaries of v1.0 odML
+        style sections into lxml.Element XML equivalents and appends the parsed Sections
+        to the provided lxml.Element parent.
+        :param parent_element: lxml.Element to which parsed sections will be appended.
+        :param section_list: list of python dictionaries containing valid v1.0 odML
+                             Sections.
+        """
+        for section in section_list:
+            sec = ET.Element("section")
+            for element in section:
+                if element == 'properties':
+                    cls._parse_dict_properties(sec, section['properties'])
+                elif element == 'sections':
+                    cls._parse_dict_sections(sec, section['sections'])
+                elif element:
+                    elem = ET.Element(element)
+                    elem.text = section[element]
+                    sec.append(elem)
+
+            parent_element.append(sec)
+
+    @classmethod
+    def _parse_dict_properties(cls, parent_element, props_list):
+        """
+        _parse_dict_properties parses a list containing python dictionaries of v1.0 odML
+        style properties into lxml.Element XML equivalents and appends the parsed
+        Properties to the provided lxml.Element parent.
+        :param parent_element: lxml.Element to which parsed properties will be appended.
+        :param props_list: list of python dictionaries containing valid v1.0 odML
+                           Properties.
+        """
+        for curr_prop in props_list:
+            prop = ET.Element("property")
+            for element in curr_prop:
+                if element == 'values':
+                    cls._parse_dict_values(prop, curr_prop['values'])
+                elif element:
+                    elem = ET.Element(element)
+                    elem.text = curr_prop[element]
+                    prop.append(elem)
+
+            parent_element.append(prop)
+
+    @staticmethod
+    def _parse_dict_values(parent_element, value_list):
+        """
+        _parse_dict_values parses a list containing python dictionaries of v1.0 odML
+        style values into lxml.Element XML equivalents and appends the parsed
+        Values to the provided lxml.Element parent.
+        :param parent_element: lxml.Element to which parsed values will be appended.
+        :param value_list: list of python dictionaries containing valid v1.0 odML Values.
+        """
+        for value in value_list:
+            val = ET.Element("value")
+            for element in value:
+                if element:
+                    if element == 'value':
+                        val.text = str(value[element])
+                    else:
+                        elem = ET.Element(element)
+                        elem.text = str(value[element])
+                        val.append(elem)
+
+            parent_element.append(val)
+
+    def _convert(self, tree):
+        """
+        Converts an lxml.ElementTree containing a v1.0 odML document to odML v1.1.
+        Unites multiple value objects and moves all supported Value elements to
+        its parent Property. Exports only Document, Section and Property elements,
+        that are supported by odML v1.1.
+        """
+        # Reset status messages
+        self.conversion_log = []
+
+        tree = self._replace_same_name_entities(tree)
+        root = tree.getroot()
+        root.set("version", FORMAT_VERSION)
+
+        # Handle Values, exclude unsupported Property attributes and unnamed Properties.
+        self._handle_properties(root)
+
+        # Exclude unsupported Section attributes, ignore comments, handle repositories.
+        for sec in root.iter("section"):
+            sec_name = sec.find("name").text
+            for e in sec:
+                if e.tag not in format.Section.arguments_keys and isinstance(e.tag, str):
+                    self._log("[Info] Omitted non-Section attribute "
+                              "'%s: %s/%s'" % (sec_name, e.tag, e.text))
+                    sec.remove(e)
+                    continue
+
+                if e.tag == "repository":
+                    self._handle_repository(e)
+                elif e.tag == "include":
+                    self._handle_include(e)
+
+        # Exclude unsupported Document attributes, ignore comments, handle repositories.
+        for e in root:
+            if e.tag not in format.Document.arguments_keys and isinstance(e.tag, str):
+                self._log("[Info] Omitted non-Document "
+                          "attribute '%s/%s'" % (e.tag, e.text))
+                root.remove(e)
+                continue
+
+            if e.tag == "repository":
+                self._handle_repository(e)
+
+        tree = self._check_add_ids(tree)
+
+        return tree
+
+    def _handle_include(self, element):
+        """
+        _handle_include checks whether a provided include element is
+        v1.1 compatible and logs a warning message otherwise.
+        :param element: lxml element containing the provided include link.
+        """
+        content = element.text
+        cache = {}
+        term_handler = Terminologies(cache)
+        term = term_handler.load(element.text)
+
+        # If the include url can be loaded and parsed, everything is fine.
+        if term is not None:
+            return
+
+        # If the include url is a v1.0 odml-terminology one,
+        # check whether a v1.1 is available and use it instead.
+        if '/'.join([REPOSITORY_BASE, "v1.0"]) in element.text:
+            element.text = element.text.replace('v1.0', 'v1.1')
+            term = term_handler.load(element.text)
+
+            if term is not None:
+                msg = "[Info] Replaced Section.include url '%s' with '%s'." \
+                      % (content, element.text)
+                self._log(msg)
+                return
+
+        # Log a warning, if no v1.1 compatible url can be provided.
+        self._log("[Warning] Section include file '%s' "
+                  "is not odML v1.1 compatible." % content)
+
+    def _handle_repository(self, element):
+        """
+        The method handles provided odML repositories.
+        :param element: lxml element containing the provided odML repository link.
+        """
+        content = element.text
+        cache = {}
+        term_handler = Terminologies(cache)
+        term = term_handler.load(element.text)
+
+        # If the repository url can be loaded and parsed, everything is fine.
+        if term is not None:
+            return
+
+        # If the repository url is a v1.0 odml-terminology one,
+        # check whether a v1.1 is available and use it instead.
+        if '/'.join([REPOSITORY_BASE, "v1.0"]) in element.text:
+            element.text = element.text.replace('v1.0', 'v1.1')
+            term = term_handler.load(element.text)
+
+            if term is not None:
+                msg = "[Info] Replaced repository url '%s' with '%s'." \
+                      % (content, element.text)
+                self._log(msg)
+                return
+
+        # Print a warning, if no v1.1 compatible repository url can be provided.
+        self._log("[Warning] Repository file '%s' is not odML v1.1 compatible." % content)
+
+    def _handle_properties(self, root):
+        """
+        Method removes all property elements w/o name attribute, converts Value
+        elements from v1.0 to v1.1 style and removes unsupported Property elements.
+        :param root:
+        """
+        for prop in root.iter("property"):
+            main_val = ET.Element("value")
+            multiple_values = False
+            parent = prop.getparent()
+
+            # If a Property has no name attribute, remove it from its parent and
+            # continue with the next Property.
+            if prop.find("name") is None:
+                self._log("[Warning] Omitted Property without "
+                          "name tag: '%s'" % ET.tostring(prop))
+                parent.remove(prop)
+                continue
+
+            sname = "unnamed"
+            if parent.find("name") is not None:
+                sname = parent.find("name").text
+            stype = "untyped"
+            if parent.find("type") is not None:
+                stype = parent.find("type").text
+            prop_id = "%s|%s:%s" % (sname, stype, prop.find("name").text)
+
+            # Special handling of Values
+            for value in prop.iter("value"):
+                # Move supported elements from Value to parent Property.
+                self._handle_value(value, prop_id)
+
+                if value.text:
+                    if main_val.text:
+                        main_val.text += "," + value.text.strip()
+                        multiple_values = True
+                    else:
+                        main_val.text = value.text.strip()
+
+                prop.remove(value)
+
+            # Append value element only if it contains an actual value
+            if main_val.text:
+                # Multiple values require brackets
+                if multiple_values:
+                    main_val.text = "[" + main_val.text + "]"
+
+                prop.append(main_val)
+
+            # Reverse map "dependency_value", exclude unsupported Property attributes.
+            for elem in prop:
+                if elem.tag == "dependency_value":
+                    elem.tag = "dependencyvalue"
+
+                if (elem.tag not in format.Property.arguments_keys and
+                        isinstance(elem.tag, str)):
+                    self._log("[Info] Omitted non-Property attribute "
+                              "'%s: %s/%s'" % (prop_id, elem.tag, elem.text))
+                    prop.remove(elem)
+
+    def _handle_value(self, value, log_id):
+        """
+        Values changed from odML v1.0 to v1.1. This function moves all supported
+        odML Property elements from a v1.0 Value element to the parent Property element.
+        Adds a log entry for every non-exported element.
+        :param value: etree element containing the v1.0 Value.
+        :param log_id: String containing Section and Property name and type to log
+                       omitted elements and value contents.
+        """
+        for val_elem in value.iter():
+            if val_elem.tag != "value":
+                # Check whether current Value attribute has already been exported
+                # under its own or a different name. Give a warning, if the values differ.
+                parent = value.getparent()
+                if val_elem.tag in self._version_map:
+                    check_export = parent.find(self._version_map[val_elem.tag])
+                else:
+                    check_export = parent.find(val_elem.tag)
+
+                if check_export is not None:
+                    if check_export.text != val_elem.text:
+                        self._log("[Warning] Value element '%s: %s/%s' already exported, "
+                                  "omitting further element value '%s'"
+                                  % (log_id, val_elem.tag,
+                                     check_export.text, val_elem.text))
+
+                # Include only supported Property attributes
+                elif val_elem.tag in format.Property.arguments_keys:
+                    new_elem = ET.Element(val_elem.tag)
+                    new_elem.text = val_elem.text
+
+                    if val_elem.tag in ["type", "dtype"] and val_elem.text == "binary":
+                        new_elem.text = "text"
+                        self._log("[Warning] Replacing unsupported value type "
+                                  "'binary' with 'text' (%s)" % log_id)
+
+                    parent.append(new_elem)
+                elif val_elem.tag in self._version_map:
+                    new_elem = ET.Element(self._version_map[val_elem.tag])
+                    new_elem.text = val_elem.text
+
+                    if val_elem.tag in ["type", "dtype"] and val_elem.text == "binary":
+                        new_elem.text = "text"
+                        self._log("[Warning] Replacing unsupported value type "
+                                  "'binary' with 'text' (%s)" % log_id)
+
+                    parent.append(new_elem)
+                else:
+                    self._log("[Info] Omitted non-Value attribute '%s: %s/%s'"
+                              % (log_id, val_elem.tag, val_elem.text))
+
+    @classmethod
+    def _replace_same_name_entities(cls, tree):
+        """
+        Changes same section names in the doc by adding <-{index}>
+        to the next section occurrences.
+        :param tree: ElementTree of the doc
+        :return: ElementTree
+        """
+        sec_map = {}
+        prop_map = {}
+        root = tree.getroot()
+        for sec in root.iter("section"):
+
+            sec_name = sec.find("name")
+            if sec_name is not None:
+                cls._change_entity_name(tree, sec_map, sec_name)
+            else:
+                raise Exception("Section attribute name is not specified")
+
+            for prop in sec.iter("property"):
+                if prop.getparent() == sec:
+                    prop_name = prop.find("name")
+                    if prop_name is not None:
+                        cls._change_entity_name(tree, prop_map, prop_name)
+            prop_map.clear()
+        return tree
+
+    @staticmethod
+    def _change_entity_name(tree, elem_map, name):
+        """
+        Adds numbering to identical element names where their odml.Section
+        or odml.Property parents reside on the same level in the tree.
+        :param tree: The element tree containing the 'name' element.
+        :param elem_map: lxml path to occurrence maps of named Sections or Properties.
+        :param name: lxml element containing the name text of a Section or Property.
+        """
+        named_path = "%s:%s" % (tree.getpath(name.getparent().getparent()), name.text)
+        if named_path not in elem_map:
+            elem_map[named_path] = 1
+        else:
+            elem_map[named_path] += 1
+            name.text += "-" + str(elem_map[named_path])
+
+    def _check_add_ids(self, tree):
+        """
+        Checks, whether elements (properties) possess an UUID
+        and adds one in case of absence.
+        :param tree: ElementTree of the doc
+        :return: ElementTree
+        """
+        root = tree.getroot()
+        self._add_id(root)
+        for sec in root.iter("section"):
+            self._add_id(sec)
+            for prop in sec.iter("property"):
+                self._add_id(prop)
+
+        return tree
+
+    @staticmethod
+    def _add_id(element):
+        """
+        Checks, whether an element possesses an ID. If yes, make sure it has
+        the right format. Otherwise a new UUID is created.
+        :param element: lxml element.
+        """
+        oid = element.find("id")
+        new_id = ET.Element("id")
+        new_id.text = str(uuid.uuid4())
+        if oid is not None:
+            try:
+                if oid.text is not None:
+                    new_id.text = str(uuid.UUID(oid.text))
+            except ValueError as e:
+                print(e)
+            element.remove(oid)
+        element.append(new_id)
+
+    def _log(self, msg):
+        """
+        Adds the passed message to the conversion_log attribute and
+        prints the message to the command line.
+        """
+        self.conversion_log.append(msg)
+        print(msg)
+
+    def __str__(self):
+        tree = self.convert()
+        return ET.tounicode(tree, pretty_print=True) if tree else ""
+
+    def __unicode__(self):
+        tree = self.convert()
+        return ET.tounicode(tree, pretty_print=True) if tree else ""
+
+    def convert(self, backend="XML"):
+        """
+        This method returns the content of the provided file object converted
+        to odML version 1.1 as a string object which is directly consumable
+        by the odml.tools.ODMLReader.
+        """
+        if backend.upper() == "JSON":
+            old_tree = self._parse_json()
+        elif backend.upper() == "YAML":
+            old_tree = self._parse_yaml()
+        elif backend.upper() == "XML":
+            old_tree = self._parse_xml()
+        else:
+            raise Exception("Unknown backend, only XML, JSON and YAML are supported.")
+
+        tree = self._convert(old_tree)
+        return ET.tounicode(tree, pretty_print=True) if tree else ""
+
+    def write_to_file(self, filename, backend="XML"):
+        """
+        This method converts the content of the provided converter file object
+        to odML version 1.1 and writes the results to `filename`.
+        :param filename: Output file.
+        :param backend: Format of the source file, default is XML.
+        """
+        data = self.convert(backend)
+        if sys.version_info < (3,):
+            data = data.encode('utf-8')
+
+        ext = [".xml", ".odml"]
+        if not filename.endswith(tuple(ext)):
+            filename = "%s.xml" % filename
+
+        if data and "<odML " in data:
+            with open(filename, "w") as file:
+                file.write('<?xml version="1.0" encoding="UTF-8"?>\n')
+                file.write(data)
diff --git a/odml/tools/dict_parser.py b/odml/tools/dict_parser.py
index f10a77a..d6ab3a7 100644
--- a/odml/tools/dict_parser.py
+++ b/odml/tools/dict_parser.py
@@ -138,7 +138,8 @@ class DictReader:
 
         elif self.parsed_doc.get('odml-version') != FORMAT_VERSION:
             msg = ("Cannot parse odML document with format version '%s'. \n"
-                   "\tUse the 'tools.VersionConverter' to import previous odML formats."
+                   "\tUse the 'VersionConverter' from 'odml.tools.converters' "
+                   "to import previous odML formats."
                    % self.parsed_doc.get('odml-version'))
             raise InvalidVersionException(msg)
 
diff --git a/odml/tools/parser_utils.py b/odml/tools/parser_utils.py
index 94c5b42..9f498db 100644
--- a/odml/tools/parser_utils.py
+++ b/odml/tools/parser_utils.py
@@ -6,6 +6,22 @@ commonly used by the odML tools parsers and converters.
 SUPPORTED_PARSERS = ['XML', 'YAML', 'JSON', 'RDF']
 
 
+RDF_CONVERSION_FORMATS = {
+    # rdflib version "4.2.2" serialization formats
+    'xml': '.rdf',
+    'pretty-xml': '.rdf',
+    'trix': '.rdf',
+    'n3': '.n3',
+    'turtle': '.ttl',
+    'ttl': '.ttl',
+    'ntriples': '.nt',
+    'nt': '.nt',
+    'nt11': '.nt',
+    'trig': '.trig',
+    'json-ld': '.jsonld'
+}
+
+
 class ParserException(Exception):
     """
     Exception wrapper used by various odML parsers.
diff --git a/odml/tools/rdf_converter.py b/odml/tools/rdf_converter.py
index cf377db..a357315 100644
--- a/odml/tools/rdf_converter.py
+++ b/odml/tools/rdf_converter.py
@@ -13,12 +13,12 @@ from rdflib.namespace import XSD, RDF
 
 import yaml
 
-from ..doc import BaseDocument
+import odml
+
 from ..format import Format, Document, Section, Property
 from ..info import FORMAT_VERSION, INSTALL_PATH
 from .dict_parser import DictReader
-from .parser_utils import ParserException
-from .utils import RDFConversionFormats
+from .parser_utils import ParserException, RDF_CONVERSION_FORMATS
 
 try:
     unicode = unicode
@@ -87,8 +87,7 @@ class RDFWriter(object):
         self.hub_root = URIRef(ODML_NS.Hub)
         if self.docs:
             for doc in self.docs:
-                if isinstance(doc, BaseDocument):
-                    # make sure links and includes are resolved before conversion
+                if isinstance(doc, odml.doc.BaseDocument):
                     doc.finalize()
                     self.save_document(doc)
 
@@ -303,15 +302,15 @@ class RDFWriter(object):
         Convert the current odML content of the parser to a common RDF graph
         and return the graph as a string object in the specified RDF format.
 
-        :param rdf_format: possible formats: 'xml', 'n3', 'turtle', 'nt', 'pretty-xml',
-                                             'trix', 'trig', 'nquads', 'json-ld'.
-               Full lists see in utils.RDFConversionFormats
+        :param rdf_format: RDF output format. Default format is 'turtle'.
+                           Available formats: 'xml', 'n3', 'turtle', 'nt',
+                           'pretty-xml', 'trix', 'trig', 'nquads', 'json-ld'.
 
         :return: string object
         """
-        if rdf_format not in RDFConversionFormats:
+        if rdf_format not in RDF_CONVERSION_FORMATS:
             msg = "odml.RDFWriter.get_rdf_str: Format for output files is incorrect."
-            msg = "%s Please choose from the list: %s" % (msg, list(RDFConversionFormats))
+            msg = "%s Please choose from the list: %s" % (msg, list(RDF_CONVERSION_FORMATS))
             raise ValueError(msg)
 
         return self.convert_to_rdf().serialize(format=rdf_format).decode("utf-8")
@@ -323,14 +322,14 @@ class RDFWriter(object):
         RDF output format.
 
         :param filename:
-        :param rdf_format: Possible RDF output format. See utils.RDFConversionFormats
-                           for a full list of supported formats.
-                           Default format is 'turtle'.
+        :param rdf_format: RDF output format. Default format is 'turtle'.
+                           Available formats: 'xml', 'n3', 'turtle', 'nt',
+                           'pretty-xml', 'trix', 'trig', 'nquads', 'json-ld'.
         """
         data = self.get_rdf_str(rdf_format)
         filename_ext = filename
-        if filename.find(RDFConversionFormats.get(rdf_format)) < 0:
-            filename_ext += RDFConversionFormats.get(rdf_format)
+        if filename.find(RDF_CONVERSION_FORMATS.get(rdf_format)) < 0:
+            filename_ext += RDF_CONVERSION_FORMATS.get(rdf_format)
 
         with open(filename_ext, "w") as out_file:
             out_file.write(data)
diff --git a/odml/tools/utils.py b/odml/tools/utils.py
deleted file mode 100644
index d981365..0000000
--- a/odml/tools/utils.py
+++ /dev/null
@@ -1,22 +0,0 @@
-import copy
-
-RDFConversionFormats = {
-    # rdflib version "4.2.2" serialization formats
-    'xml': '.rdf',
-    'pretty-xml': '.rdf',
-    'trix': '.rdf',
-    'n3': '.n3',
-    'turtle': '.ttl',
-    'ttl': '.ttl',
-    'ntriples': '.nt',
-    'nt': '.nt',
-    'nt11': '.nt',
-    'trig': '.trig',
-    'json-ld': '.jsonld'
-}
-
-ConversionFormats = copy.deepcopy(RDFConversionFormats)
-ConversionFormats.update({
-    'v1_1': '.xml',
-    'odml': '.odml'
-})
diff --git a/odml/tools/version_converter.py b/odml/tools/version_converter.py
index c7b22ab..a419935 100644
--- a/odml/tools/version_converter.py
+++ b/odml/tools/version_converter.py
@@ -1,504 +1,5 @@
-import io
-import json
-import os
-import sys
-import yaml
+from .converters import VersionConverter
 
-from lxml import etree as ET
-from .. import format
-from ..info import FORMAT_VERSION
-from ..terminology import Terminologies, REPOSITORY_BASE
-
-import uuid
-
-try:
-    unicode = unicode
-except NameError:
-    unicode = str
-
-
-class VersionConverter(object):
-    """
-    Class for converting odml xml files from version 1.0 to 1.1
-    """
-    _version_map = {
-        'filename': 'value_origin',
-        'dtype': 'type'
-    }
-
-    def __init__(self, filename):
-        self.filename = filename
-        self.conversion_log = []
-
-    def _parse_xml(self):
-        """
-        _parse_xml checks whether the provided file object can be parsed
-        and returns the parsed lxml tree.
-        :return: ElementTree
-        """
-        # Make pretty print available by resetting format
-        parser = ET.XMLParser(remove_blank_text=True)
-        if isinstance(self.filename, io.StringIO):
-            doc = self.filename.getvalue()
-            tree = ET.ElementTree(ET.fromstring(doc, parser))
-
-        elif os.path.exists(self.filename) and os.path.getsize(self.filename) > 0:
-            tree = ET.parse(self.filename, parser)
-        else:
-            msg = "Cannot parse provided file object '%s'." % self.filename
-            raise Exception(msg)
-
-        return tree
-
-    def _parse_json(self):
-        with open(self.filename) as file:
-            parsed_doc = json.load(file)
-
-        return self._parse_dict_document(parsed_doc)
-
-    def _parse_yaml(self):
-        with open(self.filename) as file:
-            parsed_doc = yaml.load(file)
-
-        return self._parse_dict_document(parsed_doc)
-
-    @classmethod
-    def _parse_dict_document(cls, parsed_doc):
-        """
-        _parse_dict_document parses a python dictionary containing a valid
-        v1.0 odML document into an lxml.ElementTree XML equivalent and returns
-        the resulting lxml ElementTree.
-        :param parsed_doc: python dictionary containing a valid v1.0 odML document.
-        :return: lxml ElementTree
-        """
-        root = ET.Element("odML")
-
-        parsed_doc = parsed_doc['Document']
-
-        for elem in parsed_doc:
-            if elem == 'sections':
-                cls._parse_dict_sections(root, parsed_doc['sections'])
-            elif elem:
-                curr_element = ET.Element(elem)
-                curr_element.text = parsed_doc[elem]
-                root.append(curr_element)
-
-        return ET.ElementTree(root)
-
-    @classmethod
-    def _parse_dict_sections(cls, parent_element, section_list):
-        """
-        _parse_dict_sections parses a list containing python dictionaries of v1.0 odML
-        style sections into lxml.Element XML equivalents and appends the parsed Sections
-        to the provided lxml.Element parent.
-        :param parent_element: lxml.Element to which parsed sections will be appended.
-        :param section_list: list of python dictionaries containing valid v1.0 odML
-                             Sections.
-        """
-        for section in section_list:
-            sec = ET.Element("section")
-            for element in section:
-                if element == 'properties':
-                    cls._parse_dict_properties(sec, section['properties'])
-                elif element == 'sections':
-                    cls._parse_dict_sections(sec, section['sections'])
-                elif element:
-                    elem = ET.Element(element)
-                    elem.text = section[element]
-                    sec.append(elem)
-
-            parent_element.append(sec)
-
-    @classmethod
-    def _parse_dict_properties(cls, parent_element, props_list):
-        """
-        _parse_dict_properties parses a list containing python dictionaries of v1.0 odML
-        style properties into lxml.Element XML equivalents and appends the parsed
-        Properties to the provided lxml.Element parent.
-        :param parent_element: lxml.Element to which parsed properties will be appended.
-        :param props_list: list of python dictionaries containing valid v1.0 odML
-                           Properties.
-        """
-        for curr_prop in props_list:
-            prop = ET.Element("property")
-            for element in curr_prop:
-                if element == 'values':
-                    cls._parse_dict_values(prop, curr_prop['values'])
-                elif element:
-                    elem = ET.Element(element)
-                    elem.text = curr_prop[element]
-                    prop.append(elem)
-
-            parent_element.append(prop)
-
-    @staticmethod
-    def _parse_dict_values(parent_element, value_list):
-        """
-        _parse_dict_values parses a list containing python dictionaries of v1.0 odML
-        style values into lxml.Element XML equivalents and appends the parsed
-        Values to the provided lxml.Element parent.
-        :param parent_element: lxml.Element to which parsed values will be appended.
-        :param value_list: list of python dictionaries containing valid v1.0 odML Values.
-        """
-        for value in value_list:
-            val = ET.Element("value")
-            for element in value:
-                if element:
-                    if element == 'value':
-                        val.text = str(value[element])
-                    else:
-                        elem = ET.Element(element)
-                        elem.text = str(value[element])
-                        val.append(elem)
-
-            parent_element.append(val)
-
-    def _convert(self, tree):
-        """
-        Converts an lxml.ElementTree containing a v1.0 odML document to odML v1.1.
-        Unites multiple value objects and moves all supported Value elements to
-        its parent Property. Exports only Document, Section and Property elements,
-        that are supported by odML v1.1.
-        """
-        # Reset status messages
-        self.conversion_log = []
-
-        tree = self._replace_same_name_entities(tree)
-        root = tree.getroot()
-        root.set("version", FORMAT_VERSION)
-
-        # Handle Values, exclude unsupported Property attributes and unnamed Properties.
-        self._handle_properties(root)
-
-        # Exclude unsupported Section attributes, ignore comments, handle repositories.
-        for sec in root.iter("section"):
-            sec_name = sec.find("name").text
-            for e in sec:
-                if e.tag not in format.Section.arguments_keys and isinstance(e.tag, str):
-                    self._log("[Info] Omitted non-Section attribute "
-                              "'%s: %s/%s'" % (sec_name, e.tag, e.text))
-                    sec.remove(e)
-                    continue
-
-                if e.tag == "repository":
-                    self._handle_repository(e)
-                elif e.tag == "include":
-                    self._handle_include(e)
-
-        # Exclude unsupported Document attributes, ignore comments, handle repositories.
-        for e in root:
-            if e.tag not in format.Document.arguments_keys and isinstance(e.tag, str):
-                self._log("[Info] Omitted non-Document "
-                          "attribute '%s/%s'" % (e.tag, e.text))
-                root.remove(e)
-                continue
-
-            if e.tag == "repository":
-                self._handle_repository(e)
-
-        tree = self._check_add_ids(tree)
-
-        return tree
-
-    def _handle_include(self, element):
-        """
-        _handle_include checks whether a provided include element is
-        v1.1 compatible and logs a warning message otherwise.
-        :param element: lxml element containing the provided include link.
-        """
-        content = element.text
-        cache = {}
-        term_handler = Terminologies(cache)
-        term = term_handler.load(element.text)
-
-        # If the include url can be loaded and parsed, everything is fine.
-        if term is not None:
-            return
-
-        # If the include url is a v1.0 odml-terminology one,
-        # check whether a v1.1 is available and use it instead.
-        if '/'.join([REPOSITORY_BASE, "v1.0"]) in element.text:
-            element.text = element.text.replace('v1.0', 'v1.1')
-            term = term_handler.load(element.text)
-
-            if term is not None:
-                msg = "[Info] Replaced Section.include url '%s' with '%s'." \
-                      % (content, element.text)
-                self._log(msg)
-                return
-
-        # Log a warning, if no v1.1 compatible url can be provided.
-        self._log("[Warning] Section include file '%s' "
-                  "is not odML v1.1 compatible." % content)
-
-    def _handle_repository(self, element):
-        """
-        The method handles provided odML repositories.
-        :param element: lxml element containing the provided odML repository link.
-        """
-        content = element.text
-        cache = {}
-        term_handler = Terminologies(cache)
-        term = term_handler.load(element.text)
-
-        # If the repository url can be loaded and parsed, everything is fine.
-        if term is not None:
-            return
-
-        # If the repository url is a v1.0 odml-terminology one,
-        # check whether a v1.1 is available and use it instead.
-        if '/'.join([REPOSITORY_BASE, "v1.0"]) in element.text:
-            element.text = element.text.replace('v1.0', 'v1.1')
-            term = term_handler.load(element.text)
-
-            if term is not None:
-                msg = "[Info] Replaced repository url '%s' with '%s'." \
-                      % (content, element.text)
-                self._log(msg)
-                return
-
-        # Print a warning, if no v1.1 compatible repository url can be provided.
-        self._log("[Warning] Repository file '%s' is not odML v1.1 compatible." % content)
-
-    def _handle_properties(self, root):
-        """
-        Method removes all property elements w/o name attribute, converts Value
-        elements from v1.0 to v1.1 style and removes unsupported Property elements.
-        :param root:
-        """
-        for prop in root.iter("property"):
-            main_val = ET.Element("value")
-            multiple_values = False
-            parent = prop.getparent()
-
-            # If a Property has no name attribute, remove it from its parent and
-            # continue with the next Property.
-            if prop.find("name") is None:
-                self._log("[Warning] Omitted Property without "
-                          "name tag: '%s'" % ET.tostring(prop))
-                parent.remove(prop)
-                continue
-
-            sname = "unnamed"
-            if parent.find("name") is not None:
-                sname = parent.find("name").text
-            stype = "untyped"
-            if parent.find("type") is not None:
-                stype = parent.find("type").text
-            prop_id = "%s|%s:%s" % (sname, stype, prop.find("name").text)
-
-            # Special handling of Values
-            for value in prop.iter("value"):
-                # Move supported elements from Value to parent Property.
-                self._handle_value(value, prop_id)
-
-                if value.text:
-                    if main_val.text:
-                        main_val.text += "," + value.text.strip()
-                        multiple_values = True
-                    else:
-                        main_val.text = value.text.strip()
-
-                prop.remove(value)
-
-            # Append value element only if it contains an actual value
-            if main_val.text:
-                # Multiple values require brackets
-                if multiple_values:
-                    main_val.text = "[" + main_val.text + "]"
-
-                prop.append(main_val)
-
-            # Reverse map "dependency_value", exclude unsupported Property attributes.
-            for elem in prop:
-                if elem.tag == "dependency_value":
-                    elem.tag = "dependencyvalue"
-
-                if (elem.tag not in format.Property.arguments_keys and
-                        isinstance(elem.tag, str)):
-                    self._log("[Info] Omitted non-Property attribute "
-                              "'%s: %s/%s'" % (prop_id, elem.tag, elem.text))
-                    prop.remove(elem)
-
-    def _handle_value(self, value, log_id):
-        """
-        Values changed from odML v1.0 to v1.1. This function moves all supported
-        odML Property elements from a v1.0 Value element to the parent Property element.
-        Adds a log entry for every non-exported element.
-        :param value: etree element containing the v1.0 Value.
-        :param log_id: String containing Section and Property name and type to log
-                       omitted elements and value contents.
-        """
-        for val_elem in value.iter():
-            if val_elem.tag != "value":
-                # Check whether current Value attribute has already been exported
-                # under its own or a different name. Give a warning, if the values differ.
-                parent = value.getparent()
-                if val_elem.tag in self._version_map:
-                    check_export = parent.find(self._version_map[val_elem.tag])
-                else:
-                    check_export = parent.find(val_elem.tag)
-
-                if check_export is not None:
-                    if check_export.text != val_elem.text:
-                        self._log("[Warning] Value element '%s: %s/%s' already exported, "
-                                  "omitting further element value '%s'"
-                                  % (log_id, val_elem.tag,
-                                     check_export.text, val_elem.text))
-
-                # Include only supported Property attributes
-                elif val_elem.tag in format.Property.arguments_keys:
-                    new_elem = ET.Element(val_elem.tag)
-                    new_elem.text = val_elem.text
-
-                    if val_elem.tag in ["type", "dtype"] and val_elem.text == "binary":
-                        new_elem.text = "text"
-                        self._log("[Warning] Replacing unsupported value type "
-                                  "'binary' with 'text' (%s)" % log_id)
-
-                    parent.append(new_elem)
-                elif val_elem.tag in self._version_map:
-                    new_elem = ET.Element(self._version_map[val_elem.tag])
-                    new_elem.text = val_elem.text
-
-                    if val_elem.tag in ["type", "dtype"] and val_elem.text == "binary":
-                        new_elem.text = "text"
-                        self._log("[Warning] Replacing unsupported value type "
-                                  "'binary' with 'text' (%s)" % log_id)
-
-                    parent.append(new_elem)
-                else:
-                    self._log("[Info] Omitted non-Value attribute '%s: %s/%s'"
-                              % (log_id, val_elem.tag, val_elem.text))
-
-    @classmethod
-    def _replace_same_name_entities(cls, tree):
-        """
-        Changes same section names in the doc by adding <-{index}>
-        to the next section occurrences.
-        :param tree: ElementTree of the doc
-        :return: ElementTree
-        """
-        sec_map = {}
-        prop_map = {}
-        root = tree.getroot()
-        for sec in root.iter("section"):
-
-            sec_name = sec.find("name")
-            if sec_name is not None:
-                cls._change_entity_name(tree, sec_map, sec_name)
-            else:
-                raise Exception("Section attribute name is not specified")
-
-            for prop in sec.iter("property"):
-                if prop.getparent() == sec:
-                    prop_name = prop.find("name")
-                    if prop_name is not None:
-                        cls._change_entity_name(tree, prop_map, prop_name)
-            prop_map.clear()
-        return tree
-
-    @staticmethod
-    def _change_entity_name(tree, elem_map, name):
-        """
-        Adds numbering to identical element names where their odml.Section
-        or odml.Property parents reside on the same level in the tree.
-        :param tree: The element tree containing the 'name' element.
-        :param elem_map: lxml path to occurrence maps of named Sections or Properties.
-        :param name: lxml element containing the name text of a Section or Property.
-        """
-        named_path = "%s:%s" % (tree.getpath(name.getparent().getparent()), name.text)
-        if named_path not in elem_map:
-            elem_map[named_path] = 1
-        else:
-            elem_map[named_path] += 1
-            name.text += "-" + str(elem_map[named_path])
-
-    def _check_add_ids(self, tree):
-        """
-        Checks, whether elements (properties) possess an UUID
-        and adds one in case of absence.
-        :param tree: ElementTree of the doc
-        :return: ElementTree
-        """
-        root = tree.getroot()
-        self._add_id(root)
-        for sec in root.iter("section"):
-            self._add_id(sec)
-            for prop in sec.iter("property"):
-                self._add_id(prop)
-
-        return tree
-
-    @staticmethod
-    def _add_id(element):
-        """
-        Checks, whether an element possesses an ID. If yes, make sure it has
-        the right format. Otherwise a new UUID is created.
-        :param element: lxml element.
-        """
-        oid = element.find("id")
-        new_id = ET.Element("id")
-        new_id.text = str(uuid.uuid4())
-        if oid is not None:
-            try:
-                if oid.text is not None:
-                    new_id.text = str(uuid.UUID(oid.text))
-            except ValueError as e:
-                print(e)
-            element.remove(oid)
-        element.append(new_id)
-
-    def _log(self, msg):
-        """
-        Adds the passed message to the conversion_log attribute and
-        prints the message to the command line.
-        """
-        self.conversion_log.append(msg)
-        print(msg)
-
-    def __str__(self):
-        tree = self.convert()
-        return ET.tounicode(tree, pretty_print=True) if tree else ""
-
-    def __unicode__(self):
-        tree = self.convert()
-        return ET.tounicode(tree, pretty_print=True) if tree else ""
-
-    def convert(self, backend="XML"):
-        """
-        This method returns the content of the provided file object converted
-        to odML version 1.1 as a string object which is directly consumable
-        by the odml.tools.ODMLReader.
-        """
-        if backend.upper() == "JSON":
-            old_tree = self._parse_json()
-        elif backend.upper() == "YAML":
-            old_tree = self._parse_yaml()
-        elif backend.upper() == "XML":
-            old_tree = self._parse_xml()
-        else:
-            raise Exception("Unknown backend, only XML, JSON and YAML are supported.")
-
-        tree = self._convert(old_tree)
-        return ET.tounicode(tree, pretty_print=True) if tree else ""
-
-    def write_to_file(self, filename, backend="XML"):
-        """
-        This method converts the content of the provided converter file object
-        to odML version 1.1 and writes the results to `filename`.
-        :param filename: Output file.
-        :param backend: Format of the source file, default is XML.
-        """
-        data = self.convert(backend)
-        if sys.version_info < (3,):
-            data = data.encode('utf-8')
-
-        ext = [".xml", ".odml"]
-        if not filename.endswith(tuple(ext)):
-            filename = "%s.xml" % filename
-
-        if data and "<odML " in data:
-            with open(filename, "w") as file:
-                file.write('<?xml version="1.0" encoding="UTF-8"?>\n')
-                file.write(data)
+print("[DEPRECATION WARNING] The VersionConverter file has been moved to "
+      "'odml.tools.converters' and will be removed from 'odml.tools' in future "
+      "odML releases. Please update the imports in your code accordingly.")
diff --git a/odml/tools/xmlparser.py b/odml/tools/xmlparser.py
index 1ecea9c..959959d 100644
--- a/odml/tools/xmlparser.py
+++ b/odml/tools/xmlparser.py
@@ -182,7 +182,8 @@ class XMLReader(object):
                                   "in <odML> tag.\n")
         elif root.attrib['version'] != FORMAT_VERSION:
             msg = ("Cannot parse odML document with format version '%s'. \n"
-                   "\tUse the 'tools.VersionConverter' to import previous odML formats."
+                   "\tUse the 'VersionConverter' from 'odml.tools.converters' "
+                   "to import previous odML formats."
                    % root.attrib['version'])
             raise InvalidVersionException(msg)
 
diff --git a/setup.py b/setup.py
index 5918378..c22f666 100644
--- a/setup.py
+++ b/setup.py
@@ -21,8 +21,10 @@ CLASSIFIERS = infodict["CLASSIFIERS"]
 
 packages = [
     'odml',
+    'odml.rdf',
+    'odml.scripts',
     'odml.tools',
-    'odml.scripts'
+    'odml.tools.converters'
 ]
 
 with open('README.md') as f:

version converter incorrect hint
When trying to load an odml file version 1.0 with odml version 1.4.2 the resulting error message states 
```
odml.tools.parser_utils.InvalidVersionException: Cannot parse odML document with format version '1'. 
	Use the 'tools.VersionConverter' to import previous odML formats.
```
However, the version converter can not be used as described above, but needs to be explicitely imported from the submodule:
```python
from odml.tools.version_converter import VersionConverter
```
Probably the VersionConverter should be linked in the `odml.tools.__init__.py`?
diff --git a/test/test_format_converter.py b/test/test_format_converter.py
index 515861e..589cdfa 100644
--- a/test/test_format_converter.py
+++ b/test/test_format_converter.py
@@ -3,7 +3,7 @@ import tempfile
 import unittest
 from contextlib import contextmanager
 
-from odml.tools.format_converter import FormatConverter
+from odml.tools.converters import FormatConverter
 
 FC = FormatConverter
 
diff --git a/test/test_version_converter.py b/test/test_version_converter.py
index 8b166e4..49dc088 100644
--- a/test/test_version_converter.py
+++ b/test/test_version_converter.py
@@ -13,7 +13,7 @@ except ImportError:
 from contextlib import contextmanager
 from lxml import etree as ET
 from odml.terminology import REPOSITORY_BASE
-from odml.tools.version_converter import VersionConverter
+from odml.tools.converters import VersionConverter
 
 try:
     unicode = unicode
diff --git a/test/test_version_converter_integration.py b/test/test_version_converter_integration.py
index 7f489cb..ebeac0f 100644
--- a/test/test_version_converter_integration.py
+++ b/test/test_version_converter_integration.py
@@ -9,7 +9,7 @@ import tempfile
 import unittest
 
 from odml import load
-from odml.tools.version_converter import VersionConverter as VC
+from odml.tools.converters import VersionConverter as VC
 
 
 class TestVersionConverterIntegration(unittest.TestCase):

pip install -e .
parse_log_pytest
requirements.txt
pytest
apt-get update apt-get install -y gcc libxml2-dev libxslt1-dev lib32z1-dev
3.9
requirements/base.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
docopt==0.6.2
exceptiongroup==1.2.2
iniconfig==2.1.0
isodate==0.7.2
lxml==5.3.1
-e git+https://github.com/G-Node/python-odml.git@db48012eb320eda27de66b1822509827f7bb6521#egg=odML
packaging==24.2
pathlib==1.0.1
pluggy==1.5.0
pyparsing==3.2.3
pytest==8.3.5
PyYAML==4.2b4
rdflib==7.1.4
tomli==2.2.1

name: python-odml
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - docopt==0.6.2
      - exceptiongroup==1.2.2
      - iniconfig==2.1.0
      - isodate==0.7.2
      - lxml==5.3.1
      - packaging==24.2
      - pathlib==1.0.1
      - pluggy==1.5.0
      - pyparsing==3.2.3
      - pytest==8.3.5
      - pyyaml==4.2b4
      - rdflib==7.1.4
      - tomli==2.2.1
prefix: /opt/conda/envs/python-odml

test/test_format_converter.py::TestFormatConverter::test_check_io_directory test/test_format_converter.py::TestFormatConverter::test_convert test/test_format_converter.py::TestFormatConverter::test_convert_dir test/test_format_converter.py::TestFormatConverter::test_convert_dir_no_output_dir test/test_format_converter.py::TestFormatConverter::test_convert_dir_with_output_dir_specified test/test_version_converter.py::TestVersionConverter::test_convert_json_file test/test_version_converter.py::TestVersionConverter::test_convert_odml_file test/test_version_converter.py::TestVersionConverter::test_convert_odml_file_document test/test_version_converter.py::TestVersionConverter::test_convert_odml_file_property test/test_version_converter.py::TestVersionConverter::test_convert_odml_file_section test/test_version_converter.py::TestVersionConverter::test_convert_odml_file_value test/test_version_converter.py::TestVersionConverter::test_convert_xml_file test/test_version_converter.py::TestVersionConverter::test_convert_yaml_file test/test_version_converter.py::TestVersionConverter::test_handle_include test/test_version_converter.py::TestVersionConverter::test_handle_repository test/test_version_converter.py::TestVersionConverter::test_parse_dict_document test/test_version_converter.py::TestVersionConverter::test_parse_dict_properties test/test_version_converter.py::TestVersionConverter::test_parse_dict_sections test/test_version_converter.py::TestVersionConverter::test_parse_dict_values test/test_version_converter.py::TestVersionConverter::test_replace_same_name_entites test/test_version_converter.py::TestVersionConverter::test_write_to_file test/test_version_converter_integration.py::TestVersionConverterIntegration::test_convert_json test/test_version_converter_integration.py::TestVersionConverterIntegration::test_convert_xml test/test_version_converter_integration.py::TestVersionConverterIntegration::test_convert_yaml
doc/tools.rst odml/tools/query_creator.py odml/scripts/odml_to_rdf.py odml/tools/converters/version_converter.py setup.py odml/tools/dict_parser.py odml/tools/rdf_converter.py odml/tools/fuzzy_finder.py odml/tools/format_converter.py odml/tools/utils.py odml/tools/parser_utils.py odml/tools/xmlparser.py odml/tools/converters/__init__.py appveyor.yml odml/tools/__init__.py odml/rdf/__init__.py odml/scripts/odml_convert.py odml/tools/version_converter.py
doc/tools.rst odml/scripts/odml_to_rdf.py odml/tools/converters/version_converter.py odml/tools/version_converter.py odml/tools/dict_parser.py odml/tools/rdf_converter.py setup.py odml/rdf/fuzzy_finder.py odml/tools/utils.py odml/tools/parser_utils.py odml/tools/xmlparser.py odml/tools/converters/__init__.py appveyor.yml odml/tools/__init__.py odml/rdf/__init__.py odml/rdf/query_creator.py odml/scripts/odml_convert.py odml/tools/converters/format_converter.py