diff --git a/BaseLib/ConfigTreeNew-impl.h b/BaseLib/ConfigTreeNew-impl.h
index 8fb48906aea467a66ff739e6d4f81f5be733bf3d..41ea3f9dc7c2509fa7fb2036f97a63aebe3b302d 100644
--- a/BaseLib/ConfigTreeNew-impl.h
+++ b/BaseLib/ConfigTreeNew-impl.h
@@ -35,11 +35,10 @@ T
 ConfigTreeNew::
 getConfParam(std::string const& param) const
 {
-    auto p = getConfParamOptional<T>(param);
-    if (p) return *p;
+    if (auto p = getConfParamOptional<T>(param))
+        return *p;
 
     error("Key <" + param + "> has not been found");
-    return T();
 }
 
 template<typename T>
@@ -47,8 +46,9 @@ T
 ConfigTreeNew::
 getConfParam(std::string const& param, T const& default_value) const
 {
-    auto p = getConfParamOptional<T>(param);
-    if (p) return *p;
+    if (auto p = getConfParamOptional<T>(param))
+        return *p;
+
     return default_value;
 }
 
@@ -58,20 +58,9 @@ ConfigTreeNew::
 getConfParamOptional(std::string const& param) const
 {
     checkUnique(param);
-    auto p = _tree->get_child_optional(param);
 
-    bool peek_only = p == boost::none;
-    markVisited<T>(param, peek_only);
-
-    if (p) {
-        auto v = p->get_value_optional<T>();
-        if (v) {
-            return v;
-        } else {
-            error("Value for key <" + param + "> `" + shortString(p->data())
-                  + "' not convertible to the desired type.");
-        }
-    }
+    if (auto p = getConfSubtreeOptional(param))
+        return p->getValue<T>();
 
     return boost::none;
 }
@@ -97,20 +86,16 @@ peekConfParam(std::string const& param) const
 {
     checkKeyname(param);
 
-    auto p =_tree->get_child_optional(param);
-
-    if (!p) {
-        error("Key <" + param + "> has not been found");
-    } else {
+    if (auto p =_tree->get_child_optional(param)) {
         try {
             return p->get_value<T>();
         } catch (boost::property_tree::ptree_bad_data) {
             error("Value for key <" + param + "> `" + shortString(p->data())
                   + "' not convertible to the desired type.");
         }
+    } else {
+        error("Key <" + param + "> has not been found");
     }
-
-    return T();
 }
 
 template<typename T>
@@ -133,11 +118,55 @@ checkConfParam(std::string const& param, Ch const* value) const
     }
 }
 
+template<typename T>
+T
+ConfigTreeNew::
+getValue() const
+{
+    // TODO test this
+    if (_have_read_data) {
+        error("The data of this subtree has already been read.");
+    }
+
+    _have_read_data = true;
+
+    if (auto v = _tree->get_value_optional<T>()) {
+        return *v;
+    } else {
+        error("Value `" + shortString(_tree->data())
+              + "' is not convertible to the desired type.");
+    }
+}
+
+template<typename T>
+T
+ConfigTreeNew::
+getAttribute(std::string const& attr) const
+{
+    checkUniqueAttr(attr);
+    markVisited(attr, true);
+
+    if (auto attrs = _tree->get_child_optional("<xmlattr>")) {
+        if (auto a = attrs->get_child_optional(attr)) {
+            if (auto v = a->get_value_optional<T>()) {
+                return *v;
+            } else {
+                error("Value for XML attribute \"" + attr + "\" `"
+                      + shortString(a->data())
+                      + "' not convertible to the desired type.");
+            }
+        } else {
+            error("No XML attribute named \"" + attr + "\"");
+        }
+    } else {
+        error("This parameter has no XML attributes");
+    }
+}
 
 template<typename T>
 ConfigTreeNew::CountType&
 ConfigTreeNew::
-markVisited(std::string const& key, bool peek_only) const
+markVisited(std::string const& key, bool const peek_only) const
 {
     auto const type = std::type_index(typeid(T));
 
diff --git a/BaseLib/ConfigTreeNew.cpp b/BaseLib/ConfigTreeNew.cpp
index 57b16ed0a0090cec2ece05a1a31d7c73e10ce7cd..c5da6e1606677d6a8e7f97f661f97297de6facef 100644
--- a/BaseLib/ConfigTreeNew.cpp
+++ b/BaseLib/ConfigTreeNew.cpp
@@ -43,11 +43,12 @@ ConfigTreeNew(PTree const& tree, ConfigTreeNew const& parent,
 
 ConfigTreeNew::
 ConfigTreeNew(ConfigTreeNew && other)
-    : _tree(other._tree)
-    , _path(other._path)
+    : _tree                    (other._tree)
+    , _path          (std::move(other._path))
     , _visited_params(std::move(other._visited_params))
-    , _onerror(other._onerror)
-    , _onwarning(other._onwarning)
+    , _have_read_data          (other._have_read_data)
+    , _onerror       (std::move(other._onerror))
+    , _onwarning     (std::move(other._onwarning))
 {
     other._tree = nullptr;
 }
@@ -67,12 +68,23 @@ operator=(ConfigTreeNew&& other)
     other._tree     = nullptr;
     _path           = std::move(other._path);
     _visited_params = std::move(other._visited_params);
+    _have_read_data = other._have_read_data;
     _onerror        = std::move(other._onerror);
     _onwarning      = std::move(other._onwarning);
 
     return *this;
 }
 
+ConfigTreeNew
+ConfigTreeNew::
+getConfParam(std::string const& root) const
+{
+    auto ct = getConfSubtree(root);
+    if (hasChildren(ct))
+        error("Requested parameter <" + root + "> actually is a subtree.");
+    return ct;
+}
+
 ConfigTreeNew
 ConfigTreeNew::
 getConfSubtree(std::string const& root) const
@@ -81,7 +93,6 @@ getConfSubtree(std::string const& root) const
         return std::move(*t);
     } else {
         error("Key <" + root + "> has not been found.");
-        return ConfigTreeNew(PTree(), *this, ""); // TODO that will crash
     }
 }
 
@@ -90,14 +101,13 @@ ConfigTreeNew::
 getConfSubtreeOptional(std::string const& root) const
 {
     checkUnique(root);
-    auto subtree = _tree->get_child_optional(root);
 
-    if (subtree) {
-        markVisited(root);
+    if (auto subtree = _tree->get_child_optional(root)) {
+        markVisited(root, false);
         return ConfigTreeNew(*subtree, *this, root);
     } else {
         markVisited(root, true);
-        return boost::optional<ConfigTreeNew>();
+        return boost::none;
     }
 }
 
@@ -138,6 +148,7 @@ void ConfigTreeNew::ignoreConfParamAll(const std::string &param) const
 void ConfigTreeNew::error(const std::string& message) const
 {
     _onerror(_path, message);
+    std::abort();
 }
 
 void ConfigTreeNew::warning(const std::string& message) const
@@ -175,6 +186,12 @@ void ConfigTreeNew::checkKeyname(std::string const& key) const
         error("Key <" + key + "> starts with an illegal character.");
     } else if (key.find_first_not_of(key_chars, 1) != std::string::npos) {
         error("Key <" + key + "> contains illegal characters.");
+    } else if (key.find("__") != std::string::npos) {
+        // This is illegal because we use parameter names to generate doxygen
+        // page names. Thereby "__" acts as a separator character. Choosing
+        // other separators is not possible because of observed limitations
+        // for valid doxygen page names.
+        error("Key <" + key + "> contains double underscore.");
     }
 }
 
@@ -199,9 +216,18 @@ void ConfigTreeNew::checkUnique(const std::string &key) const
     }
 }
 
+void ConfigTreeNew::checkUniqueAttr(const std::string &attr) const
+{
+    checkKeyname(attr);
+
+    if (_visited_params.find("<xmlattr>." + attr) != _visited_params.end()) {
+        error("Attribute \"" + attr + "\" has already been processed.");
+    }
+}
+
 ConfigTreeNew::CountType&
 ConfigTreeNew::
-markVisited(std::string const& key, bool peek_only) const
+markVisited(std::string const& key, bool const peek_only) const
 {
     return markVisited<ConfigTreeNew>(key, peek_only);
 }
@@ -220,18 +246,48 @@ markVisitedDecrement(std::string const& key) const
     }
 }
 
+bool
+ConfigTreeNew::hasChildren(ConfigTreeNew const& ct) const
+{
+    auto const& tree = *ct._tree;
+    if (tree.begin() == tree.end())
+        return false; // no children
+    if (tree.front().first == "<xmlattr>"
+        && (++tree.begin()) == tree.end())
+        return false; // only attributes
+
+    return true;
+}
+
 void
 ConfigTreeNew::checkAndInvalidate()
 {
     if (!_tree) return;
 
-    for (auto const& p : *_tree)
-    {
-        markVisitedDecrement(p.first);
+    // Note: due to a limitation in boost::property_tree it is not possible
+    // to discriminate between <tag></tag> and <tag/> in the input file.
+    // In both cases data() will be empty.
+    if ((!_have_read_data) && !_tree->data().empty()) {
+        warning("The immediate data `" + shortString(_tree->data())
+                +"' of this tag has not been read.");
+    }
+
+    // iterate over children
+    for (auto const& p : *_tree) {
+        DBUG("-- %s <%s> ", _path.c_str(), p.first.c_str());
+        if (p.first != "<xmlattr>") // attributes are handled below
+            markVisitedDecrement(p.first);
+    }
+
+    // iterate over attributes
+    if (auto attrs = _tree->get_child_optional("<xmlattr>")) {
+        for (auto const& p : *attrs) {
+            markVisitedDecrement("<xmlattr>." + p.first);
+            // markVisitedDecrement("<xmlattr>");
+        }
     }
 
-    for (auto const& p : _visited_params)
-    {
+    for (auto const& p : _visited_params) {
         if (p.second.count > 0) {
             warning("Key <" + p.first + "> has been read " + std::to_string(p.second.count)
                     + " time(s) more than it was present in the configuration tree.");
diff --git a/BaseLib/ConfigTreeNew.h b/BaseLib/ConfigTreeNew.h
index 66e553f4b564fe7b9e7a64a46bc4a6799cc51f65..1cc7a6ae835ebf8b0b87b12a33dcadfc12737f55 100644
--- a/BaseLib/ConfigTreeNew.h
+++ b/BaseLib/ConfigTreeNew.h
@@ -62,6 +62,9 @@ template<typename Iterator> class Range;
  * possible to read from this class, which configuration parameters are present in the tree.
  * This restriction, however, is intended, because it provides the possibility to get all
  * existing configuration parameters from the source code.
+ *
+ * \todo add usage description
+ *
  */
 class ConfigTreeNew final
 {
@@ -80,7 +83,7 @@ public:
 
         explicit SubtreeIterator(Iterator it, std::string const& root,
                                  ConfigTreeNew const& parent)
-            : _it(it), _root(root), _parent(parent)
+            : _it(it), _tagname(root), _parent(parent)
         {}
 
         SubtreeIterator& operator++() {
@@ -94,9 +97,9 @@ public:
             // tell the _parent instance that a subtree now has been parsed.
             if (_has_incremented) {
                 _has_incremented = false;
-                _parent.markVisited(_root);
+                _parent.markVisited(_tagname, false);
             }
-            return ConfigTreeNew(_it->second, _parent, _root);
+            return ConfigTreeNew(_it->second, _parent, _tagname);
         }
 
         bool operator==(SubtreeIterator const& other) const {
@@ -110,7 +113,7 @@ public:
     private:
         bool _has_incremented = true;
         Iterator _it;
-        std::string const _root;
+        std::string const _tagname;
         ConfigTreeNew const& _parent;
     };
 
@@ -130,7 +133,7 @@ public:
 
         explicit ValueIterator(Iterator it, std::string const& root,
                                ConfigTreeNew const& parent)
-            : _it(it), _root(root), _parent(parent)
+            : _it(it), _tagname(root), _parent(parent)
         {}
 
         ValueIterator<ValueType>& operator++() {
@@ -144,21 +147,22 @@ public:
             // tell the _parent instance that a setting now has been parsed.
             if (_has_incremented) {
                 _has_incremented = false;
-                _parent.markVisited<ValueType>(_root);
+                _parent.markVisited<ValueType>(_tagname, false);
             }
 
             if (_it->second.begin() != _it->second.end()) {
-                _parent.error("Configuration at key " + _root + " has subitems.");
-                return ValueType();
+                // TODO test
+                _parent.error("Configuration at key " + _tagname + " has subitems.");
+                // TODO what about attributes?
             }
 
-            auto v = _it->second.get_value_optional<ValueType>();
-
-            if (v) return *v;
+            // TODO maybe better make complete ConfigTree
+            if (auto v = _it->second.get_value_optional<ValueType>())
+                return *v;
 
             // TODO: change error method
-            _parent.error("Could not get value out of key " + _root + ".");
-            return ValueType();
+            // TODO test
+            _parent.error("Could not get value out of key " + _tagname + ".");
         }
 
         bool operator==(ValueIterator<ValueType> const& other) const {
@@ -172,7 +176,7 @@ public:
     private:
         bool _has_incremented = true;
         Iterator _it;
-        std::string const _root;
+        std::string const _tagname;
         ConfigTreeNew const& _parent;
     };
 
@@ -261,6 +265,26 @@ public:
     template<typename T> Range<ValueIterator<T> >
     getConfParamList(std::string const& param) const;
 
+    //! TODO doc
+    ConfigTreeNew
+    getConfParam(std::string const& param) const;
+
+    //! TODO doc
+    boost::optional<ConfigTreeNew>
+    getConfParamOptional(std::string const& param) const;
+
+    //! TODO doc
+    Range<SubtreeIterator>
+    getConfParamList(std::string const& param) const;
+
+    //! TODO doc
+    template<typename T> T
+    getValue() const;
+
+    //! TODO doc
+    template<typename T> T
+    getAttribute(std::string const& attr) const;
+
     /*! Peek at a parameter \c param of type \c T from the configuration tree.
      *
      * This method is an exception to the single-read rule. It is meant to be used to
@@ -347,7 +371,7 @@ private:
 
     //! Called if an error occurs. Will call the error callback.
     //! This method only acts as a helper method.
-    void error(std::string const& message) const;
+    [[noreturn]] void error(std::string const& message) const;
 
     //! Called for printing warning messages. Will call the warning callback.
     //! This method only acts as a helper method.
@@ -362,6 +386,9 @@ private:
     //! Asserts that the \c key has not been read yet.
     void checkUnique(std::string const& key) const;
 
+    //! TODO doc
+    void checkUniqueAttr(std::string const& attr) const;
+
     /*! Keeps track of the key \c key and its value type \c T.
      *
      * This method asserts that a key is read always with the same type.
@@ -377,12 +404,15 @@ private:
      *
      * \c param peek_only if true, do not change the read-count of the given key.
      */
-    CountType& markVisited(std::string const& key, bool peek_only = false) const;
+    CountType& markVisited(std::string const& key, bool const peek_only = false) const;
 
     //! Used in the destructor to compute the difference between number of reads of a parameter
     //! and the number of times it exists in the ConfigTree
     void markVisitedDecrement(std::string const& key) const;
 
+    //! TODO doc
+    bool hasChildren(ConfigTreeNew const& ct) const;
+
     /*! Checks if the top level of this tree has been read entirely (and not too often).
      *
      * Caution: This method also invalidates the instance, i.e., afterwards it can not
@@ -399,6 +429,8 @@ private:
     //! A path printed in error/warning messages.
     std::string _path;
 
+    //! \todo add file name
+
     //! A map key -> (count, type) keeping track which parameters have been read how often
     //! and which datatype they have.
     //!
@@ -408,6 +440,9 @@ private:
     //! temporaries.
     mutable std::map<std::string, CountType> _visited_params;
 
+    //! \todo doc
+    mutable bool _have_read_data = false;
+
     Callback _onerror;
     Callback _onwarning;