data tree FEATURE initial implementation of YANG data support
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3404319..91a2ff3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -171,17 +171,27 @@
 
 set(libsrc
     src/common.c
+    src/compat.c
     src/log.c
     src/hash_table.c
     src/set.c
     src/context.c
+    src/tree_data.c
+    src/tree_data_free.c
+    src/tree_data_helpers.c
+    src/tree_data_hash.c
+    src/parser_xml.c
+    src/printer_data.c
+    src/printer_xml.c
     src/tree_schema.c
     src/tree_schema_free.c
     src/tree_schema_compile.c
     src/tree_schema_helpers.c
     src/parser_yang.c
     src/printer.c
+    src/printer_schema.c
     src/printer_yang.c
+    src/plugins_types.c
     src/xml.c
     src/xpath.c)
 
@@ -199,15 +209,20 @@
 set(headers
     src/libyang.h
     src/context.h
+    src/tree.h
+    src/tree_data.h
+    src/printer_data.h
     src/tree_schema.h
     src/printer_schema.h
     src/extensions.h
+    src/plugins_types.h
     src/dict.h
     src/log.h
     src/set.h)
 
 list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
 check_symbol_exists(vdprintf stdio.h HAVE_VDPRINTF)
+check_symbol_exists(strnstr string.h HAVE_STRNSTR)
 
 # create static libyang library
 if(ENABLE_STATIC)
diff --git a/src/common.c b/src/common.c
index a35c72c..5e19200 100644
--- a/src/common.c
+++ b/src/common.c
@@ -16,16 +16,14 @@
 
 #include <assert.h>
 #include <errno.h>
-#include <limits.h>
 #include <stdlib.h>
-#include <stdio.h>
 #include <ctype.h>
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
-#include <sys/types.h>
 #include <unistd.h>
 
+#include "extensions.h"
 #include "tree_schema.h"
 
 const char *const ly_stmt_list[] = {
diff --git a/src/common.h b/src/common.h
index 17b24c1..df65edc 100644
--- a/src/common.h
+++ b/src/common.h
@@ -18,18 +18,21 @@
 #define _DEFAULT_SOURCE
 #define _GNU_SOURCE
 
-#include <assert.h>
+#include <features.h>
 #include <pthread.h>
+#include <stdc-predef.h>
+#include <stddef.h>
 #include <stdint.h>
-#include <stdlib.h>
-#include <unistd.h>
 
 #include "config.h"
-#include "log.h"
+
 #include "context.h"
-#include "tree_schema.h"
-#include "set.h"
+#include "dict.h"
 #include "hash_table.h"
+#include "log.h"
+#include "set.h"
+
+struct ly_ctx;
 
 #if __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__
 # define THREAD_LOCAL _Thread_local
@@ -61,6 +64,19 @@
 #endif
 
 /******************************************************************************
+ * Compatibility functions
+ *****************************************************************************/
+
+#ifndef HAVE_STRNSTR
+/**
+ * @brief Find the first occurrence of find in s, where the search is limited to the
+ * first slen characters of s.
+ */
+char *strnstr(const char *s, const char *find, size_t slen);
+#endif
+
+
+/******************************************************************************
  * Logger
  *****************************************************************************/
 
@@ -85,8 +101,32 @@
 extern volatile uint8_t ly_log_level;
 extern volatile uint8_t ly_log_opts;
 
-void ly_err_free(void *ptr);
+/**
+ * @brief Set error-app-tag to the last error record in the context.
+ * @param[in] ctx libyang context where the error records are present.
+ * @param[in] apptag The error-app-tag value to store.
+ */
+void ly_err_last_set_apptag(const struct ly_ctx *ctx, const char *apptag);
+
+/**
+ * @brief Print a log message and store it into the context (if provided).
+ *
+ * @param[in] ctx libyang context to store the error record. If not provided, the error is just printed.
+ * @param[in] level Log message level (error, warning, etc.)
+ * @param[in] no Error type code.
+ * @param[in] format Format string to print.
+ */
 void ly_log(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, const char *format, ...);
+
+/**
+ * @brief Print Validation error and store it into the context (if provided).
+ *
+ * @param[in] ctx libyang context to store the error record. If not provided, the error is just printed.
+ * @param[in] elem_type Type of the data in @p elem variable.
+ * @param[in] elem Object to provide more information about the place where the error appeared.
+ * @param[in] code Validation error code.
+ * @param[in] format Format string to print.
+ */
 void ly_vlog(const struct ly_ctx *ctx, enum LY_VLOG_ELEM elem_type, const void *elem, LY_VECODE code, const char *format, ...);
 
 #define LOGERR(ctx, errno, str, args...) ly_log(ctx, LY_LLERR, errno, str, ##args)
diff --git a/src/compat.c b/src/compat.c
new file mode 100644
index 0000000..7c4d660
--- /dev/null
+++ b/src/compat.c
@@ -0,0 +1,42 @@
+/**
+ * @file compat.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief Compatibility functions - implemented basic functions which are not available on all the platforms.
+ *
+ * Copyright (c) 2018 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "common.h"
+
+#include <string.h>
+
+#ifndef HAVE_STRNSTR
+
+char *
+strnstr(const char *s, const char *find, size_t slen)
+{
+    char c, sc;
+    size_t len;
+
+    if ((c = *find++) != '\0') {
+        len = strlen(find);
+        do {
+            do {
+                if (slen-- < 1 || (sc = *s++) == '\0')
+                    return (NULL);
+            } while (sc != c);
+            if (len > slen)
+                return (NULL);
+        } while (strncmp(s, find, len) != 0);
+        s--;
+    }
+    return ((char *)s);
+}
+
+#endif
diff --git a/src/config.h.in b/src/config.h.in
index a65de05..3f107d9 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -19,6 +19,8 @@
 
 #cmakedefine HAVE_VDPRINTF
 
+#cmakedefine HAVE_STRNSTR
+
 /**
  * @brief Compiler flag for unused function attributes
  */
diff --git a/src/context.c b/src/context.c
index d3ec7a3..9de0592 100644
--- a/src/context.c
+++ b/src/context.c
@@ -14,17 +14,21 @@
 
 #include "common.h"
 
+#include <assert.h>
 #include <errno.h>
-#include <limits.h>
+#include <pthread.h>
+#include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
-#include <sys/types.h>
 #include <unistd.h>
 
 #include "context.h"
+#include "hash_table.h"
+#include "set.h"
+#include "tree.h"
 #include "tree_schema_internal.h"
-#include "libyang.h"
+#include "plugins_types.h"
 
 #define LY_INTERNAL_MODS_COUNT 6
 
diff --git a/src/context.h b/src/context.h
index 65aa954..cbe027f 100644
--- a/src/context.h
+++ b/src/context.h
@@ -15,6 +15,8 @@
 #ifndef LY_CONTEXT_H_
 #define LY_CONTEXT_H_
 
+#include <stdint.h>
+
 #include "log.h"
 #include "tree_schema.h"
 
diff --git a/src/hash_table.c b/src/hash_table.c
index 11ca8f3..5e48332 100644
--- a/src/hash_table.c
+++ b/src/hash_table.c
@@ -12,14 +12,14 @@
  *     https://opensource.org/licenses/BSD-3-Clause
  */
 
+#include "common.h"
+
 #include <string.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <pthread.h>
 #include <assert.h>
 
-#include "common.h"
-#include "context.h"
 #include "hash_table.h"
 
 static int
diff --git a/src/hash_table.h b/src/hash_table.h
index 70ec695..ac42631 100644
--- a/src/hash_table.h
+++ b/src/hash_table.h
@@ -16,11 +16,13 @@
 #ifndef LY_HASH_TABLE_H_
 #define LY_HASH_TABLE_H_
 
-#include <stdint.h>
-#include <pthread.h>
-
 #include "common.h"
-#include "dict.h"
+
+#include <pthread.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "log.h"
 
 /**
  * @brief Compute hash from (several) string(s).
diff --git a/src/libyang.h b/src/libyang.h
index 7b89268..a702e0b 100644
--- a/src/libyang.h
+++ b/src/libyang.h
@@ -25,8 +25,11 @@
 #include "set.h"
 #include "dict.h"
 #include "context.h"
+#include "tree.h"
+#include "tree_data.h"
 #include "tree_schema.h"
 #include "printer_schema.h"
+#include "printer_data.h"
 
 /**
  * @mainpage About
diff --git a/src/log.c b/src/log.c
index b576437..b600b62 100644
--- a/src/log.c
+++ b/src/log.c
@@ -16,11 +16,14 @@
 
 #include <assert.h>
 #include <inttypes.h>
+#include <pthread.h>
 #include <stdarg.h>
+#include <stdint.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
-#include "libyang.h"
-#include "context.h"
+#include "log.h"
 
 THREAD_LOCAL enum int_log_opts log_opt;
 volatile uint8_t ly_log_level = LY_LLWRN;
@@ -106,6 +109,27 @@
 }
 
 API struct ly_err_item *
+ly_err_new(LY_LOG_LEVEL level, LY_ERR no, LY_VECODE vecode, char *msg, char *path, char *apptag)
+{
+    struct ly_err_item *eitem;
+
+    eitem = malloc(sizeof *eitem);
+    LY_CHECK_ERR_RET(!eitem, LOGMEM(NULL), NULL);
+    eitem->prev = eitem;
+    eitem->next = NULL;
+
+    /* fill in the information */
+    eitem->level = level;
+    eitem->no = no;
+    eitem->vecode = vecode;
+    eitem->msg = msg;
+    eitem->path = path;
+    eitem->apptag = apptag;
+
+    return eitem;
+}
+
+API struct ly_err_item *
 ly_err_first(const struct ly_ctx *ctx)
 {
     LY_CHECK_ARG_RET(NULL, ctx, NULL);
@@ -113,7 +137,7 @@
     return pthread_getspecific(ctx->errlist_key);
 }
 
-void
+API void
 ly_err_free(void *ptr)
 {
     struct ly_err_item *i, *next;
@@ -454,3 +478,16 @@
     }
 }
 
+void
+ly_err_last_set_apptag(const struct ly_ctx *ctx, const char *apptag)
+{
+    struct ly_err_item *i;
+
+    if (log_opt != ILO_IGNORE) {
+        i = ly_err_first(ctx);
+        if (i) {
+            i = i->prev;
+            i->apptag = strdup(apptag);
+        }
+    }
+}
diff --git a/src/log.h b/src/log.h
index 0074d83..920cd9e 100644
--- a/src/log.h
+++ b/src/log.h
@@ -166,7 +166,9 @@
     LYVE_SYNTAX_YANG,  /**< YANG-related syntax error */
     LYVE_REFERENCE,    /**< invalid referencing or using an item */
     LYVE_XPATH,        /**< invalid XPath expression */
-    LYVE_SEMANTICS     /**< generic semantic error */
+    LYVE_SEMANTICS,    /**< generic semantic error */
+    LYVE_SYNTAX_XML,   /**< XML-related syntax error */
+    LYVE_RESTRICTION   /**< YANG data does not reflect some of the module restrictions */
 } LY_VECODE;
 
 /**
diff --git a/src/parser_xml.c b/src/parser_xml.c
new file mode 100644
index 0000000..cdc8111
--- /dev/null
+++ b/src/parser_xml.c
@@ -0,0 +1,273 @@
+/**
+ * @file parser_xml.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief XML data parser for libyang
+ *
+ * Copyright (c) 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "common.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "context.h"
+#include "dict.h"
+#include "log.h"
+#include "plugins_types.h"
+#include "set.h"
+#include "tree_data.h"
+#include "tree_data_internal.h"
+#include "tree_schema.h"
+#include "xml.h"
+
+/**
+ * @brief internal context for XML YANG data parser.
+ *
+ * The leading part is compatible with the struct lyxml_context
+ */
+struct lyd_xml_ctx {
+    struct ly_ctx *ctx;              /**< libyang context */
+    uint64_t line;                   /**< number of the line being currently processed */
+    enum LYXML_PARSER_STATUS status; /**< status providing information about the next expected object in input data */
+    struct ly_set elements;          /**< list of not-yet-closed elements */
+    struct ly_set ns;                /**< handled with LY_SET_OPT_USEASLIST */
+
+    uint16_t options;                /**< various @ref dataparseroptions. */
+    uint16_t path_len;               /**< used bytes in the path buffer */
+#define LYD_PARSER_BUFSIZE 4078
+    char path[LYD_PARSER_BUFSIZE];   /**< buffer for the generated path */
+};
+
+/**
+ * @brief Parse XML attributes of the XML element of YANG data.
+ *
+ * @param[in] ctx XML YANG data parser context.
+ * @param[in] element_name Element identifier to distinguish namespaces defined in different elements.
+ * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
+ * @param[out] attributes Resulting list of the parsed attributes. XML namespace definitions are not parsed
+ * as attributes, they are stored internally in the parser context.
+ * @reutn LY_ERR value.
+ */
+static LY_ERR
+lydxml_attributes(struct lyd_xml_ctx *ctx, const char *element_name, const char **data, struct lyd_attr **attributes)
+{
+    LY_ERR ret = LY_SUCCESS;
+    unsigned int u;
+    const char *prefix, *name;
+    size_t prefix_len, name_len;
+    struct lyd_attr *attr = NULL, *last = NULL;
+    const struct lyxml_ns *ns;
+    struct ly_set attr_prefixes = {0};
+    struct attr_prefix_s {
+        const char *prefix;
+        size_t prefix_len;
+    } *attr_prefix;
+    struct lys_module *mod;
+
+    while(ctx->status == LYXML_ATTRIBUTE &&
+            lyxml_get_attribute((struct lyxml_context*)ctx, data, &prefix, &prefix_len, &name, &name_len) == LY_SUCCESS) {
+        int dynamic = 0;
+        char *buffer = NULL, *value;
+        size_t buffer_size = 0, value_len;
+
+        lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
+
+        if (prefix_len == 5 && !strncmp(prefix, "xmlns", 5)) {
+            /* named namespace */
+            lyxml_ns_add((struct lyxml_context *)ctx, element_name, name, name_len,
+                         dynamic ? value : strndup(value, value_len));
+        } else if (!prefix && name_len == 5 && !strncmp(name, "xmlns", 5)) {
+            /* default namespace */
+            lyxml_ns_add((struct lyxml_context *)ctx, element_name, NULL, 0,
+                         dynamic ? value : strndup(value, value_len));
+        } else {
+            /* attribute */
+            attr = calloc(1, sizeof *attr);
+            LY_CHECK_ERR_GOTO(!attr, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
+
+            attr->name = lydict_insert(ctx->ctx, name, name_len);
+            /* auxiliary store the prefix information and wait with resolving prefix to the time when all the namespaces,
+             * defined in this element, are parsed, so we will get the correct namespace for this prefix */
+            attr_prefix = malloc(sizeof *attr_prefix);
+            attr_prefix->prefix = prefix;
+            attr_prefix->prefix_len = prefix_len;
+            ly_set_add(&attr_prefixes, attr_prefix, LY_SET_OPT_USEASLIST);
+
+            /* TODO process value */
+
+            if (last) {
+                last->next = attr;
+            } else {
+                (*attributes) = attr;
+            }
+            last = attr;
+        }
+    }
+
+    /* resolve annotation pointers in all the attributes */
+    for (last = *attributes, u = 0; u < attr_prefixes.count && last; u++, last = last->next) {
+        attr_prefix = (struct attr_prefix_s*)attr_prefixes.objs[u];
+        ns = lyxml_ns_get((struct lyxml_context *)ctx, attr_prefix->prefix, attr_prefix->prefix_len);
+        mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
+
+        /* TODO get annotation */
+    }
+
+cleanup:
+
+    ly_set_erase(&attr_prefixes, free);
+    return ret;
+}
+
+/**
+ * @brief Parse XML elements as children YANG data node of the specified parent node.
+ *
+ * @param[in] ctx XML YANG data parser context.
+ * @param[in] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
+ * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
+ * @param[out] node Resulting list of the parsed nodes.
+ * @reutn LY_ERR value.
+ */
+static LY_ERR
+lydxml_nodes(struct lyd_xml_ctx *ctx, struct lyd_node_inner *parent, const char **data, struct lyd_node **node)
+{
+    LY_ERR ret = LY_SUCCESS;
+    const char *prefix, *name;
+    char *element_name = NULL;
+    size_t prefix_len, name_len;
+    struct lyd_attr *attributes = NULL;
+    const struct lyxml_ns *ns;
+    const struct lysc_node *snode;
+    struct lys_module *mod;
+    unsigned int parents_count = ctx->elements.count;
+    struct lyd_node *cur = NULL, *prev = NULL;
+
+    (*node) = NULL;
+
+    while(ctx->status == LYXML_ELEMENT) {
+        ret = lyxml_get_element((struct lyxml_context *)ctx, data, &prefix, &prefix_len, &name, &name_len);
+        LY_CHECK_GOTO(ret, cleanup);
+        if (!name) {
+            /* closing previous element */
+            lyxml_ns_rm((struct lyxml_context *)ctx, element_name);
+            free(element_name);
+            element_name = NULL;
+            if (ctx->elements.count < parents_count) {
+                /* all siblings parsed */
+                break;
+            } else {
+                continue;
+            }
+        }
+        attributes = NULL;
+        element_name = strndup(name, name_len);
+        LY_CHECK_GOTO(lydxml_attributes(ctx, element_name, data, &attributes), cleanup);
+        ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
+        if (!ns) {
+            LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%*.s\".", prefix_len, prefix);
+            goto cleanup;
+        }
+        mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
+        if (!mod) {
+            LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
+            goto cleanup;
+        }
+        snode = lys_child(parent ? parent->schema : NULL, mod, name, name_len, 0, (ctx->options & LYD_OPT_RPCREPLY) ? LYS_GETNEXT_OUTPUT : 0);
+        if (!snode) {
+            LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.", name_len, name, mod->name);
+            goto cleanup;
+        }
+
+        /* allocate new node */
+        switch (snode->nodetype) {
+        case LYS_CONTAINER:
+        case LYS_LIST:
+            cur = calloc(1, sizeof(struct lyd_node_inner));
+            break;
+        case LYS_LEAF:
+        case LYS_LEAFLIST:
+            cur = calloc(1, sizeof(struct lyd_node_term));
+            break;
+        case LYS_ANYDATA:
+        case LYS_ANYXML:
+            cur = calloc(1, sizeof(struct lyd_node_any));
+            break;
+        /* TODO LYS_ACTION, LYS_NOTIF */
+        default:
+            LOGINT(ctx->ctx);
+            goto cleanup;
+        }
+        if (!(*node)) {
+            (*node) = cur;
+        }
+        cur->schema = snode;
+        cur->parent = parent;
+        if (prev) {
+            cur->prev = prev;
+            prev->next = cur;
+        } else {
+            cur->prev = cur;
+        }
+        prev = cur;
+        cur->attr = attributes;
+        attributes = NULL;
+
+        if (snode->nodetype & LYD_NODE_TERM) {
+            int dynamic = 0;
+            char *buffer = NULL, *value;
+            size_t buffer_size = 0, value_len;
+
+            if (ctx->status == LYXML_ELEM_CONTENT) {
+                /* get the value */
+                lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
+                lyd_value_validate((struct lyd_node_term*)cur, value, value_len,
+                                   LY_TYPE_VALIDATE_CANONIZE | (dynamic ? LY_TYPE_VALIDATE_DYNAMIC : 0));
+            }
+        } else if (snode->nodetype & LYD_NODE_INNER) {
+            int dynamic = 0;
+            char *buffer = NULL, *value;
+            size_t buffer_size = 0, value_len;
+
+            if (ctx->status == LYXML_ELEM_CONTENT) {
+                LY_ERR r = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
+                if (r != LY_EINVAL) {
+                    LOGINT(ctx->ctx);
+                    goto cleanup;
+                }
+            }
+            if (ctx->status == LYXML_ELEMENT) {
+                ret = lydxml_nodes(ctx, (struct lyd_node_inner*)cur, data, lyd_node_children_p(cur));
+            }
+        }
+        /* TODO anyxml/anydata */
+    }
+
+cleanup:
+    lyxml_ns_rm((struct lyxml_context *)ctx, element_name);
+    lyd_free_attr(ctx->ctx, attributes, 1);
+    free(element_name);
+    return ret;
+}
+
+LY_ERR
+lyd_parse_xml(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **result)
+{
+    LY_ERR ret;
+    struct lyd_xml_ctx xmlctx = {0};
+
+    xmlctx.options = options;
+    xmlctx.ctx = ctx;
+    xmlctx.line = 1;
+
+    ret = lydxml_nodes(&xmlctx, NULL, &data, result);
+    lyxml_context_clear((struct lyxml_context*)&xmlctx);
+    return ret;
+}
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 83ad888..7ef4968 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -11,22 +11,24 @@
  *
  *     https://opensource.org/licenses/BSD-3-Clause
  */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <errno.h>
-#include <ctype.h>
-#include <string.h>
-#include <dirent.h>
-#include <assert.h>
 
 #include "common.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
 #include "context.h"
-#include "libyang.h"
+#include "dict.h"
+#include "extensions.h"
+#include "log.h"
+#include "set.h"
+#include "tree.h"
+#include "tree_schema.h"
 #include "tree_schema_internal.h"
 
 /* Macro to check YANG's yang-char grammar rule */
@@ -117,12 +119,12 @@
 #define YANG_CHECK_STMTVER2_RET(CTX, KW, PARENT) \
     if ((CTX)->mod_version < 2) {LOGVAL_YANG((CTX), LY_VCODE_INCHILDSTMT2, KW, PARENT); return LY_EVALID;}
 
-static LY_ERR parse_container(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
-static LY_ERR parse_uses(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
-static LY_ERR parse_choice(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
-static LY_ERR parse_case(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
-static LY_ERR parse_list(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
-static LY_ERR parse_grouping(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_grp **groupings);
+static LY_ERR parse_container(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
+static LY_ERR parse_uses(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
+static LY_ERR parse_choice(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
+static LY_ERR parse_case(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
+static LY_ERR parse_list(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
+static LY_ERR parse_grouping(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_grp **groupings);
 
 /**
  * @brief Add another character to dynamic buffer, a low-level function.
@@ -166,7 +168,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-check_stringchar(struct ly_parser_ctx *ctx, unsigned int c)
+check_stringchar(struct lys_parser_ctx *ctx, unsigned int c)
 {
     if (!is_yangutf8char(c)) {
         LOGVAL_YANG(ctx, LY_VCODE_INCHAR, c);
@@ -190,7 +192,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-check_identifierchar(struct ly_parser_ctx *ctx, unsigned int c, int first, int *prefix)
+check_identifierchar(struct lys_parser_ctx *ctx, unsigned int c, int first, int *prefix)
 {
     if (first || (prefix && (*prefix) == 1)) {
         if (!is_yangidentstartchar(c)) {
@@ -231,7 +233,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-buf_store_char(struct ly_parser_ctx *ctx, const char **input, enum yang_arg arg,
+buf_store_char(struct lys_parser_ctx *ctx, const char **input, enum yang_arg arg,
                char **word_p, size_t *word_len, char **word_b, size_t *buf_len, int need_buf)
 {
     int prefix = 0;
@@ -315,7 +317,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-skip_comment(struct ly_parser_ctx *ctx, const char **data, int comment)
+skip_comment(struct lys_parser_ctx *ctx, const char **data, int comment)
 {
     /* internal statuses: 0 - comment ended,
      *                    1 - in line comment,
@@ -384,7 +386,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-read_qstring(struct ly_parser_ctx *ctx, const char **data, enum yang_arg arg, char **word_p, char **word_b, size_t *word_len,
+read_qstring(struct lys_parser_ctx *ctx, const char **data, enum yang_arg arg, char **word_p, char **word_b, size_t *word_len,
              size_t *buf_len)
 {
     /* string: 0 - string ended, 1 - string with ', 2 - string with ", 3 - string with " with last character \,
@@ -580,7 +582,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-get_argument(struct ly_parser_ctx *ctx, const char **data, enum yang_arg arg,
+get_argument(struct lys_parser_ctx *ctx, const char **data, enum yang_arg arg,
              uint16_t *flags, char **word_p, char **word_b, size_t *word_len)
 {
     size_t buf_len = 0;
@@ -695,7 +697,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-get_keyword(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword *kw, char **word_p, size_t *word_len)
+get_keyword(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword *kw, char **word_p, size_t *word_len)
 {
     int prefix;
     const char *word_start;
@@ -1011,7 +1013,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_ext_substmt(struct ly_parser_ctx *ctx, const char **data, char *word, size_t word_len,
+parse_ext_substmt(struct lys_parser_ctx *ctx, const char **data, char *word, size_t word_len,
                   struct lysp_stmt **child)
 {
     char *buf;
@@ -1063,7 +1065,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_ext(struct ly_parser_ctx *ctx, const char **data, const char *ext_name, int ext_name_len, LYEXT_SUBSTMT insubstmt,
+parse_ext(struct lys_parser_ctx *ctx, const char **data, const char *ext_name, int ext_name_len, LYEXT_SUBSTMT insubstmt,
           uint32_t insubstmt_index, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -1107,7 +1109,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_text_field(struct ly_parser_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, uint32_t substmt_index,
+parse_text_field(struct lys_parser_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, uint32_t substmt_index,
                  const char **value, enum yang_arg arg, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -1150,7 +1152,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_yangversion(struct ly_parser_ctx *ctx, const char **data, uint8_t *version, struct lysp_ext_instance **exts)
+parse_yangversion(struct lys_parser_ctx *ctx, const char **data, uint8_t *version, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1201,7 +1203,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_belongsto(struct ly_parser_ctx *ctx, const char **data, const char **belongsto, const char **prefix, struct lysp_ext_instance **exts)
+parse_belongsto(struct lys_parser_ctx *ctx, const char **data, const char **belongsto, const char **prefix, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1251,7 +1253,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_revisiondate(struct ly_parser_ctx *ctx, const char **data, char *rev, struct lysp_ext_instance **exts)
+parse_revisiondate(struct lys_parser_ctx *ctx, const char **data, char *rev, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1300,7 +1302,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_include(struct ly_parser_ctx *ctx, const char *module_name, const char **data, struct lysp_include **includes)
+parse_include(struct lys_parser_ctx *ctx, const char *module_name, const char **data, struct lysp_include **includes)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1357,7 +1359,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_import(struct ly_parser_ctx *ctx, const char *module_prefix, const char **data, struct lysp_import **imports)
+parse_import(struct lys_parser_ctx *ctx, const char *module_prefix, const char **data, struct lysp_import **imports)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1414,7 +1416,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_revision(struct ly_parser_ctx *ctx, const char **data, struct lysp_revision **revs)
+parse_revision(struct lys_parser_ctx *ctx, const char **data, struct lysp_revision **revs)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1467,7 +1469,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_text_fields(struct ly_parser_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, const char ***texts, enum yang_arg arg,
+parse_text_fields(struct lys_parser_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, const char ***texts, enum yang_arg arg,
                   struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -1507,7 +1509,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_config(struct ly_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_config(struct lys_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1557,7 +1559,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_mandatory(struct ly_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_mandatory(struct lys_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1607,7 +1609,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_restr(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword restr_kw, struct lysp_restr *restr)
+parse_restr(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword restr_kw, struct lysp_restr *restr)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1654,7 +1656,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_restrs(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword restr_kw, struct lysp_restr **restrs)
+parse_restrs(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword restr_kw, struct lysp_restr **restrs)
 {
     struct lysp_restr *restr;
 
@@ -1673,7 +1675,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_status(struct ly_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_status(struct lys_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1724,7 +1726,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_when(struct ly_parser_ctx *ctx, const char **data, struct lysp_when **when_p)
+parse_when(struct lys_parser_ctx *ctx, const char **data, struct lysp_when **when_p)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1775,7 +1777,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_any(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword kw, struct lysp_node *parent, struct lysp_node **siblings)
+parse_any(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword kw, struct lysp_node *parent, struct lysp_node **siblings)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1853,7 +1855,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_type_enum_value_pos(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword val_kw, int64_t *value, uint16_t *flags,
+parse_type_enum_value_pos(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword val_kw, int64_t *value, uint16_t *flags,
                           struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -1935,7 +1937,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_type_enum(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword enum_kw, struct lysp_type_enum **enums)
+parse_type_enum(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword enum_kw, struct lysp_type_enum **enums)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2013,7 +2015,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_type_fracdigits(struct ly_parser_ctx *ctx, const char **data, uint8_t *fracdig, struct lysp_ext_instance **exts)
+parse_type_fracdigits(struct lys_parser_ctx *ctx, const char **data, uint8_t *fracdig, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word, *ptr;
@@ -2076,7 +2078,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_type_reqinstance(struct ly_parser_ctx *ctx, const char **data, uint8_t *reqinst, uint16_t *flags,
+parse_type_reqinstance(struct lys_parser_ctx *ctx, const char **data, uint8_t *reqinst, uint16_t *flags,
                        struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -2126,7 +2128,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_type_pattern_modifier(struct ly_parser_ctx *ctx, const char **data, const char **pat, struct lysp_ext_instance **exts)
+parse_type_pattern_modifier(struct lys_parser_ctx *ctx, const char **data, const char **pat, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2181,7 +2183,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_type_pattern(struct ly_parser_ctx *ctx, const char **data, struct lysp_restr **patterns)
+parse_type_pattern(struct lys_parser_ctx *ctx, const char **data, struct lysp_restr **patterns)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2246,7 +2248,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_type(struct ly_parser_ctx *ctx, const char **data, struct lysp_type *type)
+parse_type(struct lys_parser_ctx *ctx, const char **data, struct lysp_type *type)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2341,7 +2343,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_leaf(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_leaf(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2439,7 +2441,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_maxelements(struct ly_parser_ctx *ctx, const char **data, uint32_t *max, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_maxelements(struct lys_parser_ctx *ctx, const char **data, uint32_t *max, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word, *ptr;
@@ -2506,7 +2508,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_minelements(struct ly_parser_ctx *ctx, const char **data, uint32_t *min, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_minelements(struct lys_parser_ctx *ctx, const char **data, uint32_t *min, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word, *ptr;
@@ -2569,7 +2571,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_orderedby(struct ly_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_orderedby(struct lys_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2618,7 +2620,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_leaflist(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_leaflist(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2727,7 +2729,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_refine(struct ly_parser_ctx *ctx, const char **data, struct lysp_refine **refines)
+parse_refine(struct lys_parser_ctx *ctx, const char **data, struct lysp_refine **refines)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2795,7 +2797,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_typedef(struct ly_parser_ctx *ctx, struct lysp_node *parent, const char **data, struct lysp_tpdf **typedefs)
+parse_typedef(struct lys_parser_ctx *ctx, struct lysp_node *parent, const char **data, struct lysp_tpdf **typedefs)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2865,7 +2867,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_inout(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword inout_kw, struct lysp_node *parent, struct lysp_action_inout *inout_p)
+parse_inout(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword inout_kw, struct lysp_node *parent, struct lysp_action_inout *inout_p)
 {
     LY_ERR ret = LY_SUCCESS;
     char *word;
@@ -2947,7 +2949,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_action(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_action **actions)
+parse_action(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_action **actions)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3020,7 +3022,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_notif(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_notif **notifs)
+parse_notif(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_notif **notifs)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3115,7 +3117,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_grouping(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_grp **groupings)
+parse_grouping(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_grp **groupings)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3211,7 +3213,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_augment(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_augment **augments)
+parse_augment(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_augment **augments)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3302,7 +3304,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_uses(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_uses(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3375,7 +3377,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_case(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_case(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3466,7 +3468,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_choice(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_choice(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3573,7 +3575,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_container(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_container(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
 {
     LY_ERR ret = 0;
     char *buf, *word;
@@ -3695,7 +3697,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_list(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_list(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3839,7 +3841,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_yinelement(struct ly_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_yinelement(struct lys_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3890,7 +3892,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_argument(struct ly_parser_ctx *ctx, const char **data, const char **argument, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_argument(struct lys_parser_ctx *ctx, const char **data, const char **argument, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3932,7 +3934,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_extension(struct ly_parser_ctx *ctx, const char **data, struct lysp_ext **extensions)
+parse_extension(struct lys_parser_ctx *ctx, const char **data, struct lysp_ext **extensions)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3981,7 +3983,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_deviate(struct ly_parser_ctx *ctx, const char **data, struct lysp_deviate **deviates)
+parse_deviate(struct lys_parser_ctx *ctx, const char **data, struct lysp_deviate **deviates)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -4195,7 +4197,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_deviation(struct ly_parser_ctx *ctx, const char **data, struct lysp_deviation **deviations)
+parse_deviation(struct lys_parser_ctx *ctx, const char **data, struct lysp_deviation **deviations)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -4249,7 +4251,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_feature(struct ly_parser_ctx *ctx, const char **data, struct lysp_feature **features)
+parse_feature(struct lys_parser_ctx *ctx, const char **data, struct lysp_feature **features)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -4298,7 +4300,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_identity(struct ly_parser_ctx *ctx, const char **data, struct lysp_ident **identities)
+parse_identity(struct lys_parser_ctx *ctx, const char **data, struct lysp_ident **identities)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -4381,7 +4383,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_module(struct ly_parser_ctx *ctx, const char **data, struct lysp_module *mod)
+parse_module(struct lys_parser_ctx *ctx, const char **data, struct lysp_module *mod)
 {
     LY_ERR ret = 0;
     char *buf, *word;
@@ -4591,7 +4593,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_submodule(struct ly_parser_ctx *ctx, const char **data, struct lysp_submodule *submod)
+parse_submodule(struct lys_parser_ctx *ctx, const char **data, struct lysp_submodule *submod)
 {
     LY_ERR ret = 0;
     char *buf, *word;
@@ -4785,7 +4787,7 @@
 }
 
 LY_ERR
-yang_parse_submodule(struct ly_parser_ctx *context, const char *data, struct lysp_submodule **submod)
+yang_parse_submodule(struct lys_parser_ctx *context, const char *data, struct lysp_submodule **submod)
 {
     LY_ERR ret = LY_SUCCESS;
     char *word, *buf;
@@ -4841,7 +4843,7 @@
 }
 
 LY_ERR
-yang_parse_module(struct ly_parser_ctx *context, const char *data, struct lys_module *mod)
+yang_parse_module(struct lys_parser_ctx *context, const char *data, struct lys_module *mod)
 {
     LY_ERR ret = LY_SUCCESS;
     char *word, *buf;
diff --git a/src/plugins_types.c b/src/plugins_types.c
new file mode 100644
index 0000000..cc5d740
--- /dev/null
+++ b/src/plugins_types.c
@@ -0,0 +1,204 @@
+/**
+ * @file plugin_types.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Built-in types plugins and interface for user types plugins.
+ *
+ * Copyright (c) 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+#include "common.h"
+
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "plugins_types.h"
+#include "dict.h"
+#include "tree_schema.h"
+
+API LY_ERR
+ly_type_validate_range(LY_DATA_TYPE basetype, struct lysc_range *range, int64_t value, struct ly_err_item **err)
+{
+    unsigned int u;
+    char *errmsg = NULL;
+
+    LY_ARRAY_FOR(range->parts, u) {
+        if (basetype < LY_TYPE_DEC64) {
+            /* unsigned */
+            if ((uint64_t)value < range->parts[u].min_u64) {
+                if (range->emsg) {
+                    errmsg = strdup(range->emsg);
+                } else {
+                    asprintf(&errmsg, "%s \"%"PRIu64"\" does not satisfy the %s constraint.",
+                           (basetype & (LY_TYPE_BINARY | LY_TYPE_STRING)) ? "Length" : "Value", (uint64_t)value,
+                           (basetype & (LY_TYPE_BINARY | LY_TYPE_STRING)) ? "length" : "range");
+                }
+                goto error;
+            } else if ((uint64_t)value < range->parts[u].max_u64) {
+                /* inside the range */
+                return LY_SUCCESS;
+            } else if (u == LY_ARRAY_SIZE(range->parts) - 1) {
+                /* we have the last range part, so the value is out of bounds */
+                if (range->emsg) {
+                    errmsg = strdup(range->emsg);
+                } else {
+                    asprintf(&errmsg, "%s \"%"PRIu64"\" does not satisfy the %s constraint.",
+                           (basetype & (LY_TYPE_BINARY | LY_TYPE_STRING)) ? "Length" : "Value", (uint64_t)value,
+                           (basetype & (LY_TYPE_BINARY | LY_TYPE_STRING)) ? "length" : "range");
+                }
+                goto error;
+            }
+        } else {
+            /* signed */
+            if (value < range->parts[u].min_64) {
+                if (range->emsg) {
+                    errmsg = strdup(range->emsg);
+                } else {
+                    asprintf(&errmsg, "Value \"%"PRId64"\" does not satisfy the range constraint.", value);
+                }
+                goto error;
+            } else if (value < range->parts[u].max_64) {
+                /* inside the range */
+                return LY_SUCCESS;
+            } else if (u == LY_ARRAY_SIZE(range->parts) - 1) {
+                /* we have the last range part, so the value is out of bounds */
+                if (range->emsg) {
+                    errmsg = strdup(range->emsg);
+                } else {
+                    asprintf(&errmsg, "Value \"%"PRId64"\" does not satisfy the range constraint.", value);
+                }
+                goto error;
+            }
+        }
+    }
+
+    return LY_SUCCESS;
+
+error:
+    *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, range->eapptag ? strdup(range->eapptag) : NULL);
+    return LY_EVALID;
+}
+
+/**
+ * @brief Validate and canonize value of the YANG built-in binary type.
+ *
+ * Implementation of the ly_type_validate_clb.
+ */
+static LY_ERR
+ly_type_validate_binary(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+                        const char **canonized, struct ly_err_item **err)
+{
+    size_t start, stop, count = 0, u, termination = 0;
+    struct lysc_type_bin *type_bin = (struct lysc_type_bin *)type;
+    char *errmsg;
+
+    /* initiate */
+    *err = NULL;
+
+    /* validate characters and remember the number of octets for length validation */
+    if (value) {
+        /* silently skip leading/trailing whitespaces */
+        for (start = 0; (start < value_len) && isspace(value[start]); start++);
+        for (stop = value_len - 1; stop > start && isspace(value[stop]); stop--);
+        if (start == stop) {
+            /* empty string */
+            goto finish;
+        }
+
+        for (count = 0, u = start; u < stop; u++) {
+            if (value[u] == '\n') {
+                /* newline formatting */
+                continue;
+            }
+            count++;
+
+            if ((value[u] < '/' && value[u] != '+') ||
+                    (value[u] > '9' && value[u] < 'A') ||
+                    (value[u] > 'Z' && value[u] < 'a') || value[u] > 'z') {
+                /* non-encoding characters */
+                if (value[u] == '=') {
+                    /* padding */
+                    if (u == stop - 1 && value[u + 1] == '=') {
+                        termination = 2;
+                        stop = u + 1;
+                    } else if (u == stop){
+                        termination = 1;
+                        stop = u;
+                    }
+                }
+                if (!termination) {
+                    /* error */
+                    asprintf(&errmsg, "Invalid Base64 character (%c).", value[u]);
+                    goto error;
+                }
+            }
+        }
+    }
+
+finish:
+    if (count & 3) {
+        /* base64 length must be multiple of 4 chars */
+        errmsg = strdup("Base64 encoded value length must be divisible by 4.");
+        goto error;
+    }
+
+    /* length of the encoded string */
+    if (type_bin->length) {
+        uint64_t len = ((count / 4) * 3) - termination;
+        LY_CHECK_RET(ly_type_validate_range(LY_TYPE_BINARY, type_bin->length, len, err));
+    }
+
+    if (options & LY_TYPE_VALIDATE_CANONIZE) {
+        if (start != 0 || stop != value_len - 1) {
+            *canonized = lydict_insert_zc(ctx, strndup(&value[start], stop - start));
+        } else if (options & LY_TYPE_VALIDATE_DYNAMIC) {
+            *canonized = lydict_insert_zc(ctx, (char*)value);
+            value = NULL;
+        } else {
+            *canonized = lydict_insert(ctx, value, value_len);
+        }
+    }
+    if (options & LY_TYPE_VALIDATE_DYNAMIC) {
+        free((char*)value);
+    }
+
+    return LY_SUCCESS;
+
+error:
+    if (!*err) {
+        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+    }
+    return (*err)->no;
+}
+
+
+struct lysc_type_plugin ly_builtin_type_plugins[LY_DATA_TYPE_COUNT] = {
+    {0}, /* LY_TYPE_UNKNOWN */
+    {.type = LY_TYPE_BINARY, .validate = ly_type_validate_binary, .store = NULL},
+    {0}, /* TODO LY_TYPE_UINT8 */
+    {0}, /* TODO LY_TYPE_UINT16 */
+    {0}, /* TODO LY_TYPE_UINT32 */
+    {0}, /* TODO LY_TYPE_UINT64 */
+    {0}, /* TODO LY_TYPE_STRING */
+    {0}, /* TODO LY_TYPE_BITS */
+    {0}, /* TODO LY_TYPE_BOOL */
+    {0}, /* TODO LY_TYPE_DEC64 */
+    {0}, /* TODO LY_TYPE_EMPTY */
+    {0}, /* TODO LY_TYPE_ENUM */
+    {0}, /* TODO LY_TYPE_IDENT */
+    {0}, /* TODO LY_TYPE_INST */
+    {0}, /* TODO LY_TYPE_LEAFREF */
+    {0}, /* TODO LY_TYPE_UNION */
+    {0}, /* TODO LY_TYPE_INT8 */
+    {0}, /* TODO LY_TYPE_INT16 */
+    {0}, /* TODO LY_TYPE_INT32 */
+    {0}  /* TODO LY_TYPE_INT64 */
+};
+
diff --git a/src/plugins_types.h b/src/plugins_types.h
new file mode 100644
index 0000000..0a84f3c
--- /dev/null
+++ b/src/plugins_types.h
@@ -0,0 +1,144 @@
+/**
+ * @file plugins_types.h
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief API for (user) types plugins
+ *
+ * Copyright (c) 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef LY_PLUGINS_TYPES_H_
+#define LY_PLUGINS_TYPES_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "log.h"
+#include "tree.h"
+#include "tree_schema.h"
+#include "tree_data.h"
+
+/**
+ * @brief Helper function for various plugin functions to generate error information structure.
+ *
+ * @param[in] level Error level of the error.
+ * @param[in] code Code of the error.
+ * @param[in] vecode Validity error code in case of LY_EVALID error code.
+ * @param[in] msg Error message.
+ * @param[in] path Path to the node causing the error.
+ * @param[in] apptag Error-app-tag value.
+ * @return NULL in case of memory allocation failure.
+ * @return Created error information structure that can be freed using ly_err_free().
+ */
+struct ly_err_item *ly_err_new(LY_LOG_LEVEL level, LY_ERR code, LY_VECODE vecode, char *msg, char *path, char *apptag);
+
+/**
+ * @brief Destructor for the error records created with ly_err_new().
+ *
+ * Compatible with the free(), so usable as a generic callback.
+ *
+ * @param[in] ptr Error record to free. With the record, also all the records connected after this one are freed.
+ */
+void ly_err_free(void *ptr);
+
+/**
+ * @defgroup plugintypevalidateopts Options for type plugin validation callback.
+ * Options applicable to ly_type_validate_clb().
+ * @{
+ */
+#define LY_TYPE_VALIDATE_CANONIZE 0x01 /**< Canonize the given value and store it (insert into the context's dictionary)
+                                            as the value's canonized string */
+#define LY_TYPE_VALIDATE_DYNAMIC  0x02 /**< Flag for the dynamically allocated string value, in this case the value is supposed to be freed
+                                            or directly used to insert into the node's value structure in case of canonization.
+                                            In any case, the caller of the callback does not free the provided string value after calling
+                                            the ly_type_validate_clb() with this option */
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup plugintypeflags Various flags for type plugins usage.
+ * Options applicable to ly_type_validate_clb().
+ * @{
+ */
+#define LY_TYPE_FLAG_PREFIXES 0x01     /**< The value contains prefixes, so when printing XML,
+                                            get the namespaces connected with the prefixes and print them. */
+/**
+ * @}
+ */
+
+/**
+ * @brief Callback to validate the given @p value according to the given @p type. Optionaly, it can be requested to canonize the value.
+ *
+ * Note that the \p value string is not necessarily zero-terminated. The provided \p value_len is always correct.
+ *
+ * @param[in] ctx libyang Context
+ * @param[in] type Type of the value being canonized.
+ * @param[in] value Lexical representation of the value to be validated (and canonized).
+ * @param[in] value_len Length of the given \p value.
+ * @param[in] options [Type validation options ](@ref plugintypevalidateopts).
+ * @param[out] canonized If LY_TYPE_VALIDATE_CANONIZE option set, the canonized string stored in the @p ctx dictionary is returned via this parameter.
+ * @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic error message is prepared instead.
+ * The error structure can be created by ly_err_new().
+ * @return LY_SUCCESS on success
+ * @return LY_ERR value if an error occurred and the value could not be canonized following the type's rules.
+ */
+typedef LY_ERR (*ly_type_validate_clb)(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+                                       const char **canonized, struct ly_err_item **err);
+
+/**
+ * @brief Callback for storing user type values.
+ *
+ * This callback should overwrite the value stored in \p value using some custom encoding. Be careful,
+ * if the type is #LY_TYPE_BITS, the bits must be freed before overwritting the union value.
+ *
+ * @param[in] ctx libyang ctx to enable correct manipulation with values that are in the dictionary.
+ * @param[in] type Type of the value being stored.
+ * @param[in] value_str Canonized string value to be stored.
+ * @param[in,out] value Value structure to store the data in the type plugin specific way.
+ * @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic error message is prepared instead.
+ * The error structure can be created by ly_err_new().
+ * @return LY_SUCCESS on success
+ * @return LY_ERR value if an error occurred and the value could not be stored for any reason.
+ */
+typedef LY_ERR (*ly_type_store_clb)(struct ly_ctx *ctx, struct lysc_type *type, const char *value_str, struct lyd_value *value, struct ly_err_item **err);
+
+/**
+ * @brief Hold type-specific functions for various operations with the data values.
+ *
+ * libyang includes set of plugins for all the built-in types. They are, by default, inherited to the derived types.
+ * However, if the user type plugin for the specific type is loaded, the plugin can provide it's own functions.
+ * The built-in types plugins and are public, so even the user type plugins can use them to do part of their own functionality.
+ */
+struct lysc_type_plugin {
+    LY_DATA_TYPE type;               /**< implemented type, use LY_TYPE_UNKNOWN for derived data types */
+    ly_type_validate_clb validate;   /**< function to validate and canonize given value */
+    ly_type_store_clb store;         /**< function to store the value in the type-specific way */
+    uint32_t flags;                  /**< [type flags ](@ref plugintypeflags). */
+};
+
+/**
+ * @brief List of type plugins for built-in types.
+ */
+extern struct lysc_type_plugin ly_builtin_type_plugins[LY_DATA_TYPE_COUNT];
+
+/**
+ * @brief Data type validator for a range/length-restricted values.
+ *
+ * @param[in] ctx libyang context
+ * @param[in] range Range (length) restriction information.
+ * @param[in] value Value to check. In case of basetypes using unsigned integer values, the value is actually cast to uint64_t.
+ * @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic error message is prepared instead.
+ * The error structure can be created by ly_err_new().
+ * @return LY_ERR value according to the result of the validation.
+ */
+LY_ERR ly_type_validate_range(LY_DATA_TYPE basetype, struct lysc_range *range, int64_t value, struct ly_err_item **err);
+
+
+#endif /* LY_PLUGINS_TYPES_H_ */
diff --git a/src/printer.c b/src/printer.c
index e681104..72872b1 100644
--- a/src/printer.c
+++ b/src/printer.c
@@ -1,7 +1,7 @@
 /**
  * @file printer.c
  * @author Radek Krejci <rkrejci@cesnet.cz>
- * @brief Wrapper for all libyang printers.
+ * @brief Generic libyang printers functions.
  *
  * Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
  *
@@ -16,8 +16,12 @@
 
 #include <errno.h>
 #include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
+#include "log.h"
 #include "printer_internal.h"
 
 /**
@@ -159,15 +163,20 @@
         fflush(out->method.f);
         break;
     case LYOUT_FD:
+        fsync(out->method.fd);
+        break;
     case LYOUT_MEMORY:
     case LYOUT_CALLBACK:
         /* nothing to do */
         break;
     }
+
+    free(out->buffered);
+    out->buf_size = out->buf_len = 0;
 }
 
 LY_ERR
-ly_write(struct lyout *out, const char *buf, size_t count)
+ly_write(struct lyout *out, const char *buf, size_t len)
 {
     int written = 0;
 
@@ -175,48 +184,48 @@
 
     if (out->hole_count) {
         /* we are buffering data after a hole */
-        if (out->buf_len + count > out->buf_size) {
-            out->buffered = ly_realloc(out->buffered, out->buf_len + count);
+        if (out->buf_len + len > out->buf_size) {
+            out->buffered = ly_realloc(out->buffered, out->buf_len + len);
             if (!out->buffered) {
                 out->buf_len = 0;
                 out->buf_size = 0;
                 LOGMEM_RET(NULL);
             }
-            out->buf_size = out->buf_len + count;
+            out->buf_size = out->buf_len + len;
         }
 
-        memcpy(&out->buffered[out->buf_len], buf, count);
-        out->buf_len += count;
+        memcpy(&out->buffered[out->buf_len], buf, len);
+        out->buf_len += len;
         return LY_SUCCESS;
     }
 
 repeat:
     switch (out->type) {
     case LYOUT_MEMORY:
-        if (out->method.mem.len + count + 1 > out->method.mem.size) {
-            out->method.mem.buf = ly_realloc(out->method.mem.buf, out->method.mem.len + count + 1);
+        if (out->method.mem.len + len + 1 > out->method.mem.size) {
+            out->method.mem.buf = ly_realloc(out->method.mem.buf, out->method.mem.len + len + 1);
             if (!out->method.mem.buf) {
                 out->method.mem.len = 0;
                 out->method.mem.size = 0;
                 LOGMEM_RET(NULL);
             }
-            out->method.mem.size = out->method.mem.len + count + 1;
+            out->method.mem.size = out->method.mem.len + len + 1;
         }
-        memcpy(&out->method.mem.buf[out->method.mem.len], buf, count);
-        out->method.mem.len += count;
+        memcpy(&out->method.mem.buf[out->method.mem.len], buf, len);
+        out->method.mem.len += len;
         out->method.mem.buf[out->method.mem.len] = '\0';
 
-        out->printed += count;
+        out->printed += len;
         return LY_SUCCESS;
     case LYOUT_FD:
-        written = write(out->method.fd, buf, count);
+        written = write(out->method.fd, buf, len);
         break;
     case LYOUT_FDSTREAM:
     case LYOUT_STREAM:
-        written =  fwrite(buf, sizeof *buf, count, out->method.f);
+        written =  fwrite(buf, sizeof *buf, len, out->method.f);
         break;
     case LYOUT_CALLBACK:
-        written = out->method.clb.f(out->method.clb.arg, buf, count);
+        written = out->method.clb.f(out->method.clb.arg, buf, len);
         break;
     }
 
@@ -227,8 +236,8 @@
         LOGERR(out->ctx, LY_ESYS, "%s: writing data failed (%s).", __func__, strerror(errno));
         out->status = LY_ESYS;
         return LY_ESYS;
-    } else if ((size_t)written != count) {
-        LOGERR(out->ctx, LY_ESYS, "%s: writing data failed (unable to write %u from %u data).", __func__, count - (size_t)written, count);
+    } else if ((size_t)written != len) {
+        LOGERR(out->ctx, LY_ESYS, "%s: writing data failed (unable to write %u from %u data).", __func__, len - (size_t)written, len);
         out->status = LY_ESYS;
         return LY_ESYS;
     } else {
@@ -331,162 +340,3 @@
 
     return ret;
 }
-
-static LY_ERR
-lys_print_(struct lyout *out, const struct lys_module *module, LYS_OUTFORMAT format, int UNUSED(line_length), int UNUSED(options))
-{
-    LY_ERR ret;
-
-    switch (format) {
-    case LYS_OUT_YANG:
-        ret = yang_print_parsed(out, module);
-        break;
-    case LYS_OUT_YANG_COMPILED:
-        ret = yang_print_compiled(out, module);
-        break;
-    /* TODO not yet implemented
-    case LYS_OUT_YIN:
-        lys_disable_deviations((struct lys_module *)module);
-        ret = yin_print_model(out, module);
-        lys_enable_deviations((struct lys_module *)module);
-        break;
-    case LYS_OUT_TREE:
-        ret = tree_print_model(out, module, target_node, line_length, options);
-        break;
-    case LYS_OUT_INFO:
-        ret = info_print_model(out, module, target_node);
-        break;
-    case LYS_OUT_JSON:
-        ret = jsons_print_model(out, module, target_node);
-        break;
-    */
-    default:
-        LOGERR(module->ctx, LY_EINVAL, "Unknown output format.");
-        ret = LY_EINVAL;
-        break;
-    }
-
-    return ret;
-}
-
-API ssize_t
-lys_print_file(FILE *f, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
-{
-    struct lyout out;
-    LY_ERR ret;
-
-    LY_CHECK_ARG_RET(NULL, f, module, LY_EINVAL);
-
-    memset(&out, 0, sizeof out);
-    out.ctx = module->ctx;
-    out.type = LYOUT_STREAM;
-    out.method.f = f;
-
-    ret = lys_print_(&out, module, format, line_length, options);
-    if (ret) {
-        /* error */
-        return (-1) * ret;
-    } else {
-        /* success */
-        return (ssize_t)out.printed;
-    }
-}
-
-API ssize_t
-lys_print_path(const char *path, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
-{
-    FILE *f;
-    ssize_t ret;
-
-    LY_CHECK_ARG_RET(NULL, path, module, LY_EINVAL);
-
-    f = fopen(path, "w");
-    if (!f) {
-        LOGERR(module->ctx, LY_ESYS, "Failed to open file \"%s\" (%s).", path, strerror(errno));
-        return LY_ESYS;
-    }
-
-    ret = lys_print_file(f, module, format, line_length, options);
-    fclose(f);
-    return ret;
-}
-
-API ssize_t
-lys_print_fd(int fd, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
-{
-    LY_ERR ret;
-    struct lyout out;
-
-    LY_CHECK_ARG_RET(NULL, fd >= 0, module, LY_EINVAL);
-
-    memset(&out, 0, sizeof out);
-    out.ctx = module->ctx;
-    out.type = LYOUT_FD;
-    out.method.fd = fd;
-
-    ret = lys_print_(&out, module, format, line_length, options);
-
-    if (out.type == LYOUT_FDSTREAM) {
-        /* close temporary stream based on the given file descriptor */
-        fclose(out.method.f);
-        /* move the original file descriptor to the end of the output file */
-        lseek(fd, 0, SEEK_END);
-    }
-
-    if (ret) {
-        /* error */
-        return (-1) * ret;
-    } else {
-        /* success */
-        return (ssize_t)out.printed;
-    }
-}
-
-API ssize_t
-lys_print_mem(char **strp, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
-{
-    struct lyout out;
-    LY_ERR ret;
-
-    LY_CHECK_ARG_RET(NULL, strp, module, LY_EINVAL);
-
-    memset(&out, 0, sizeof out);
-    out.ctx = module->ctx;
-    out.type = LYOUT_MEMORY;
-
-    ret = lys_print_(&out, module, format, line_length, options);
-    if (ret) {
-        /* error */
-        *strp = NULL;
-        return (-1) * ret;
-    } else {
-        /* success */
-        *strp = out.method.mem.buf;
-        return (ssize_t)out.printed;
-    }
-}
-
-API ssize_t
-lys_print_clb(ssize_t (*writeclb)(void *arg, const void *buf, size_t count), void *arg, const struct lys_module *module,
-              LYS_OUTFORMAT format, int line_length, int options)
-{
-    LY_ERR ret;
-    struct lyout out;
-
-    LY_CHECK_ARG_RET(NULL, writeclb, module, LY_EINVAL);
-
-    memset(&out, 0, sizeof out);
-    out.ctx = module->ctx;
-    out.type = LYOUT_CALLBACK;
-    out.method.clb.f = writeclb;
-    out.method.clb.arg = arg;
-
-    ret = lys_print_(&out, module, format, line_length, options);
-    if (ret) {
-        /* error */
-        return (-1) * ret;
-    } else {
-        /* success */
-        return (ssize_t)out.printed;
-    }
-}
diff --git a/src/printer_data.c b/src/printer_data.c
new file mode 100644
index 0000000..7853099
--- /dev/null
+++ b/src/printer_data.c
@@ -0,0 +1,194 @@
+/**
+ * @file printer_data.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Generic data printers functions.
+ *
+ * Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "common.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "printer_internal.h"
+#include "tree_schema.h"
+#include "tree_data.h"
+
+/**
+ * @brief Common YANG data printer.
+ *
+ * @param[in] out Prepared structure defining the type and details of the printer output.
+ * @param[in] root The root element of the (sub)tree to print.
+ * @param[in] format Output format.
+ * @param[in] options [Data printer flags](@ref dataprinterflags). With \p format LYD_LYB, only #LYP_WITHSIBLINGS option is accepted.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyd_print_(struct lyout *out, const struct lyd_node *root, LYD_FORMAT format, int options)
+{
+    LY_ERR ret;
+
+    switch (format) {
+    case LYD_XML:
+        ret = xml_print_data(out, root, options);
+        break;
+#if 0
+    case LYD_JSON:
+        ret = json_print_data(out, root, options);
+        break;
+    case LYD_LYB:
+        ret = lyb_print_data(out, root, options);
+        break;
+#endif
+    default:
+        LOGERR(root->schema->module->ctx, LY_EINVAL, "Unknown output format.");
+        ret = LY_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+API ssize_t
+lyd_print_file(FILE *f, const struct lyd_node *root, LYD_FORMAT format, int options)
+{
+    struct lyout out;
+    LY_ERR ret;
+
+    LY_CHECK_ARG_RET(NULL, f, LY_EINVAL);
+
+    memset(&out, 0, sizeof out);
+    out.type = LYOUT_STREAM;
+    out.method.f = f;
+
+    if (root) {
+        out.ctx = root->schema->module->ctx;
+    }
+
+    ret = lyd_print_(&out, root, format, options);
+    if (ret) {
+        /* error */
+        return (-1) * ret;
+    } else {
+        /* success */
+        return (ssize_t)out.printed;
+    }
+}
+
+API ssize_t
+lyd_print_path(const char *path, const struct lyd_node *root, LYD_FORMAT format, int options)
+{
+    FILE *f;
+    ssize_t ret;
+
+    LY_CHECK_ARG_RET(NULL, path, LY_EINVAL);
+
+    f = fopen(path, "w");
+    if (!f) {
+        LOGERR(root ? root->schema->module->ctx : NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", path, strerror(errno));
+        return LY_ESYS;
+    }
+
+    ret = lyd_print_file(f, root, format, options);
+    fclose(f);
+    return ret;
+}
+
+API ssize_t
+lyd_print_fd(int fd, const struct lyd_node *root, LYD_FORMAT format, int options)
+{
+    LY_ERR ret;
+    struct lyout out;
+
+    LY_CHECK_ARG_RET(NULL, fd >= 0, LY_EINVAL);
+
+    memset(&out, 0, sizeof out);
+    out.type = LYOUT_FD;
+    out.method.fd = fd;
+
+    if (root) {
+        out.ctx = root->schema->module->ctx;
+    }
+
+    ret = lyd_print_(&out, root, format, options);
+
+    if (out.type == LYOUT_FDSTREAM) {
+        /* close temporary stream based on the given file descriptor */
+        fclose(out.method.f);
+        /* move the original file descriptor to the end of the output file */
+        lseek(fd, 0, SEEK_END);
+    }
+
+    if (ret) {
+        /* error */
+        return (-1) * ret;
+    } else {
+        /* success */
+        return (ssize_t)out.printed;
+    }
+}
+
+API ssize_t
+lyd_print_mem(char **strp, const struct lyd_node *root, LYD_FORMAT format, int options)
+{
+    struct lyout out;
+    LY_ERR ret;
+
+    LY_CHECK_ARG_RET(NULL, strp, LY_EINVAL);
+
+    memset(&out, 0, sizeof out);
+    out.type = LYOUT_MEMORY;
+
+    if (root) {
+        out.ctx = root->schema->module->ctx;
+    }
+
+    ret = lyd_print_(&out, root, format, options);
+    if (ret) {
+        /* error */
+        *strp = NULL;
+        return (-1) * ret;
+    } else {
+        /* success */
+        *strp = out.method.mem.buf;
+        return (ssize_t)out.printed;
+    }
+}
+
+API ssize_t
+lyd_print_clb(ssize_t (*writeclb)(void *arg, const void *buf, size_t count), void *arg, const struct lyd_node *root,
+              LYD_FORMAT format, int options)
+{
+    LY_ERR ret;
+    struct lyout out;
+
+    LY_CHECK_ARG_RET(NULL, writeclb, LY_EINVAL);
+
+    memset(&out, 0, sizeof out);
+    out.type = LYOUT_CALLBACK;
+    out.method.clb.f = writeclb;
+    out.method.clb.arg = arg;
+
+    if (root) {
+        out.ctx = root->schema->module->ctx;
+    }
+
+    ret = lyd_print_(&out, root, format, options);
+    if (ret) {
+        /* error */
+        return (-1) * ret;
+    } else {
+        /* success */
+        return (ssize_t)out.printed;
+    }
+}
diff --git a/src/printer_data.h b/src/printer_data.h
new file mode 100644
index 0000000..197463c
--- /dev/null
+++ b/src/printer_data.h
@@ -0,0 +1,125 @@
+/**
+ * @file printer_schema.h
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Schema printers for libyang
+ *
+ * Copyright (c) 2015-2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef LY_PRINTER_DATA_H_
+#define LY_PRINTER_DATA_H_
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "tree_data.h"
+
+/**
+ * @defgroup dataprinterflags Data printer flags
+ * @ingroup datatree
+ *
+ * Validity flags for data nodes.
+ *
+ * @{
+ */
+#define LYDP_WITHSIBLINGS  0x01  /**< Flag for printing also the (following) sibling nodes of the data node. */
+#define LYDP_FORMAT        0x02  /**< Flag for formatted output. */
+#define LYDP_KEEPEMPTYCONT 0x04  /**< Preserve empty non-presence containers */
+#define LYDP_WD_MASK       0xF0  /**< Mask for with-defaults modes */
+#define LYDP_WD_EXPLICIT   0x00  /**< Explicit mode - print only data explicitly being present in the data tree.
+                                      Note that this is the default value when no WD option is specified. */
+#define LYDP_WD_TRIM       0x10  /**< Do not print the nodes with the value equal to their default value */
+#define LYDP_WD_ALL        0x20  /**< Include implicit default nodes */
+#define LYDP_WD_ALL_TAG    0x40  /**< Same as #LYP_WD_ALL but also adds attribute 'default' with value 'true' to
+                                      all nodes that has its default value. The 'default' attribute has namespace:
+                                      urn:ietf:params:xml:ns:netconf:default:1.0 and thus the attributes are
+                                      printed only when the ietf-netconf-with-defaults module is present in libyang
+                                      context (but in that case this namespace is always printed). */
+#define LYDP_WD_IMPL_TAG   0x80  /**< Same as LYP_WD_ALL_TAG but the attributes are added only to the nodes that
+                                      are not explicitly present in the original data tree despite their
+                                      value is equal to their default value.  There is the same limitation regarding
+                                      the presence of ietf-netconf-with-defaults module in libyang context. */
+#define LYDP_NETCONF       0x100 /**< Print the data tree for use in NETCONF meaning:
+                                      - for RPC output - skip the top-level RPC node,
+                                      - for action output - skip all the parents of and the action node itself,
+                                      - for action input - enclose the data in an action element in the base YANG namespace,
+                                      - for all other data - print the whole data tree normally. */
+/**
+ * @}
+ */
+
+/**
+ * @brief Print data tree in the specified format into a memory block.
+ * It is up to caller to free the returned string by free().
+ *
+ * @param[out] strp Pointer to store the resulting dump.
+ * @param[in] root Root node of the data tree to print. It can be actually any (not only real root)
+ * node of the data tree to print the specific subtree.
+ * @param[in] format Data output format.
+ * @param[in] options [Data printer flags](@ref dataprinterflags). With \p format LYD_LYB, only #LYP_WITHSIBLINGS option is accepted.
+ * @return Number of printed bytes in case of success.
+ * @return Negative value failure (absolute value corresponds to LY_ERR values).
+ */
+ssize_t lyd_print_mem(char **strp, const struct lyd_node *root, LYD_FORMAT format, int options);
+
+/**
+ * @brief Print data tree in the specified format into a file descriptor.
+ *
+ * @param[in] fd File descriptor where to print the data.
+ * @param[in] root Root node of the data tree to print. It can be actually any (not only real root)
+ * node of the data tree to print the specific subtree.
+ * @param[in] format Data output format.
+ * @param[in] options [Data printer flags](@ref dataprinterflags). With \p format LYD_LYB, only #LYP_WITHSIBLINGS option is accepted.
+ * @return Number of printed bytes in case of success.
+ * @return Negative value failure (absolute value corresponds to LY_ERR values).
+ */
+ssize_t lyd_print_fd(int fd, const struct lyd_node *root, LYD_FORMAT format, int options);
+
+/**
+ * @brief Print data tree in the specified format into a file stream.
+ *
+ * @param[in] f File stream where to print the schema.
+ * @param[in] root Root node of the data tree to print. It can be actually any (not only real root)
+ * node of the data tree to print the specific subtree.
+ * @param[in] format Data output format.
+ * @param[in] options [Data printer flags](@ref dataprinterflags). With \p format LYD_LYB, only #LYP_WITHSIBLINGS option is accepted.
+ * @return Number of printed bytes in case of success.
+ * @return Negative value failure (absolute value corresponds to LY_ERR values).
+ */
+ssize_t lyd_print_file(FILE *f, const struct lyd_node *root, LYD_FORMAT format, int options);
+
+/**
+ * @brief Print data tree in the specified format into a file.
+ *
+ * @param[in] path File where to print the schema.
+ * @param[in] root Root node of the data tree to print. It can be actually any (not only real root)
+ * node of the data tree to print the specific subtree.
+ * @param[in] format Data output format.
+ * @param[in] options [Data printer flags](@ref dataprinterflags). With \p format LYD_LYB, only #LYP_WITHSIBLINGS option is accepted.
+ * @return Number of printed bytes in case of success.
+ * @return Negative value failure (absolute value corresponds to LY_ERR values).
+ */
+ssize_t lyd_print_path(const char *path, const struct lyd_node *root, LYD_FORMAT format, int options);
+
+/**
+ * @brief Print data tree in the specified format using the provided callback.
+ *
+ * @param[in] writeclb Callback function to write the data (see write(2)).
+ * @param[in] arg Optional caller-specific argument to be passed to the \p writeclb callback.
+ * @param[in] root Root node of the data tree to print. It can be actually any (not only real root)
+ * node of the data tree to print the specific subtree.
+ * @param[in] format Data output format.
+ * @param[in] options [Data printer flags](@ref dataprinterflags). With \p format LYD_LYB, only #LYP_WITHSIBLINGS option is accepted.
+ * @return Number of printed bytes in case of success.
+ * @return Negative value failure (absolute value corresponds to LY_ERR values).
+ */
+ssize_t lyd_print_clb(ssize_t (*writeclb)(void *arg, const void *buf, size_t count), void *arg, const struct lyd_node *root,
+                      LYD_FORMAT format, int options);
+
+#endif /* LY_PRINTER_DATA_H_ */
diff --git a/src/printer_internal.h b/src/printer_internal.h
index 2fb582e..7d0e312 100644
--- a/src/printer_internal.h
+++ b/src/printer_internal.h
@@ -16,7 +16,11 @@
 #define LY_PRINTER_INTERNAL_H_
 
 #include "printer_schema.h"
+#include "printer_data.h"
 
+/**
+ * @brief Types of the printer's output
+ */
 typedef enum LYOUT_TYPE {
     LYOUT_FD,          /**< file descriptor */
     LYOUT_STREAM,      /**< FILE stream */
@@ -25,44 +29,43 @@
     LYOUT_CALLBACK     /**< print via provided callback */
 } LYOUT_TYPE;
 
+/**
+ * @brief Printer output structure specifying where the data are printed.
+ */
 struct lyout {
-    LYOUT_TYPE type;
+    LYOUT_TYPE type;     /**< type of the output to select the output method */
     union {
-        int fd;
-        FILE *f;
+        int fd;          /**< file descriptor for LYOUT_FD type */
+        FILE *f;         /**< file structure for LYOUT_STREAM and LYOUT_FDSTREAM types */
         struct {
-            char *buf;
-            size_t len;
-            size_t size;
-        } mem;
+            char *buf;        /**< pointer to the memory buffer to store the output */
+            size_t len;       /**< number of used bytes in the buffer */
+            size_t size;      /**< allocated size of the buffer */
+        } mem;           /**< memory buffer information for LYOUT_MEMORY type */
         struct {
-            ssize_t (*f)(void *arg, const void *buf, size_t count);
-            void *arg;
-        } clb;
-    } method;
+            ssize_t (*f)(void *arg, const void *buf, size_t count); /**< callback function */
+            void *arg;        /**< optional argument for the callback function */
+        } clb;           /**< printer callback for LYOUT_CALLBACK type */
+    } method;            /**< type-specific information about the output */
 
-    /* buffer for holes */
-    char *buffered;
-    size_t buf_len;
-    size_t buf_size;
+    char *buffered;      /**< additional buffer for holes, used only for LYB data format */
+    size_t buf_len;      /**< number of used bytes in the additional buffer for holes, used only for LYB data format */
+    size_t buf_size;     /**< allocated size of the buffer for holes, used only for LYB data format */
+    size_t hole_count;   /**< hole counter, used only for LYB data format */
 
-    /* hole counter */
-    size_t hole_count;
+    size_t printed;      /**< Number of printed bytes */
 
-    /* counter for printed bytes */
-    size_t printed;
-
-    /* libyang context for error logging */
-    struct ly_ctx *ctx;
-    LY_ERR status;
+    struct ly_ctx *ctx;  /**< libyang context for error logging */
+    LY_ERR status;       /**< current status of the printer */
 };
 
-#define LYOUT_CHECK(LYOUT, ...) if (LYOUT->status) {return __VA_ARGS__;}
-
+/**
+ * @brief Informational structure for YANG statements
+ */
 struct ext_substmt_info_s {
-    const char *name;
-    const char *arg;
-    int flags;
+    const char *name;      /**< name of the statement */
+    const char *arg;       /**< name of YIN's attribute to present the statement */
+    int flags;             /**< various flags to clarify printing of the statement */
 #define SUBST_FLAG_YIN 0x1 /**< has YIN element */
 #define SUBST_FLAG_ID 0x2  /**< the value is identifier -> no quotes */
 };
@@ -70,21 +73,97 @@
 /* filled in printer.c */
 extern struct ext_substmt_info_s ext_substmt_info[];
 
+/**
+ * @brief macro to check current status of the printer.
+ */
+#define LYOUT_CHECK(LYOUT, ...) if (LYOUT->status) {return __VA_ARGS__;}
 
 /**
- * @brief
+ * @brief YANG printer of the parsed schemas. Full YANG printer.
+ *
+ * @param[in] out Output specification.
+ * @param[in] module Schema to be printed (the parsed member is used).
+ * @return LY_ERR value, number of the printed bytes is updated in lyout::printed.
  */
 LY_ERR yang_print_parsed(struct lyout *out, const struct lys_module *module);
 
 /**
- * @brief
+ * @brief YANG printer of the compiled schemas.
+ *
+ * This printer provides information about modules how they are understood by libyang.
+ * Despite the format is inspired by YANG, it is not fully compatible and should not be
+ * used as a standard YANG format.
+ *
+ * @param[in] out Output specification.
+ * @param[in] module Schema to be printed (the compiled member is used).
+ * @return LY_ERR value, number of the printed bytes is updated in lyout::printed.
  */
 LY_ERR yang_print_compiled(struct lyout *out, const struct lys_module *module);
 
+/**
+ * @brief XML printer of the YANG data.
+ *
+ * @param[in] out Output specification.
+ * @param[in] root The root element of the (sub)tree to print.
+ * @param[in] options [Data printer flags](@ref dataprinterflags).
+ * @return LY_ERR value, number of the printed bytes is updated in lyout::printed.
+ */
+LY_ERR xml_print_data(struct lyout *out, const struct lyd_node *root, int options);
+
+/**
+ * @brief Generic printer of the given format string into the specified output.
+ *
+ * Alternatively, ly_write() can be used.
+ *
+ * @param[in] out Output specification.
+ * @param[in] format format string to be printed.
+ * @return LY_ERR value, number of the printed bytes is updated in lyout::printed.
+ */
 LY_ERR ly_print(struct lyout *out, const char *format, ...);
 
+/**
+ * @brief Flush the output from any internal buffers and clean any auxiliary data.
+ * @param[in] out Output specification.
+ */
 void ly_print_flush(struct lyout *out);
 
-LY_ERR ly_write(struct lyout *out, const char *buf, size_t count);
+/**
+ * @brief Generic printer of the given string buffer into the specified output.
+ *
+ * Alternatively, ly_print() can be used.
+ *
+ * As an extension for printing holes (skipping some data until they are known),
+ * ly_write_skip() and ly_write_skipped() can be used.
+ *
+ * @param[in] out Output specification.
+ * @param[in] buf Memory buffer with the data to print.
+ * @param[in] len Length of the data to print in the @p buf.
+ * @return LY_ERR value, number of the printed bytes is updated in lyout::printed.
+ */
+LY_ERR ly_write(struct lyout *out, const char *buf, size_t len);
+
+/**
+ * @brief Create a hole in the output data that will be filled later.
+ *
+ * @param[in] out Output specification.
+ * @param[in] len Length of the created hole.
+ * @param[out] position Position of the hole, value must be later provided to the ly_write_skipped() call.
+ * @return LY_ERR value. The number of the printed bytes is updated in lyout::printed
+ * only in case the data are really written into the output.
+ */
+LY_ERR ly_write_skip(struct lyout *out, size_t len, size_t *position);
+
+/**
+ * @brief Write data into the hole at given position.
+ *
+ * @param[in] out Output specification.
+ * @param[in] position Position of the hole to fill, the value was provided by ly_write_skip().
+ * @param[in] buf Memory buffer with the data to print.
+ * @param[in] len Length of the data to print in the @p buf. Not that the length must correspond
+ * to the len value specified in the corresponding ly_write_skip() call.
+ * @return LY_ERR value. The number of the printed bytes is updated in lyout::printed
+ * only in case the data are really written into the output.
+ */
+LY_ERR ly_write_skipped(struct lyout *out, size_t position, const char *buf, size_t len);
 
 #endif /* LY_PRINTER_INTERNAL_H_ */
diff --git a/src/printer_schema.c b/src/printer_schema.c
new file mode 100644
index 0000000..c07ea79
--- /dev/null
+++ b/src/printer_schema.c
@@ -0,0 +1,193 @@
+/**
+ * @file printer_schema.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Generic schema printers functions.
+ *
+ * Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "common.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "printer_internal.h"
+#include "tree_schema.h"
+
+/**
+ * @brief Common schema printer.
+ *
+ * @param[in] out Prepared structure defining the type and details of the printer output.
+ * @param[in] module Schema to print.
+ * @param[in] format Output format.
+ * @param[in] line_length Maximum characters to be printed on a line, 0 for unlimited. Only for #LYS_OUT_TREE printer.
+ * @param[in] options Schema output options (see @ref schemaprinterflags).
+ * @return LY_ERR value, number of the printed bytes is updated in lyout::printed.
+ */
+static LY_ERR
+lys_print_(struct lyout *out, const struct lys_module *module, LYS_OUTFORMAT format, int UNUSED(line_length), int UNUSED(options))
+{
+    LY_ERR ret;
+
+    switch (format) {
+    case LYS_OUT_YANG:
+        ret = yang_print_parsed(out, module);
+        break;
+    case LYS_OUT_YANG_COMPILED:
+        ret = yang_print_compiled(out, module);
+        break;
+    /* TODO not yet implemented
+    case LYS_OUT_YIN:
+        lys_disable_deviations((struct lys_module *)module);
+        ret = yin_print_model(out, module);
+        lys_enable_deviations((struct lys_module *)module);
+        break;
+    case LYS_OUT_TREE:
+        ret = tree_print_model(out, module, target_node, line_length, options);
+        break;
+    case LYS_OUT_INFO:
+        ret = info_print_model(out, module, target_node);
+        break;
+    case LYS_OUT_JSON:
+        ret = jsons_print_model(out, module, target_node);
+        break;
+    */
+    default:
+        LOGERR(module->ctx, LY_EINVAL, "Unknown output format.");
+        ret = LY_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+API ssize_t
+lys_print_file(FILE *f, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
+{
+    struct lyout out;
+    LY_ERR ret;
+
+    LY_CHECK_ARG_RET(NULL, f, module, LY_EINVAL);
+
+    memset(&out, 0, sizeof out);
+    out.ctx = module->ctx;
+    out.type = LYOUT_STREAM;
+    out.method.f = f;
+
+    ret = lys_print_(&out, module, format, line_length, options);
+    if (ret) {
+        /* error */
+        return (-1) * ret;
+    } else {
+        /* success */
+        return (ssize_t)out.printed;
+    }
+}
+
+API ssize_t
+lys_print_path(const char *path, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
+{
+    FILE *f;
+    ssize_t ret;
+
+    LY_CHECK_ARG_RET(NULL, path, module, LY_EINVAL);
+
+    f = fopen(path, "w");
+    if (!f) {
+        LOGERR(module->ctx, LY_ESYS, "Failed to open file \"%s\" (%s).", path, strerror(errno));
+        return LY_ESYS;
+    }
+
+    ret = lys_print_file(f, module, format, line_length, options);
+    fclose(f);
+    return ret;
+}
+
+API ssize_t
+lys_print_fd(int fd, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
+{
+    LY_ERR ret;
+    struct lyout out;
+
+    LY_CHECK_ARG_RET(NULL, fd >= 0, module, LY_EINVAL);
+
+    memset(&out, 0, sizeof out);
+    out.ctx = module->ctx;
+    out.type = LYOUT_FD;
+    out.method.fd = fd;
+
+    ret = lys_print_(&out, module, format, line_length, options);
+
+    if (out.type == LYOUT_FDSTREAM) {
+        /* close temporary stream based on the given file descriptor */
+        fclose(out.method.f);
+        /* move the original file descriptor to the end of the output file */
+        lseek(fd, 0, SEEK_END);
+    }
+
+    if (ret) {
+        /* error */
+        return (-1) * ret;
+    } else {
+        /* success */
+        return (ssize_t)out.printed;
+    }
+}
+
+API ssize_t
+lys_print_mem(char **strp, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
+{
+    struct lyout out;
+    LY_ERR ret;
+
+    LY_CHECK_ARG_RET(NULL, strp, module, LY_EINVAL);
+
+    memset(&out, 0, sizeof out);
+    out.ctx = module->ctx;
+    out.type = LYOUT_MEMORY;
+
+    ret = lys_print_(&out, module, format, line_length, options);
+    if (ret) {
+        /* error */
+        *strp = NULL;
+        return (-1) * ret;
+    } else {
+        /* success */
+        *strp = out.method.mem.buf;
+        return (ssize_t)out.printed;
+    }
+}
+
+API ssize_t
+lys_print_clb(ssize_t (*writeclb)(void *arg, const void *buf, size_t count), void *arg, const struct lys_module *module,
+              LYS_OUTFORMAT format, int line_length, int options)
+{
+    LY_ERR ret;
+    struct lyout out;
+
+    LY_CHECK_ARG_RET(NULL, writeclb, module, LY_EINVAL);
+
+    memset(&out, 0, sizeof out);
+    out.ctx = module->ctx;
+    out.type = LYOUT_CALLBACK;
+    out.method.clb.f = writeclb;
+    out.method.clb.arg = arg;
+
+    ret = lys_print_(&out, module, format, line_length, options);
+    if (ret) {
+        /* error */
+        return (-1) * ret;
+    } else {
+        /* success */
+        return (ssize_t)out.printed;
+    }
+}
diff --git a/src/printer_schema.h b/src/printer_schema.h
index 7ad6154..613e768 100644
--- a/src/printer_schema.h
+++ b/src/printer_schema.h
@@ -15,8 +15,11 @@
 #ifndef LY_PRINTER_SCHEMA_H_
 #define LY_PRINTER_SCHEMA_H_
 
+#include <stdio.h>
 #include <unistd.h>
 
+#include "tree_schema.h"
+
 /**
  * @brief Print schema tree in the specified format into a memory block.
  * It is up to caller to free the returned string by free().
diff --git a/src/printer_xml.c b/src/printer_xml.c
new file mode 100644
index 0000000..37ebc0d
--- /dev/null
+++ b/src/printer_xml.c
@@ -0,0 +1,560 @@
+/**
+ * @file printer_xml.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief XML printer for libyang data structure
+ *
+ * Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "common.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "log.h"
+#include "plugins_types.h"
+#include "printer_data.h"
+#include "printer_internal.h"
+#include "tree.h"
+#include "tree_data.h"
+#include "tree_schema.h"
+#include "xml.h"
+
+/**
+ * @brief XML printer context.
+ */
+struct xmlpr_ctx {
+    struct lyout *out;  /**< output specification */
+    unsigned int level; /**< current indentation level: 0 - no formatting, >= 1 indentation levels */
+    int options;        /**< [Data printer flags](@ref dataprinterflags) */
+    int toplevel;       /**< top-level flag */
+};
+
+#define LEVEL ctx->level                     /**< current level */
+#define INDENT ((LEVEL) ? (LEVEL)*2 : 0),""  /**< indentation parameters for printer functions */
+#define LEVEL_INC if (LEVEL) {LEVEL++;}      /**< increase indentation level */
+#define LEVEL_DEC if (LEVEL) {LEVEL--;}      /**< decrease indentation level */
+
+/**
+ * TODO
+ */
+struct mlist {
+    struct mlist *next;
+    struct lys_module *module;
+} *mlist = NULL, *mlist_new;
+
+#if 0
+static LY_ERR
+modlist_add(struct mlist **mlist, const struct lys_module *mod)
+{
+    struct mlist *iter;
+
+    for (iter = *mlist; iter; iter = iter->next) {
+        if (mod == iter->module) {
+            break;
+        }
+    }
+
+    if (!iter) {
+        iter = malloc(sizeof *iter);
+        LY_CHECK_ERR_RET(!iter, LOGMEM(mod->ctx), LY_EMEM);
+        iter->next = *mlist;
+        iter->module = (struct lys_module *)mod;
+        *mlist = iter;
+    }
+
+    return LY_SUCCESS;
+}
+#endif
+
+/**
+ * TODO
+ */
+static void
+xml_print_ns(struct xmlpr_ctx *ctx, const struct lyd_node *node)
+{
+    struct lyd_node *next, *cur, *child;
+    struct lyd_attr *attr;
+    struct mlist *mlist = NULL, *miter;
+    int r = 0;
+
+#if 0
+    const struct lys_module *wdmod = NULL;
+
+    /* add node attribute modules */
+    for (attr = node->attr; attr; attr = attr->next) {
+        if (!strcmp(node->schema->name, "filter") &&
+                (!strcmp(node->schema->module->name, "ietf-netconf") ||
+                 !strcmp(node->schema->module->name, "notifications"))) {
+            /* exception for NETCONF's filter attributes */
+            continue;
+        } else {
+            r = modlist_add(&mlist, lys_main_module(attr->annotation->module));
+        }
+        if (r) {
+            goto print;
+        }
+    }
+#endif
+
+    /* add node children nodes and attribute modules */
+    switch (node->schema->nodetype) {
+    case LYS_LEAFLIST:
+    case LYS_LEAF:
+        /* TODO ietf-netconf-with-defaults namespace */
+#if 0
+        if (node->dflt && (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG))) {
+            /* get with-defaults module and print its namespace */
+            wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
+            if (wdmod && modlist_add(&mlist, wdmod)) {
+                goto print;
+            }
+        }
+#endif
+        break;
+    case LYS_CONTAINER:
+    case LYS_LIST:
+#if 0
+    case LYS_RPC:
+    case LYS_ACTION:
+    case LYS_NOTIF:
+        if (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG)) {
+            /* get with-defaults module and print its namespace */
+            wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
+            if (wdmod && modlist_add(&mlist, wdmod)) {
+                goto print;
+            }
+        }
+#endif
+        LY_LIST_FOR(((struct lyd_node_inner*)node)->child, child) {
+            LYD_TREE_DFS_BEGIN(child, next, cur) {
+                for (attr = cur->attr; attr; attr = attr->next) {
+                    if (!strcmp(cur->schema->name, "filter") &&
+                            (!strcmp(cur->schema->module->name, "ietf-netconf") ||
+                             !strcmp(cur->schema->module->name, "notifications"))) {
+                        /* exception for NETCONF's filter attributes */
+                        continue;
+                    } else {
+                        /* TODO annotations r = modlist_add(&mlist, lys_main_module(attr->annotation->module)); */
+                    }
+                    if (r) {
+                        goto print;
+                    }
+                }
+            LYD_TREE_DFS_END(child, next, cur)}
+        }
+        break;
+    default:
+        break;
+    }
+
+print:
+    /* print used namespaces */
+    while (mlist) {
+        miter = mlist;
+        mlist = mlist->next;
+
+        ly_print(ctx->out, " xmlns:%s=\"%s\"", miter->module->prefix, miter->module->ns);
+        free(miter);
+    }
+}
+
+/**
+ * TODO
+ */
+static LY_ERR
+xml_print_attrs(struct xmlpr_ctx *ctx, const struct lyd_node *node)
+{
+    (void) ctx;
+    (void) node;
+
+#if 0
+    struct lyd_attr *attr;
+    const char **prefs, **nss;
+    const char *xml_expr = NULL, *mod_name;
+    uint32_t ns_count, i;
+    int rpc_filter = 0;
+    const struct lys_module *wdmod = NULL;
+    char *p;
+    size_t len;
+
+    LY_PRINT_SET;
+
+    /* with-defaults */
+    if (node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
+        if ((node->dflt && (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG))) ||
+                (!node->dflt && (options & LYP_WD_ALL_TAG) && lyd_wd_default((struct lyd_node_leaf_list *)node))) {
+            /* we have implicit OR explicit default node */
+            /* get with-defaults module */
+            wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
+            if (wdmod) {
+                /* print attribute only if context include with-defaults schema */
+                ly_print(out, " %s:default=\"true\"", wdmod->prefix);
+            }
+        }
+    }
+    /* technically, check for the extension get-filter-element-attributes from ietf-netconf */
+    if (!strcmp(node->schema->name, "filter")
+            && (!strcmp(node->schema->module->name, "ietf-netconf") || !strcmp(node->schema->module->name, "notifications"))) {
+        rpc_filter = 1;
+    }
+
+    for (attr = node->attr; attr; attr = attr->next) {
+        if (rpc_filter) {
+            /* exception for NETCONF's filter's attributes */
+            if (!strcmp(attr->name, "select")) {
+                /* xpath content, we have to convert the JSON format into XML first */
+                xml_expr = transform_json2xml(node->schema->module, attr->value_str, 0, &prefs, &nss, &ns_count);
+                if (!xml_expr) {
+                    /* error */
+                    return EXIT_FAILURE;
+                }
+
+                for (i = 0; i < ns_count; ++i) {
+                    ly_print(out, " xmlns:%s=\"%s\"", prefs[i], nss[i]);
+                }
+                free(prefs);
+                free(nss);
+            }
+            ly_print(out, " %s=\"", attr->name);
+        } else {
+            ly_print(out, " %s:%s=\"", attr->annotation->module->prefix, attr->name);
+        }
+
+        switch (attr->value_type) {
+        case LY_TYPE_BINARY:
+        case LY_TYPE_STRING:
+        case LY_TYPE_BITS:
+        case LY_TYPE_ENUM:
+        case LY_TYPE_BOOL:
+        case LY_TYPE_DEC64:
+        case LY_TYPE_INT8:
+        case LY_TYPE_INT16:
+        case LY_TYPE_INT32:
+        case LY_TYPE_INT64:
+        case LY_TYPE_UINT8:
+        case LY_TYPE_UINT16:
+        case LY_TYPE_UINT32:
+        case LY_TYPE_UINT64:
+            if (attr->value_str) {
+                /* xml_expr can contain transformed xpath */
+                lyxml_dump_text(out, xml_expr ? xml_expr : attr->value_str, LYXML_DATA_ATTR);
+            }
+            break;
+
+        case LY_TYPE_IDENT:
+            if (!attr->value_str) {
+                break;
+            }
+            p = strchr(attr->value_str, ':');
+            assert(p);
+            len = p - attr->value_str;
+            mod_name = attr->annotation->module->name;
+            if (!strncmp(attr->value_str, mod_name, len) && !mod_name[len]) {
+                lyxml_dump_text(out, ++p, LYXML_DATA_ATTR);
+            } else {
+                /* avoid code duplication - use instance-identifier printer which gets necessary namespaces to print */
+                goto printinst;
+            }
+            break;
+        case LY_TYPE_INST:
+printinst:
+            xml_expr = transform_json2xml(node->schema->module, ((struct lyd_node_leaf_list *)node)->value_str, 1,
+                                          &prefs, &nss, &ns_count);
+            if (!xml_expr) {
+                /* error */
+                return EXIT_FAILURE;
+            }
+
+            for (i = 0; i < ns_count; ++i) {
+                ly_print(out, " xmlns:%s=\"%s\"", prefs[i], nss[i]);
+            }
+            free(prefs);
+            free(nss);
+
+            lyxml_dump_text(out, xml_expr, LYXML_DATA_ATTR);
+            lydict_remove(node->schema->module->ctx, xml_expr);
+            break;
+
+        /* LY_TYPE_LEAFREF not allowed */
+        case LY_TYPE_EMPTY:
+            break;
+
+        default:
+            /* error */
+            LOGINT(node->schema->module->ctx);
+            return EXIT_FAILURE;
+        }
+
+        ly_print(out, "\"");
+
+        if (xml_expr) {
+            lydict_remove(node->schema->module->ctx, xml_expr);
+        }
+    }
+#endif
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Print generic XML element despite of the data node type.
+ *
+ * Prints the element name, attributes and necessary namespaces.
+ *
+ * @param[in] ctx XML printer context.
+ * @param[in] node Data node to be printed.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+xml_print_node_open(struct xmlpr_ctx *ctx, const struct lyd_node *node)
+{
+    if (ctx->toplevel || !node->parent || node->schema->module != node->parent->schema->module) {
+        /* print "namespace" */
+        ly_print(ctx->out, "%*s<%s xmlns=\"%s\"", INDENT, node->schema->name, node->schema->module->ns);
+    } else {
+        ly_print(ctx->out, "%*s<%s", INDENT, node->schema->name);
+    }
+
+    if (ctx->toplevel) {
+        xml_print_ns(ctx, node);
+        ctx->toplevel = 0;
+    }
+
+    LY_CHECK_RET(xml_print_attrs(ctx, node));
+
+    return LY_SUCCESS;
+}
+
+static LY_ERR xml_print_node(struct xmlpr_ctx *ctx, const struct lyd_node *node);
+
+/**
+ * @brief Print XML element representing lyd_node_term.
+ *
+ * @param[in] ctx XML printer context.
+ * @param[in] node Data node to be printed.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+xml_print_term(struct xmlpr_ctx *ctx, const struct lyd_node_term *node)
+{
+    LY_CHECK_RET(xml_print_node_open(ctx, (struct lyd_node *)node));
+
+    if (((struct lysc_node_leaf*)node->schema)->type->plugin->flags & LY_TYPE_FLAG_PREFIXES) {
+        /* TODO get prefixes from the value and print namespaces */
+    }
+
+    if (!node->value.canonized || !node->value.canonized[0]) {
+        ly_print(ctx->out, "/>%s", LEVEL ? "\n" : "");
+    } else {
+        ly_print(ctx->out, ">");
+        lyxml_dump_text(ctx->out, node->value.canonized, 0);
+        ly_print(ctx->out, "</%s>%s", node->schema->name, LEVEL ? "\n" : "");
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Print XML element representing lyd_node_inner.
+ *
+ * @param[in] ctx XML printer context.
+ * @param[in] node Data node to be printed.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+xml_print_inner(struct xmlpr_ctx *ctx, const struct lyd_node_inner *node)
+{
+    LY_ERR ret;
+    struct lyd_node *child;
+
+    LY_CHECK_RET(xml_print_node_open(ctx, (struct lyd_node *)node));
+
+    if (!node->child) {
+        ly_print(ctx->out, "/>%s", ctx->level ? "\n" : "");
+        return LY_SUCCESS;
+    }
+
+    /* children */
+    ly_print(ctx->out, ">%s", ctx->level ? "\n" : "");
+
+    LEVEL_INC;
+    LY_LIST_FOR(node->child, child) {
+        ret = xml_print_node(ctx, child);
+        LY_CHECK_ERR_RET(ret, LEVEL_DEC, ret);
+    }
+    LEVEL_DEC;
+
+    ly_print(ctx->out, "%*s</%s>%s", INDENT, node->schema->name, LEVEL ? "\n" : "");
+
+    return LY_SUCCESS;
+}
+
+#if 0
+static int
+xml_print_anydata(struct lyout *out, int level, const struct lyd_node *node, int toplevel, int options)
+{
+    char *buf;
+    struct lyd_node_anydata *any = (struct lyd_node_anydata *)node;
+    struct lyd_node *iter;
+    const char *ns;
+
+    LY_PRINT_SET;
+
+    if (toplevel || !node->parent || nscmp(node, node->parent)) {
+        /* print "namespace" */
+        ns = lyd_node_module(node)->ns;
+        ly_print(out, "%*s<%s xmlns=\"%s\"", INDENT, node->schema->name, ns);
+    } else {
+        ly_print(out, "%*s<%s", INDENT, node->schema->name);
+    }
+
+    if (toplevel) {
+        xml_print_ns(out, node, options);
+    }
+    if (xml_print_attrs(out, node, options)) {
+        return EXIT_FAILURE;
+    }
+    if (!(void*)any->value.tree || (any->value_type == LYD_ANYDATA_CONSTSTRING && !any->value.str[0])) {
+        /* no content */
+        ly_print(out, "/>%s", level ? "\n" : "");
+    } else {
+        if (any->value_type == LYD_ANYDATA_DATATREE) {
+            /* print namespaces in the anydata data tree */
+            LY_TREE_FOR(any->value.tree, iter) {
+                xml_print_ns(out, iter, options);
+            }
+        }
+        /* close opening tag ... */
+        ly_print(out, ">");
+        /* ... and print anydata content */
+        switch (any->value_type) {
+        case LYD_ANYDATA_CONSTSTRING:
+            lyxml_dump_text(out, any->value.str, LYXML_DATA_ELEM);
+            break;
+        case LYD_ANYDATA_DATATREE:
+            if (any->value.tree) {
+                if (level) {
+                    ly_print(out, "\n");
+                }
+                LY_TREE_FOR(any->value.tree, iter) {
+                    if (xml_print_node(out, level ? level + 1 : 0, iter, 0, (options & ~(LYP_WITHSIBLINGS | LYP_NETCONF)))) {
+                        return EXIT_FAILURE;
+                    }
+                }
+            }
+            break;
+        case LYD_ANYDATA_XML:
+            lyxml_print_mem(&buf, any->value.xml, (level ? LYXML_PRINT_FORMAT | LYXML_PRINT_NO_LAST_NEWLINE : 0)
+                                                   | LYXML_PRINT_SIBLINGS);
+            ly_print(out, "%s%s", level ? "\n" : "", buf);
+            free(buf);
+            break;
+        case LYD_ANYDATA_SXML:
+            /* print without escaping special characters */
+            ly_print(out, "%s", any->value.str);
+            break;
+        case LYD_ANYDATA_JSON:
+        case LYD_ANYDATA_LYB:
+            /* JSON and LYB format is not supported */
+            LOGWRN(node->schema->module->ctx, "Unable to print anydata content (type %d) as XML.", any->value_type);
+            break;
+        case LYD_ANYDATA_STRING:
+        case LYD_ANYDATA_SXMLD:
+        case LYD_ANYDATA_JSOND:
+        case LYD_ANYDATA_LYBD:
+            /* dynamic strings are used only as input parameters */
+            assert(0);
+            break;
+        }
+
+        /* closing tag */
+        ly_print(out, "</%s>%s", node->schema->name, level ? "\n" : "");
+    }
+
+    LY_PRINT_RET(node->schema->module->ctx);
+}
+#endif
+
+/**
+ * @brief Print XML element representing lyd_node.
+ *
+ * @param[in] ctx XML printer context.
+ * @param[in] node Data node to be printed.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+xml_print_node(struct xmlpr_ctx *ctx, const struct lyd_node *node)
+{
+    LY_ERR ret = LY_SUCCESS;
+
+#if 0
+    if (!lyd_wd_toprint(node, ctx->options)) {
+        /* wd says do not print */
+        return EXIT_SUCCESS;
+    }
+#endif
+
+    switch (node->schema->nodetype) {
+#if 0
+    case LYS_NOTIF:
+    case LYS_ACTION:
+#endif
+    case LYS_CONTAINER:
+    case LYS_LIST:
+        ret = xml_print_inner(ctx, (const struct lyd_node_inner*)node);
+        break;
+    case LYS_LEAF:
+    case LYS_LEAFLIST:
+        ret = xml_print_term(ctx, (const struct lyd_node_term*)node);
+        break;
+#if 0
+    case LYS_ANYXML:
+    case LYS_ANYDATA:
+        ret = xml_print_anydata(ctx, node);
+        break;
+#endif
+    default:
+        LOGINT(node->schema->module->ctx);
+        ret = LY_EINT;
+        break;
+    }
+
+    return ret;
+}
+
+LY_ERR
+xml_print_data(struct lyout *out, const struct lyd_node *root, int options)
+{
+    const struct lyd_node *node;
+    struct xmlpr_ctx ctx_ = {.out = out, .level = (options & LYDP_FORMAT ? 1 : 0), .options = options, .toplevel = 1}, *ctx = &ctx_;
+
+    if (!root) {
+        if (out->type == LYOUT_MEMORY || out->type == LYOUT_CALLBACK) {
+            ly_print(out, "");
+        }
+        goto finish;
+    }
+
+    /* content */
+    LY_LIST_FOR(root, node) {
+        if (xml_print_node(ctx, node)) {
+            return EXIT_FAILURE;
+        }
+        if (!(options & LYDP_WITHSIBLINGS)) {
+            break;
+        }
+    }
+
+finish:
+    ly_print_flush(out);
+    return LY_SUCCESS;
+}
+
diff --git a/src/printer_yang.c b/src/printer_yang.c
index 2dfd5e6..c429094 100755
--- a/src/printer_yang.c
+++ b/src/printer_yang.c
@@ -15,27 +15,52 @@
 #include "common.h"
 
 #include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
+#include "extensions.h"
+#include "log.h"
 #include "printer_internal.h"
+#include "tree.h"
 #include "tree_schema.h"
 #include "tree_schema_internal.h"
 #include "xpath.h"
 
-#define LEVEL ctx->level
-#define INDENT (LEVEL)*2,""
-
+/**
+ * @brief Types of the YANG printers
+ */
 enum schema_type {
-    YPR_PARSED,
-    YPR_COMPILED
+    YPR_PARSED,   /**< YANG printer of the parsed schema */
+    YPR_COMPILED  /**< YANG printer of the compiled schema */
 };
 
+/**
+ * @brief YANG printer context.
+ */
 struct ypr_ctx {
-    struct lyout *out;
-    unsigned int level;
-    const struct lys_module *module;
-    enum schema_type schema;
+    struct lyout *out;               /**< output specification */
+    unsigned int level;              /**< current indentation level: 0 - no formatting, >= 1 indentation levels */
+    const struct lys_module *module; /**< schema to print */
+    enum schema_type schema;         /**< type of the schema to print */
 };
 
+#define LEVEL ctx->level             /**< current level */
+#define INDENT (LEVEL)*2,""          /**< indentation parameters for printer functions */
+
+/**
+ * @brief Print the given text as content of a double quoted YANG string,
+ * including encoding characters that have special meanings. The quotation marks
+ * are not printed.
+ *
+ * Follows RFC 7950, section 6.1.3.
+ *
+ * @param[in] out Output specification.
+ * @param[in] text String to be printed.
+ * @param[in] len Length of the string from @p text to be printed. In case of 0,
+ * the @p text is printed completely as a NULL-terminated string.
+ */
 static void
 ypr_encode(struct lyout *out, const char *text, int len)
 {
diff --git a/src/set.c b/src/set.c
index 9769145..b858491 100644
--- a/src/set.c
+++ b/src/set.c
@@ -12,9 +12,14 @@
  *     https://opensource.org/licenses/BSD-3-Clause
  */
 
-#include "libyang.h"
 #include "common.h"
 
+#include <stdlib.h>
+#include <string.h>
+
+#include "log.h"
+#include "set.h"
+
 API struct ly_set *
 ly_set_new(void)
 {
diff --git a/src/set.h b/src/set.h
index f16feae..9f73064 100644
--- a/src/set.h
+++ b/src/set.h
@@ -15,6 +15,8 @@
 #ifndef LY_SET_H_
 #define LY_SET_H_
 
+#include "log.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/src/tree.h b/src/tree.h
new file mode 100644
index 0000000..d700a5b
--- /dev/null
+++ b/src/tree.h
@@ -0,0 +1,158 @@
+/**
+ * @file tree.h
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief libyang geenric macros and functions to work with YANG schema or data trees.
+ *
+ * Copyright (c) 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef LY_TREE_H_
+#define LY_TREE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Macro selector for other LY_ARRAY_* macros, do not use directly!
+ */
+#define LY_ARRAY_SELECT(_1, _2, NAME, ...) NAME
+
+/**
+ * @brief Helper macro to go through sized-arrays with a pointer iterator.
+ *
+ * Use with opening curly bracket (`{`).
+ *
+ * @param[in] ARRAY Array to go through
+ * @param[in] TYPE Type of the records in the ARRAY
+ * @param[out] ITER Iterating pointer to the item being processed in each loop
+ */
+#define LY_ARRAY_FOR_ITER(ARRAY, TYPE, ITER) \
+    for (ITER = ARRAY; \
+         (ARRAY) && ((void*)ITER - (void*)ARRAY)/(sizeof(TYPE)) < (*((uint32_t*)(ARRAY) - 1)); \
+         ITER = (void*)((TYPE*)ITER + 1))
+
+/**
+ * @brief Helper macro to go through sized-arrays with a numeric iterator.
+ *
+ * Use with opening curly bracket (`{`).
+ *
+ * To access an item with the INDEX value, use always LY_ARRAY_INDEX macro!
+ *
+ * @param[in] ARRAY Array to go through
+ * @param[out] INDEX Iterating index of the item being processed in each loop
+ */
+#define LY_ARRAY_FOR_INDEX(ARRAY, INDEX) \
+    for (INDEX = 0; \
+         ARRAY && INDEX < (*((uint32_t*)(ARRAY) - 1)); \
+         ++INDEX)
+
+/**
+ * @defgroup schematree Schema Tree
+ * @{
+ *
+ * Data structures and functions to manipulate and access schema tree.
+ */
+
+/**
+ * @brief Get a number of records in the ARRAY.
+ *
+ * Does not check if array exists!
+ */
+#define LY_ARRAY_SIZE(ARRAY) (*((uint32_t*)(ARRAY) - 1))
+
+/**
+ * @brief Sized-array iterator (for-loop).
+ *
+ * Use with opening curly bracket (`{`).
+ *
+ * There are 2 variants:
+ *
+ *     LY_ARRAY_FOR(ARRAY, TYPE, ITER)
+ *
+ * Where ARRAY is a sized-array to go through, TYPE is the type of the items in the ARRAY and ITER is a pointer variable
+ * providing the items of the ARRAY in the loops. This functionality is provided by LY_ARRAY_FOR_ITER macro
+ *
+ *     LY_ARRAY_FOR(ARRAY, INDEX)
+ *
+ * The ARRAY is again a sized-array to go through, the INDEX is a variable (unsigned integer) for storing iterating ARRAY's index
+ * to access the items of ARRAY in the loops. This functionality is provided by LY_ARRAY_FOR_INDEX macro.
+ */
+#define LY_ARRAY_FOR(ARRAY, ...) LY_ARRAY_SELECT(__VA_ARGS__, LY_ARRAY_FOR_ITER, LY_ARRAY_FOR_INDEX)(ARRAY, __VA_ARGS__)
+
+/**
+ * @brief Macro to iterate via all sibling elements without affecting the list itself
+ *
+ * Works for all types of nodes despite it is data or schema tree, but all the
+ * parameters must be pointers to the same type.
+ *
+ * Use with opening curly bracket (`{`). All parameters must be of the same type.
+ *
+ * @param START Pointer to the starting element.
+ * @param ELEM Iterator.
+ */
+#define LY_LIST_FOR(START, ELEM) \
+    for ((ELEM) = (START); \
+         (ELEM); \
+         (ELEM) = (ELEM)->next)
+
+/**
+ * @brief Macro to iterate via all sibling elements allowing to modify the list itself (e.g. removing elements)
+ *
+ * Use with opening curly bracket (`{`). All parameters must be of the same type.
+ *
+ * @param START Pointer to the starting element.
+ * @param NEXT Temporary storage to allow removing of the current iterator content.
+ * @param ELEM Iterator.
+ */
+#define LY_LIST_FOR_SAFE(START, NEXT, ELEM) \
+    for ((ELEM) = (START); \
+         (ELEM) ? (NEXT = (ELEM)->next, 1) : 0; \
+         (ELEM) = (NEXT))
+
+/**
+ * @brief YANG built-in types
+ */
+typedef enum
+{
+    LY_TYPE_UNKNOWN = 0, /**< Unknown type */
+    LY_TYPE_BINARY, /**< Any binary data ([RFC 6020 sec 9.8](http://tools.ietf.org/html/rfc6020#section-9.8)) */
+    LY_TYPE_UINT8, /**< 8-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
+    LY_TYPE_UINT16, /**< 16-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
+    LY_TYPE_UINT32, /**< 32-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
+    LY_TYPE_UINT64, /**< 64-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
+    LY_TYPE_STRING, /**< Human-readable string ([RFC 6020 sec 9.4](http://tools.ietf.org/html/rfc6020#section-9.4)) */
+    LY_TYPE_BITS, /**< A set of bits or flags ([RFC 6020 sec 9.7](http://tools.ietf.org/html/rfc6020#section-9.7)) */
+    LY_TYPE_BOOL, /**< "true" or "false" ([RFC 6020 sec 9.5](http://tools.ietf.org/html/rfc6020#section-9.5)) */
+    LY_TYPE_DEC64, /**< 64-bit signed decimal number ([RFC 6020 sec 9.3](http://tools.ietf.org/html/rfc6020#section-9.3))*/
+    LY_TYPE_EMPTY, /**< A leaf that does not have any value ([RFC 6020 sec 9.11](http://tools.ietf.org/html/rfc6020#section-9.11)) */
+    LY_TYPE_ENUM, /**< Enumerated strings ([RFC 6020 sec 9.6](http://tools.ietf.org/html/rfc6020#section-9.6)) */
+    LY_TYPE_IDENT, /**< A reference to an abstract identity ([RFC 6020 sec 9.10](http://tools.ietf.org/html/rfc6020#section-9.10)) */
+    LY_TYPE_INST, /**< References a data tree node ([RFC 6020 sec 9.13](http://tools.ietf.org/html/rfc6020#section-9.13)) */
+    LY_TYPE_LEAFREF, /**< A reference to a leaf instance ([RFC 6020 sec 9.9](http://tools.ietf.org/html/rfc6020#section-9.9))*/
+    LY_TYPE_UNION, /**< Choice of member types ([RFC 6020 sec 9.12](http://tools.ietf.org/html/rfc6020#section-9.12)) */
+    LY_TYPE_INT8, /**< 8-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
+    LY_TYPE_INT16, /**< 16-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
+    LY_TYPE_INT32, /**< 32-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
+    LY_TYPE_INT64, /**< 64-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
+} LY_DATA_TYPE;
+#define LY_DATA_TYPE_COUNT 20 /**< Number of different types */
+
+/**
+ * @brief Stringified YANG built-in data types
+ */
+extern const char* ly_data_type2str[LY_DATA_TYPE_COUNT];
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LY_TREE_H_ */
diff --git a/src/tree_data.c b/src/tree_data.c
new file mode 100644
index 0000000..7ecb5e9
--- /dev/null
+++ b/src/tree_data.c
@@ -0,0 +1,257 @@
+/**
+ * @file tree_schema.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Schema tree implementation
+ *
+ * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "common.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "tree.h"
+#include "tree_data.h"
+#include "tree_data_internal.h"
+#include "tree_schema.h"
+
+static int
+cmp_str(const char *refstr, const char *str, size_t strlen)
+{
+
+    if (strlen) {
+        int r = strncmp(refstr, str, strlen);
+        if (!r && !refstr[strlen]) {
+            return 0;
+        } else {
+            return 1;
+        }
+    } else {
+        return strcmp(refstr, str);
+    }
+}
+
+API const struct lyd_node *
+lyd_search(const struct lyd_node *first, const struct lys_module *module,
+          const char *name, size_t name_len, uint16_t nodetype, const char *value, size_t value_len)
+{
+    const struct lyd_node *node = NULL;
+    const struct lysc_node *snode;
+
+    LY_CHECK_ARG_RET(NULL, module, name, NULL);
+    if (!nodetype) {
+        nodetype = 0xffff;
+    }
+
+    LY_LIST_FOR(first, node) {
+        snode = node->schema;
+        if (!(snode->nodetype & nodetype)) {
+            continue;
+        }
+        if (snode->module != module) {
+            continue;
+        }
+
+        if (cmp_str(snode->name, name, name_len)) {
+            continue;
+        }
+
+        if (value) {
+            if (snode->nodetype == LYS_LIST) {
+                /* TODO handle value as keys of the list instance */
+            } else if (snode->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
+                if (cmp_str(((struct lyd_node_term*)node)->value.canonized, value, value_len)) {
+                    continue;
+                }
+            } else {
+                continue;
+            }
+        }
+
+        /* all criteria passed */
+        return node;
+    }
+    return NULL;
+}
+
+static struct lyd_node *
+lyd_parse_mem_(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options, va_list ap)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct lyd_node *result = NULL;
+    const struct lyd_node *rpc_act = NULL, *data_tree = NULL, *iter;
+    const char *yang_data_name = NULL;
+
+    if (lyd_parse_check_options(ctx, options, __func__)) {
+        return NULL;
+    }
+
+    if (options & LYD_OPT_RPCREPLY) {
+        rpc_act = va_arg(ap, const struct lyd_node *);
+        if (!rpc_act || rpc_act->parent || !(rpc_act->schema->nodetype & (LYS_ACTION | LYS_LIST | LYS_CONTAINER))) {
+            LOGERR(ctx, LY_EINVAL, "Data parser invalid variable parameter (const struct lyd_node *rpc_act).");
+            return NULL;
+        }
+    }
+    if (options & (LYD_OPT_RPC | LYD_OPT_NOTIF | LYD_OPT_RPCREPLY)) {
+        data_tree = va_arg(ap, const struct lyd_node *);
+        if (data_tree) {
+            if (options & LYD_OPT_NOEXTDEPS) {
+                LOGERR(ctx, LY_EINVAL, "%s: invalid parameter (variable arg const struct lyd_node *data_tree and LYD_OPT_NOEXTDEPS set).",
+                       __func__);
+                return NULL;
+            }
+
+            LY_LIST_FOR(data_tree, iter) {
+                if (iter->parent) {
+                    /* a sibling is not top-level */
+                    LOGERR(ctx, LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *data_tree).", __func__);
+                    return NULL;
+                }
+            }
+
+            /* move it to the beginning */
+            for (; data_tree->prev->next; data_tree = data_tree->prev);
+
+            /* LYD_OPT_NOSIBLINGS cannot be set in this case */
+            if (options & LYD_OPT_NOSIBLINGS) {
+                LOGERR(ctx, LY_EINVAL, "%s: invalid parameter (variable arg const struct lyd_node *data_tree with LYD_OPT_NOSIBLINGS).", __func__);
+                return NULL;
+            }
+        }
+    }
+    if (options & LYD_OPT_DATA_TEMPLATE) {
+        yang_data_name = va_arg(ap, const char *);
+    }
+
+    if (!format) {
+        /* TODO try to detect format from the content */
+    }
+
+    switch (format) {
+    case LYD_XML:
+        ret = lyd_parse_xml(ctx, data, options, &result);
+        break;
+#if 0
+    case LYD_JSON:
+        ret = lyd_parse_json(ctx, data, options, rpc_act, data_tree, yang_data_name);
+        break;
+    case LYD_LYB:
+        ret = lyd_parse_lyb(ctx, data, options, data_tree, yang_data_name, NULL);
+        break;
+#endif
+    case LYD_UNKNOWN:
+        LOGINT(ctx);
+        break;
+    }
+
+    if (ret) {
+        lyd_free_all(result);
+        result = NULL;
+    }
+
+    return result;
+}
+
+API struct lyd_node *
+lyd_parse_mem(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options, ...)
+{
+    va_list ap;
+    struct lyd_node *result;
+
+    va_start(ap, options);
+    result = lyd_parse_mem_(ctx, data, format, options, ap);
+    va_end(ap);
+
+    return result;
+}
+
+static struct lyd_node *
+lyd_parse_fd_(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options, va_list ap)
+{
+    struct lyd_node *result;
+    size_t length;
+    char *addr;
+
+    LY_CHECK_ARG_RET(ctx, ctx, NULL);
+    if (fd < 0) {
+        LOGARG(ctx, fd);
+        return NULL;
+    }
+
+    LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
+    result = lyd_parse_mem_(ctx, addr ? addr : "", format, options, ap);
+    ly_munmap(addr, length);
+
+    return result;
+}
+
+API struct lyd_node *
+lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options, ...)
+{
+    struct lyd_node *ret;
+    va_list ap;
+
+    va_start(ap, options);
+    ret = lyd_parse_fd_(ctx, fd, format, options, ap);
+    va_end(ap);
+
+    return ret;
+}
+
+API struct lyd_node *
+lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options, ...)
+{
+    int fd;
+    struct lyd_node *result;
+    size_t len;
+    va_list ap;
+
+    LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
+
+    fd = open(path, O_RDONLY);
+    LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
+
+    if (!format) {
+        /* unknown format - try to detect it from filename's suffix */
+        len = strlen(path);
+
+        /* ignore trailing whitespaces */
+        for (; len > 0 && isspace(path[len - 1]); len--);
+
+        if (len >= 5 && !strncmp(&path[len - 4], ".xml", 4)) {
+            format = LYD_XML;
+#if 0
+        } else if (len >= 6 && !strncmp(&path[len - 5], ".json", 5)) {
+            format = LYD_JSON;
+        } else if (len >= 5 && !strncmp(&path[len - 4], ".lyb", 4)) {
+            format = LYD_LYB;
+#endif
+        } /* else still unknown, try later to detect it from the content */
+    }
+
+    va_start(ap, options);
+    result = lyd_parse_fd_(ctx, fd, format, options, ap);
+
+    va_end(ap);
+    close(fd);
+
+    return result;
+}
+
+
+
+
diff --git a/src/tree_data.h b/src/tree_data.h
new file mode 100644
index 0000000..9fe0af6
--- /dev/null
+++ b/src/tree_data.h
@@ -0,0 +1,571 @@
+/**
+ * @file tree_data.h
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief libyang representation of YANG data trees.
+ *
+ * Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef LY_TREE_DATA_H_
+#define LY_TREE_DATA_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "log.h"
+#include "tree.h"
+#include "tree_schema.h"
+
+struct ly_ctx;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup datatree Data Tree
+ * @{
+ *
+ * Data structures and functions to manipulate and access instance data tree.
+ */
+
+/**
+ * @brief Macro to iterate via all elements in a data tree. This is the opening part
+ * to the #LYD_TREE_DFS_END - they always have to be used together.
+ *
+ * The function follows deep-first search algorithm:
+ * <pre>
+ *     1
+ *    / \
+     *   2   4
+ *  /   / \
+     * 3   5   6
+ * </pre>
+ *
+ * Use the same parameters for #LY_TREE_DFS_BEGIN and #LY_TREE_DFS_END. While
+ * START can be any of the lyd_node* types, NEXT and ELEM variables are expected
+ * to be pointers to a generic struct lyd_node.
+ *
+ * Since the next node is selected as part of #LYD_TREE_DFS_END, do not use
+ * continue statement between the #LYD_TREE_DFS_BEGIN and #LYD_TREE_DFS_END.
+ *
+ * Use with opening curly bracket '{' after the macro.
+ *
+ * @param START Pointer to the starting element processed first.
+ * @param NEXT Temporary storage, do not use.
+ * @param ELEM Iterator intended for use in the block.
+ */
+#define LYD_TREE_DFS_BEGIN(START, NEXT, ELEM) \
+    for ((ELEM) = (NEXT) = (START); \
+         (ELEM); \
+         (ELEM) = (NEXT))
+
+/**
+ * @brief Macro to iterate via all elements in a tree. This is the closing part
+ * to the #LYD_TREE_DFS_BEGIN - they always have to be used together.
+ *
+ * Use the same parameters for #LYD_TREE_DFS_BEGIN and #LYD_TREE_DFS_END. While
+ * START can be any of the lyd_node* types, NEXT and ELEM variables are expected
+ * to be pointers to a generic struct lyd_node.
+ *
+ * Use with closing curly bracket '}' after the macro.
+ *
+ * @param START Pointer to the starting element processed first.
+ * @param NEXT Temporary storage, do not use.
+ * @param ELEM Iterator intended for use in the block.
+ */
+
+#define LYD_TREE_DFS_END(START, NEXT, ELEM) \
+    /* select element for the next run - children first */ \
+    (NEXT) = (struct lyd_node*)lyd_node_children((struct lyd_node*)ELEM); \
+    if (!(NEXT)) { \
+        /* no children */ \
+        if ((ELEM) == (struct lyd_node*)(START)) { \
+            /* we are done, (START) has no children */ \
+            break; \
+        } \
+        /* try siblings */ \
+        (NEXT) = (ELEM)->next; \
+    } \
+    while (!(NEXT)) { \
+        /* parent is already processed, go to its sibling */ \
+        (ELEM) = (struct lyd_node*)(ELEM)->parent; \
+        /* no siblings, go back through parents */ \
+        if ((ELEM)->parent == (START)->parent) { \
+            /* we are done, no next element to process */ \
+            break; \
+        } \
+        (NEXT) = (ELEM)->next; \
+    }
+
+/**
+ * @brief Data input/output formats supported by libyang [parser](@ref howtodataparsers) and
+ * [printer](@ref howtodataprinters) functions.
+ */
+typedef enum {
+    LYD_UNKNOWN = 0,     /**< unknown format, used as return value in case of error */
+    LYD_XML,             /**< XML format of the instance data */
+#if 0
+    LYD_JSON,            /**< JSON format of the instance data */
+    LYD_LYB,             /**< LYB format of the instance data */
+#endif
+} LYD_FORMAT;
+
+/**
+ * @brief List of possible value types stored in ::lyd_node_anydata.
+ */
+typedef enum {
+    LYD_ANYDATA_CONSTSTRING = 0x00, /**< value is constant string (const char *) which is internally duplicated for
+                                         storing in the anydata structure; XML sensitive characters (such as & or \>)
+                                         are automatically escaped when the anydata is printed in XML format. */
+    LYD_ANYDATA_STRING = 0x01,      /**< value is dynamically allocated string (char*), so the data are used directly
+                                         without duplication and caller is supposed to not manipulate with the data
+                                         after a successful call (including calling free() on the provided data); XML
+                                         sensitive characters (such as & or \>) are automatically escaped when the
+                                         anydata is printed in XML format */
+    LYD_ANYDATA_JSON = 0x02,        /**< value is string containing the data modeled by YANG and encoded as I-JSON. The
+                                         string is handled as constant string. In case of using the value as input
+                                         parameter, the #LYD_ANYDATA_JSOND can be used for dynamically allocated
+                                         string. */
+    LYD_ANYDATA_JSOND = 0x03,       /**< In case of using value as input parameter, this enumeration is supposed to be
+                                         used for dynamically allocated strings (it is actually combination of
+                                         #LYD_ANYDATA_JSON and #LYD_ANYDATA_STRING (and it can be also specified as
+                                         ORed value of the mentioned values. */
+    LYD_ANYDATA_SXML = 0x04,        /**< value is string containing the serialized XML data. The string is handled as
+                                         constant string. In case of using the value as input parameter, the
+                                         #LYD_ANYDATA_SXMLD can be used for dynamically allocated string. */
+    LYD_ANYDATA_SXMLD = 0x05,       /**< In case of using serialized XML value as input parameter, this enumeration is
+                                         supposed to be used for dynamically allocated strings (it is actually
+                                         combination of #LYD_ANYDATA_SXML and #LYD_ANYDATA_STRING (and it can be also
+                                         specified as ORed value of the mentioned values). */
+    LYD_ANYDATA_XML = 0x08,         /**< value is struct lyxml_elem*, the structure is directly connected into the
+                                         anydata node without duplication, caller is supposed to not manipulate with the
+                                         data after a successful call (including calling lyxml_free() on the provided
+                                         data) */
+    LYD_ANYDATA_DATATREE = 0x10,    /**< value is struct lyd_node* (first sibling), the structure is directly connected
+                                         into the anydata node without duplication, caller is supposed to not manipulate
+                                         with the data after a successful call (including calling lyd_free() on the
+                                         provided data) */
+    LYD_ANYDATA_LYB = 0x20,         /**< value is a memory with serialized data tree in LYB format. The data are handled
+                                         as a constant string. In case of using the value as input parameter,
+                                         the #LYD_ANYDATA_LYBD can be used for dynamically allocated string. */
+    LYD_ANYDATA_LYBD = 0x21,        /**< In case of using LYB value as input parameter, this enumeration is
+                                         supposed to be used for dynamically allocated strings (it is actually
+                                         combination of #LYD_ANYDATA_LYB and #LYD_ANYDATA_STRING (and it can be also
+                                         specified as ORed value of the mentioned values). */
+} LYD_ANYDATA_VALUETYPE;
+
+/** @} */
+
+/**
+ * @brief YANG data representation
+ */
+struct lyd_value {
+    const char *canonized;          /**< string representation of value (for comparison, printing,...), canonized according to the
+                                          rules implemented in the type's canonization callback (if any). */
+    union {
+        const char *string;         /**< original, non-canonized string value. Useful for example for unions where the type (and therefore
+                                         the cannonization rules) can change by changing value (e.g. leafref target) somewhere else. */
+        int8_t boolean;              /**< 0 as false, 1 as true */
+        int64_t dec64;               /**< decimal64: value = dec64 / 10^fraction-digits  */
+        struct lysc_type_bitenum_item *enum_item;  /**< pointer to the definition of the enumeration value */
+        struct lysc_ident *ident;    /**< pointer to the schema definition of the identityref value */
+        int8_t int8;                 /**< 8-bit signed integer */
+        int16_t int16;               /**< 16-bit signed integer */
+        int32_t int32;               /**< 32-bit signed integer */
+        int64_t int64;               /**< 64-bit signed integer */
+        uint8_t uint8;               /**< 8-bit unsigned integer */
+        uint16_t uint16;             /**< 16-bit signed integer */
+        uint32_t uint32;             /**< 32-bit signed integer */
+        uint64_t uint64;             /**< 64-bit signed integer */
+        void *ptr;                   /**< generic data type structure used to store the data */
+    };  /**< The union is just a list of shorthands to possible values stored by a type's plugin. libyang works only with the canonized string,
+             this specific data type storage is just to simplify use of the values by the libyang users. */
+    LY_DATA_TYPE type;               /**< type of the value in the node, mainly for union to avoid repeating of type detection */
+};
+
+/**
+ * @brief Attribute structure.
+ *
+ * The structure provides information about attributes of a data element. Such attributes must map to
+ * annotations as specified in RFC 7952. The only exception is the filter type (in NETCONF get operations)
+ * and edit-config's operation attributes. In XML, they are represented as standard XML attributes. In JSON,
+ * they are represented as JSON elements starting with the '@' character (for more information, see the
+ * YANG metadata RFC.
+ *
+ */
+struct lyd_attr {
+    struct lyd_node *parent;         /**< data node where the attribute is placed */
+    struct lyd_attr *next;           /**< pointer to the next attribute of the same element */
+    void *annotation;                /**< TODO pointer to the attribute/annotation's definition */
+    const char *name;                /**< attribute name */
+    struct lyd_value value;            /**< attribute's value representation */
+};
+
+
+#define LYD_NODE_INNER (LYS_CONTAINER|LYS_LIST) /**< Schema nodetype mask for lyd_node_inner */
+#define LYD_NODE_TERM (LYS_LEAF|LYS_LEAFLIST)   /**< Schema nodetype mask for lyd_node_term */
+#define LYD_NODE_ANY (LYS_ANYDATA)   /**< Schema nodetype mask for lyd_node_any */
+
+/**
+ * @brief Generic structure for a data node.
+ */
+struct lyd_node {
+    uint32_t hash;                   /**< hash of this particular node (module name + schema name + key string values if list) */
+    const struct lysc_node *schema;  /**< pointer to the schema definition of this node */
+    struct lyd_node_inner *parent;   /**< pointer to the parent node, NULL in case of root node */
+    struct lyd_node *next;           /**< pointer to the next sibling node (NULL if there is no one) */
+    struct lyd_node *prev;           /**< pointer to the previous sibling node \note Note that this pointer is
+                                          never NULL. If there is no sibling node, pointer points to the node
+                                          itself. In case of the first node, this pointer points to the last
+                                          node in the list. */
+    struct lyd_attr *attr;           /**< pointer to the list of attributes of this node */
+
+#ifdef LY_ENABLED_LYD_PRIV
+    void *priv;                      /**< private user data, not used by libyang */
+#endif
+};
+
+/**
+ * @brief Data node structure for the inner data tree nodes - containers and lists.
+ */
+struct lyd_node_inner {
+    uint32_t hash;                   /**< hash of this particular node (module name + schema name + key string values if list) */
+    const struct lysc_node *schema;  /**< pointer to the schema definition of this node */
+    struct lyd_node_inner *parent;   /**< pointer to the parent node, NULL in case of root node */
+    struct lyd_node *next;           /**< pointer to the next sibling node (NULL if there is no one) */
+    struct lyd_node *prev;           /**< pointer to the previous sibling node \note Note that this pointer is
+                                          never NULL. If there is no sibling node, pointer points to the node
+                                          itself. In case of the first node, this pointer points to the last
+                                          node in the list. */
+    struct lyd_attr *attr;           /**< pointer to the list of attributes of this node */
+
+#ifdef LY_ENABLED_LYD_PRIV
+    void *priv;                      /**< private user data, not used by libyang */
+#endif
+
+    struct lyd_node *child;          /**< pointer to the first child node. */
+    struct hash_table *children_ht;  /**< hash table with all the direct children (except keys for a list, lists without keys) */
+};
+
+/**
+ * @brief Data node structure for the terminal data tree nodes - leafs and leaf-lists.
+ */
+struct lyd_node_term {
+    uint32_t hash;                   /**< hash of this particular node (module name + schema name + key string values if list) */
+    const struct lysc_node *schema;  /**< pointer to the schema definition of this node */
+    struct lyd_node_inner *parent;   /**< pointer to the parent node, NULL in case of root node */
+    struct lyd_node *next;           /**< pointer to the next sibling node (NULL if there is no one) */
+    struct lyd_node *prev;           /**< pointer to the previous sibling node \note Note that this pointer is
+                                          never NULL. If there is no sibling node, pointer points to the node
+                                          itself. In case of the first node, this pointer points to the last
+                                          node in the list. */
+    struct lyd_attr *attr;           /**< pointer to the list of attributes of this node */
+
+#ifdef LY_ENABLED_LYD_PRIV
+    void *priv;                      /**< private user data, not used by libyang */
+#endif
+
+    struct lyd_value value;            /**< node's value representation */
+};
+
+/**
+ * @brief Data node structure for the anydata data tree nodes - anydatas and anyxmls.
+ */
+struct lyd_node_any {
+    uint32_t hash;                   /**< hash of this particular node (module name + schema name + key string values if list) */
+    const struct lysc_node *schema;  /**< pointer to the schema definition of this node */
+    struct lyd_node_inner *parent;   /**< pointer to the parent node, NULL in case of root node */
+    struct lyd_node *next;           /**< pointer to the next sibling node (NULL if there is no one) */
+    struct lyd_node *prev;           /**< pointer to the previous sibling node \note Note that this pointer is
+                                          never NULL. If there is no sibling node, pointer points to the node
+                                          itself. In case of the first node, this pointer points to the last
+                                          node in the list. */
+    struct lyd_attr *attr;           /**< pointer to the list of attributes of this node */
+
+#ifdef LY_ENABLED_LYD_PRIV
+    void *priv;                      /**< private user data, not used by libyang */
+#endif
+
+    /* TODO - anydata representation */
+};
+
+/**
+ * @defgroup dataparseroptions Data parser options
+ * @ingroup datatree
+ *
+ * Various options to change the data tree parsers behavior.
+ *
+ * Default behavior:
+ * - in case of XML, parser reads all data from its input (file, memory, XML tree) including the case of not well-formed
+ * XML document (multiple top-level elements) and if there is an unknown element, it is skipped including its subtree
+ * (see the next point). This can be changed by the #LYD_OPT_NOSIBLINGS option which make parser to read only a single
+ * tree (with a single root element) from its input.
+ * - parser silently ignores the data without a matching node in schema trees. If the caller want to stop
+ * parsing in case of presence of unknown data, the #LYD_OPT_STRICT can be used. The strict mode is useful for
+ * NETCONF servers, since NETCONF clients should always send data according to the capabilities announced by the server.
+ * On the other hand, the default non-strict mode is useful for clients receiving data from NETCONF server since
+ * clients are not required to understand everything the server does. Of course, the optimal strategy for clients is
+ * to use filtering to get only the required data. Having an unknown element of the known namespace is always an error.
+ * The behavior can be changed by #LYD_OPT_STRICT option.
+ * - using obsolete statements (status set to obsolete) just generates a warning, but the processing continues. The
+ * behavior can be changed by #LYD_OPT_OBSOLETE option.
+ * - parser expects that the provided data provides complete datastore content (both the configuration and state data)
+ * and performs data validation according to all YANG rules. This can be a problem in case of representing NETCONF's
+ * subtree filter data, edit-config's data or other type of data set - such data do not represent a complete data set
+ * and some of the validation rules can fail. Therefore there are other options (within lower 8 bits) to make parser
+ * to accept such a data.
+ * - when parser evaluates when-stmt condition to false, a validation error is raised. If the
+ * #LYD_OPT_WHENAUTODEL is used, the invalid node is silently removed instead of an error. The option (and also this default
+ * behavior) takes effect only in case of #LYD_OPT_DATA or #LYD_OPT_CONFIG type of data.
+ * @{
+ */
+
+#define LYD_OPT_DATA       0x00 /**< Default type of data - complete datastore content with configuration as well as
+                                     state data. To handle possibly missing (but by default required) ietf-yang-library
+                                     data, use #LYD_OPT_DATA_NO_YANGLIB or #LYD_OPT_DATA_ADD_YANGLIB options. */
+#define LYD_OPT_CONFIG     0x01 /**< A configuration datastore - complete datastore without state data.
+                                     Validation modifications:
+                                     - status data are not allowed */
+#define LYD_OPT_GET        0x02 /**< Data content from a NETCONF reply message to the NETCONF \<get\> operation.
+                                     Validation modifications:
+                                     - mandatory nodes can be omitted
+                                     - leafrefs and instance-identifier resolution is allowed to fail
+                                     - list's keys/unique nodes are not required (so duplication is not checked)
+                                     - must and when evaluation skipped */
+#define LYD_OPT_GETCONFIG  0x04 /**< Data content from a NETCONF reply message to the NETCONF \<get-config\> operation
+                                     Validation modifications:
+                                     - mandatory nodes can be omitted
+                                     - leafrefs and instance-identifier resolution is allowed to fail
+                                     - list's keys/unique nodes are not required (so duplication is not checked)
+                                     - must and when evaluation skipped
+                                     - status data are not allowed */
+#define LYD_OPT_EDIT       0x08 /**< Content of the NETCONF \<edit-config\>'s config element.
+                                     Validation modifications:
+                                     - mandatory nodes can be omitted
+                                     - leafrefs and instance-identifier resolution is allowed to fail
+                                     - must and when evaluation skipped
+                                     - status data are not allowed */
+#define LYD_OPT_RPC        0x10 /**< Data represents RPC or action input parameters. */
+#define LYD_OPT_RPCREPLY   0x20 /**< Data represents RPC or action output parameters (maps to NETCONF <rpc-reply> data). */
+#define LYD_OPT_NOTIF      0x40 /**< Data represents an event notification data. */
+#define LYD_OPT_NOTIF_FILTER 0x80 /**< Data represents a filtered event notification data.
+                                       Validation modification:
+                                       - the only requirement is that the data tree matches the schema tree */
+#define LYD_OPT_TYPEMASK   0x10000ff /**< Mask to filter data type options. Always only a single data type option (only
+                                          single bit from the lower 8 bits) can be set. */
+
+/* 0x100 reserved, used internally */
+#define LYD_OPT_STRICT     0x0200 /**< Instead of silent ignoring data without schema definition, raise an error. */
+#define LYD_OPT_DESTRUCT   0x0400 /**< Free the provided XML tree during parsing the data. With this option, the
+                                       provided XML tree is affected and all successfully parsed data are freed.
+                                       This option is applicable only to lyd_parse_xml() function. */
+#define LYD_OPT_OBSOLETE   0x0800 /**< Raise an error when an obsolete statement (status set to obsolete) is used. */
+#define LYD_OPT_NOSIBLINGS 0x1000 /**< Parse only a single XML tree from the input. This option applies only to
+                                       XML input data. */
+#define LYD_OPT_TRUSTED    0x2000 /**< Data comes from a trusted source and it is not needed to validate them. Data
+                                       are connected with the schema, but the most validation checks (mandatory nodes,
+                                       list instance uniqueness, etc.) are not performed. This option does not make
+                                       sense for lyd_validate() so it is ignored by this function. */
+#define LYD_OPT_WHENAUTODEL 0x4000 /**< Automatically delete subtrees with false when-stmt condition. The flag is
+                                        applicable only in combination with #LYD_OPT_DATA and #LYD_OPT_CONFIG flags.
+                                        If used, libyang will not generate a validation error. */
+#define LYD_OPT_NOEXTDEPS  0x8000 /**< Allow external dependencies (external leafrefs, instance-identifiers, must,
+                                       and when) to not be resolved/satisfied during validation. */
+#define LYD_OPT_DATA_NO_YANGLIB  0x10000 /**< Ignore (possibly) missing ietf-yang-library data. Applicable only with #LYD_OPT_DATA. */
+#define LYD_OPT_DATA_ADD_YANGLIB 0x20000 /**< Add missing ietf-yang-library data into the validated data tree. Applicable
+                                              only with #LYD_OPT_DATA. If some ietf-yang-library data are present, they are
+                                              preserved and option is ignored. */
+#define LYD_OPT_VAL_DIFF 0x40000 /**< Flag only for validation, store all the data node changes performed by the validation
+                                      in a diff structure. */
+#define LYD_OPT_DATA_TEMPLATE 0x1000000 /**< Data represents YANG data template. */
+
+/**@} dataparseroptions */
+
+/**
+ * @brief Get the node's children list if any.
+ *
+ * Decides the node's type and in case it has a children list, returns it.
+ * @param[in] node Node to check.
+ * @return Pointer to the first child node (if any) of the \p node.
+ */
+const struct lyd_node *lyd_node_children(const struct lyd_node *node);
+
+/**
+ * @brief Find the node, in the list, satisfying the given restrictions.
+ *
+ * @param[in] first Starting child node for search.
+ * @param[in] module Module of the node to find (mandatory argument).
+ * @param[in] name Name of the node to find (mandatory argument).
+ * @param[in] name_len Optional length of the @p name argument in case it is not NULL-terminated string.
+ * @param[in] nodetype Optional mask for the nodetype of the node to find, 0 is understood as all nodetypes.
+ * @param[in] value Optional restriction for lyd_node_term nodes to select node with the specific value.
+ * @param[in] value_len Optional length of the @p value argument in case it is not NULL-terminated string.
+ * @return The sibling node of the @p first (or itself), satisfying the given restrictions.
+ * @return NULL in case there is no node satisfying the restrictions.
+ */
+const struct lyd_node *lyd_search(const struct lyd_node *first, const struct lys_module *module,
+                                  const char *name, size_t name_len, uint16_t nodetype, const char *value, size_t value_len);
+
+/**
+ * @brief Parse (and validate) data from memory.
+ *
+ * In case of LY_XML format, the data string is parsed completely. It means that when it contains
+ * a non well-formed XML with multiple root elements, all those sibling XML trees are parsed. The
+ * returned data node is a root of the first tree with other trees connected via the next pointer.
+ * This behavior can be changed by #LYD_OPT_NOSIBLINGS option.
+ *
+ * @param[in] ctx Context to connect with the data tree being built here.
+ * @param[in] data Serialized data in the specified format.
+ * @param[in] format Format of the input data to be parsed.
+ * @param[in] options Parser options, see @ref parseroptions. \p format LYD_LYB uses #LYD_OPT_TRUSTED implicitly.
+ * @param[in] ... Variable arguments depend on \p options. If they include:
+ *                - #LYD_OPT_DATA:
+ *                - #LYD_OPT_CONFIG:
+ *                - #LYD_OPT_GET:
+ *                - #LYD_OPT_GETCONFIG:
+ *                - #LYD_OPT_EDIT:
+ *                  - no variable arguments expected.
+ *                - #LYD_OPT_RPC:
+ *                - #LYD_OPT_NOTIF:
+ *                  - struct lyd_node *data_tree - additional data tree that will be used
+ *                    when checking any "when" or "must" conditions in the parsed tree that require
+ *                    some nodes outside their subtree. It must be a list of top-level elements!
+ *                - #LYD_OPT_RPCREPLY:
+ *                  - const struct ::lyd_node *rpc_act - pointer to the whole RPC or (top-level) action operation
+ *                    data tree (the request) of the reply.
+ *                  - const struct ::lyd_node *data_tree - additional data tree that will be used
+ *                    when checking any "when" or "must" conditions in the parsed tree that require
+ *                    some nodes outside their subtree. It must be a list of top-level elements!
+ * @return Pointer to the built data tree or NULL in case of empty \p data. To free the returned structure,
+ *         use lyd_free(). In these cases, the function sets #ly_errno to LY_SUCCESS. In case of error,
+ *         #ly_errno contains appropriate error code (see #LY_ERR).
+ */
+struct lyd_node *lyd_parse_mem(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options, ...);
+
+/**
+ * @brief Read (and validate) data from the given file descriptor.
+ *
+ * \note Current implementation supports only reading data from standard (disk) file, not from sockets, pipes, etc.
+ *
+ * In case of LY_XML format, the file content is parsed completely. It means that when it contains
+ * a non well-formed XML with multiple root elements, all those sibling XML trees are parsed. The
+ * returned data node is a root of the first tree with other trees connected via the next pointer.
+ * This behavior can be changed by #LYD_OPT_NOSIBLINGS option.
+ *
+ * @param[in] ctx Context to connect with the data tree being built here.
+ * @param[in] fd The standard file descriptor of the file containing the data tree in the specified format.
+ * @param[in] format Format of the input data to be parsed.
+ * @param[in] options Parser options, see @ref parseroptions. \p format LYD_LYB uses #LYD_OPT_TRUSTED implicitly.
+ * @param[in] ... Variable arguments depend on \p options. If they include:
+ *                - #LYD_OPT_DATA:
+ *                - #LYD_OPT_CONFIG:
+ *                - #LYD_OPT_GET:
+ *                - #LYD_OPT_GETCONFIG:
+ *                - #LYD_OPT_EDIT:
+ *                  - no variable arguments expected.
+ *                - #LYD_OPT_RPC:
+ *                - #LYD_OPT_NOTIF:
+ *                  - struct lyd_node *data_tree - additional data tree that will be used
+ *                    when checking any "when" or "must" conditions in the parsed tree that require
+ *                    some nodes outside their subtree. It must be a list of top-level elements!
+ *                - #LYD_OPT_RPCREPLY:
+ *                  - const struct ::lyd_node *rpc_act - pointer to the whole RPC or action operation data
+ *                    tree (the request) of the reply.
+ *                  - const struct ::lyd_node *data_tree - additional data tree that will be used
+ *                    when checking any "when" or "must" conditions in the parsed tree that require
+ *                    some nodes outside their subtree. It must be a list of top-level elements!
+ * @return Pointer to the built data tree or NULL in case of empty file. To free the returned structure,
+ *         use lyd_free(). In these cases, the function sets #ly_errno to LY_SUCCESS. In case of error,
+ *         #ly_errno contains appropriate error code (see #LY_ERR).
+ */
+struct lyd_node *lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options, ...);
+
+/**
+ * @brief Read (and validate) data from the given file path.
+ *
+ * In case of LY_XML format, the file content is parsed completely. It means that when it contains
+ * a non well-formed XML with multiple root elements, all those sibling XML trees are parsed. The
+ * returned data node is a root of the first tree with other trees connected via the next pointer.
+ * This behavior can be changed by #LYD_OPT_NOSIBLINGS option.
+ *
+ * @param[in] ctx Context to connect with the data tree being built here.
+ * @param[in] path Path to the file containing the data tree in the specified format.
+ * @param[in] format Format of the input data to be parsed.
+ * @param[in] options Parser options, see @ref parseroptions. \p format LYD_LYB uses #LYD_OPT_TRUSTED implicitly.
+ * @param[in] ... Variable arguments depend on \p options. If they include:
+ *                - #LYD_OPT_DATA:
+ *                - #LYD_OPT_CONFIG:
+ *                - #LYD_OPT_GET:
+ *                - #LYD_OPT_GETCONFIG:
+ *                - #LYD_OPT_EDIT:
+ *                  - no variable arguments expected.
+ *                - #LYD_OPT_RPC:
+ *                - #LYD_OPT_NOTIF:
+ *                  - struct lyd_node *data_tree - additional data tree that will be used
+ *                    when checking any "when" or "must" conditions in the parsed tree that require
+ *                    some nodes outside their subtree. It must be a list of top-level elements!
+ *                - #LYD_OPT_RPCREPLY:
+ *                  - const struct ::lyd_node *rpc_act - pointer to the whole RPC or action operation data
+ *                    tree (the request) of the reply.
+ *                  - const struct ::lyd_node *data_tree - additional data tree that will be used
+ *                    when checking any "when" or "must" conditions in the parsed tree that require
+ *                    some nodes outside their subtree. It must be a list of top-level elements!
+ * @return Pointer to the built data tree or NULL in case of empty file. To free the returned structure,
+ *         use lyd_free(). In these cases, the function sets #ly_errno to LY_SUCCESS. In case of error,
+ *         #ly_errno contains appropriate error code (see #LY_ERR).
+ */
+struct lyd_node *lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options, ...);
+
+/**
+ * @brief Free all the nodes in the data tree.
+ *
+ * @param[in] node Any of the nodes inside the tree.
+ */
+void lyd_free_all(struct lyd_node *node);
+
+/**
+ * @brief Free (and unlink) the specified data (sub)tree.
+ *
+ * __PARTIAL CHANGE__ - validate after the final change on the data tree (see @ref howtodatamanipulators).
+ *
+ * @param[in] node Root of the (sub)tree to be freed.
+ */
+void lyd_free_tree(struct lyd_node *node);
+
+/**
+ * @brief Unlink the specified data subtree. All referenced namespaces are copied.
+ *
+ * Note, that the node's connection with the schema tree is kept. Therefore, in case of
+ * reconnecting the node to a data tree using lyd_paste() it is necessary to paste it
+ * to the appropriate place in the data tree following the schema.
+ *
+ * __PARTIAL CHANGE__ - validate after the final change on the data tree (see @ref howtodatamanipulators).
+ *
+ * @param[in] node Data tree node to be unlinked (together with all children).
+ * @return LY_SUCCESS for success
+ * @return LY_E* values in case of error
+ */
+LY_ERR lyd_unlink_tree(struct lyd_node *node);
+
+/**
+ * @brief Destroy data attribute.
+ *
+ * @param[in] ctx Context where the attribute was created.
+ * @param[in] attr Attribute to destroy
+ * @param[in] recursive Zero to destroy only the attribute (the attribute list is corrected),
+ * non-zero to destroy also all the subsequent attributes in the list.
+ */
+void lyd_free_attr(struct ly_ctx *ctx, struct lyd_attr *attr, int recursive);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LY_TREE_DATA_H_ */
diff --git a/src/tree_data_free.c b/src/tree_data_free.c
new file mode 100644
index 0000000..1337abf
--- /dev/null
+++ b/src/tree_data_free.c
@@ -0,0 +1,224 @@
+/**
+ * @file tree_data_free.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Freeing functions for data tree structures
+ *
+ * Copyright (c) 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "common.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "hash_table.h"
+#include "log.h"
+#include "tree.h"
+#include "tree_data.h"
+#include "tree_schema.h"
+#include "tree_data_internal.h"
+
+API LY_ERR
+lyd_unlink_tree(struct lyd_node *node)
+{
+    struct lyd_node *iter;
+    struct lyd_node **first_sibling;
+
+    LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
+
+    if (node->parent) {
+        first_sibling = lyd_node_children_p((struct lyd_node*)node->parent);
+    }
+
+    /* unlink from siblings */
+    if (node->prev->next) {
+        node->prev->next = node->next;
+    }
+    if (node->next) {
+        node->next->prev = node->prev;
+    } else {
+        /* unlinking the last node */
+        if (node->parent) {
+            iter = *first_sibling;
+        } else {
+            iter = node->prev;
+            while (iter->prev != node) {
+                iter = iter->prev;
+            }
+        }
+        /* update the "last" pointer from the first node */
+        iter->prev = node->prev;
+    }
+
+    /* unlink from parent */
+    if (node->parent) {
+        if (*first_sibling == node) {
+            /* the node is the first child */
+            *first_sibling = node->next;
+        }
+        lyd_unlink_hash(node);
+        node->parent = NULL;
+    }
+
+    node->next = NULL;
+    node->prev = node;
+
+    return EXIT_SUCCESS;
+}
+
+/**
+ * @brief Free the YANG data value content.
+ * @param[in] ctx libyang context
+ * @param[in] value Data value structure to clean - since it is mostly part of other structure, only content is freed.
+ */
+static void
+lyd_free_value(struct ly_ctx *ctx, struct lyd_value *value)
+{
+    FREE_STRING(ctx, value->canonized);
+}
+
+API void
+lyd_free_attr(struct ly_ctx *ctx, struct lyd_attr *attr, int recursive)
+{
+    struct lyd_attr *iter;
+
+    LY_CHECK_ARG_RET(NULL, ctx, );
+    if (!attr) {
+        return;
+    }
+
+    if (attr->parent) {
+        if (attr->parent->attr == attr) {
+            if (recursive) {
+                attr->parent->attr = NULL;
+            } else {
+                attr->parent->attr = attr->next;
+            }
+        } else {
+            for (iter = attr->parent->attr; iter->next != attr; iter = iter->next);
+            if (iter->next) {
+                if (recursive) {
+                    iter->next = NULL;
+                } else {
+                    iter->next = attr->next;
+                }
+            }
+        }
+    }
+
+    if (!recursive) {
+        attr->next = NULL;
+    }
+
+    for(iter = attr; iter; ) {
+        attr = iter;
+        iter = iter->next;
+
+        FREE_STRING(ctx, attr->name);
+        lyd_free_value(ctx, &attr->value);
+        free(attr);
+    }
+}
+
+/**
+ * @brief Free Data (sub)tree.
+ * @param[in] ctx libyang context.
+ * @param[in] node Data node to be freed.
+ * @param[in] top Recursion flag to unlink the root of the subtree being freed.
+ */
+static void
+lyd_free_subtree(struct ly_ctx *ctx, struct lyd_node *node, int top)
+{
+    struct lyd_node *iter, *next;
+    struct lyd_node *children;
+
+    assert(node);
+
+    /* remove children hash table in case of inner data node */
+    if (node->schema->nodetype & LYD_NODE_INNER) {
+        lyht_free(((struct lyd_node_inner*)node)->children_ht);
+        ((struct lyd_node_inner*)node)->children_ht = NULL;
+
+        /* free the children */
+        children = (struct lyd_node*)lyd_node_children(node);
+        LY_LIST_FOR_SAFE(children, next, iter) {
+            lyd_free_subtree(ctx, iter, 0);
+        }
+    } else if (node->schema->nodetype & LYD_NODE_ANY) {
+        /* TODO anydata */
+#if 0
+        switch (((struct lyd_node_anydata *)node)->value_type) {
+        case LYD_ANYDATA_CONSTSTRING:
+        case LYD_ANYDATA_SXML:
+        case LYD_ANYDATA_JSON:
+            FREE_STRING(node->schema->module->ctx, ((struct lyd_node_anydata *)node)->value.str);
+            break;
+        case LYD_ANYDATA_DATATREE:
+            lyd_free_withsiblings(((struct lyd_node_anydata *)node)->value.tree);
+            break;
+        case LYD_ANYDATA_XML:
+            lyxml_free_withsiblings(node->schema->module->ctx, ((struct lyd_node_anydata *)node)->value.xml);
+            break;
+        case LYD_ANYDATA_LYB:
+            free(((struct lyd_node_anydata *)node)->value.mem);
+            break;
+        case LYD_ANYDATA_STRING:
+        case LYD_ANYDATA_SXMLD:
+        case LYD_ANYDATA_JSOND:
+        case LYD_ANYDATA_LYBD:
+            /* dynamic strings are used only as input parameters */
+            assert(0);
+            break;
+        }
+#endif
+    } else if (node->schema->nodetype & LYD_NODE_TERM) {
+        lyd_free_value(ctx, &((struct lyd_node_term*)node)->value);
+    }
+
+    /* free the node's attributes */
+    lyd_free_attr(ctx, node->attr, 1);
+
+    /* unlink only the nodes from the first level, nodes in subtree are freed all, so no unlink is needed */
+    if (top) {
+        lyd_unlink_tree(node);
+    }
+
+    free(node);
+}
+
+API void
+lyd_free_tree(struct lyd_node *node)
+{
+    if (!node) {
+        return;
+    }
+
+    lyd_free_subtree(node->schema->module->ctx, node, 1);
+}
+
+API void
+lyd_free_all(struct lyd_node *node)
+{
+    struct lyd_node *iter, *next;
+
+    if (!node) {
+        return;
+    }
+
+    /* get the first top-level sibling */
+    for (; node->parent; node = (struct lyd_node*)node->parent);
+    while (node->prev->next) {
+        node = node->prev;
+    }
+
+    LY_LIST_FOR_SAFE(node, next, iter) {
+        /* in case of the top-level nodes (node->parent is NULL), no unlinking needed */
+        lyd_free_subtree(node->schema->module->ctx, node, node->parent ? 1 : 0);
+    }
+}
diff --git a/src/tree_data_hash.c b/src/tree_data_hash.c
new file mode 100644
index 0000000..546b2fd
--- /dev/null
+++ b/src/tree_data_hash.c
@@ -0,0 +1,25 @@
+/**
+ * @file tree_data_hash.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Functions to manipulate with the data node's hashes.
+ *
+ * Copyright (c) 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+#include "common.h"
+
+#include "hash_table.h"
+#include "tree_data.h"
+
+void
+lyd_unlink_hash(struct lyd_node *node)
+{
+    if (node->parent && node->parent->children_ht) {
+        lyht_remove(node->parent->children_ht, &node, node->hash);
+    }
+}
diff --git a/src/tree_data_helpers.c b/src/tree_data_helpers.c
new file mode 100644
index 0000000..fc4bf1c
--- /dev/null
+++ b/src/tree_data_helpers.c
@@ -0,0 +1,111 @@
+/**
+ * @file tree_data_helpers.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Parsing and validation helper functions for data trees
+ *
+ * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+#include "common.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "log.h"
+#include "dict.h"
+#include "plugins_types.h"
+#include "tree_data.h"
+#include "tree_schema.h"
+
+struct lyd_node **
+lyd_node_children_p(struct lyd_node *node)
+{
+    assert(node);
+    switch (node->schema->nodetype) {
+    case LYS_CONTAINER:
+    case LYS_LIST:
+        return &((struct lyd_node_inner*)node)->child;
+    default:
+        return NULL;
+    }
+}
+
+API const struct lyd_node *
+lyd_node_children(const struct lyd_node *node)
+{
+    struct lyd_node **children;
+
+    if (!node) {
+        return NULL;
+    }
+
+    children = lyd_node_children_p((struct lyd_node*)node);
+    if (children) {
+        return *children;
+    } else {
+        return NULL;
+    }
+}
+
+LY_ERR
+lyd_parse_check_options(struct ly_ctx *ctx, int options, const char *func)
+{
+    int x = options & LYD_OPT_TYPEMASK;
+
+    /* LYD_OPT_WHENAUTODEL can be used only with LYD_OPT_DATA or LYD_OPT_CONFIG */
+    if (options & LYD_OPT_WHENAUTODEL) {
+        if ((x == LYD_OPT_EDIT) || (x == LYD_OPT_NOTIF_FILTER)) {
+            LOGERR(ctx, LY_EINVAL, "%s: Invalid options 0x%x (LYD_OPT_DATA_WHENAUTODEL can be used only with LYD_OPT_DATA or LYD_OPT_CONFIG)",
+                   func, options);
+            return LY_EINVAL;
+        }
+    }
+
+    if (options & (LYD_OPT_DATA_ADD_YANGLIB | LYD_OPT_DATA_NO_YANGLIB)) {
+        if (x != LYD_OPT_DATA) {
+            LOGERR(ctx, LY_EINVAL, "%s: Invalid options 0x%x (LYD_OPT_DATA_*_YANGLIB can be used only with LYD_OPT_DATA)",
+                   func, options);
+            return LY_EINVAL;
+        }
+    }
+
+    /* "is power of 2" algorithm, with 0 exception */
+    if (x && !(x && !(x & (x - 1)))) {
+        LOGERR(ctx, LY_EINVAL, "%s: Invalid options 0x%x (multiple data type flags set).", func, options);
+        return LY_EINVAL;
+    }
+
+    return LY_SUCCESS;
+}
+
+LY_ERR
+lyd_value_validate(struct lyd_node_term *node, const char *value, size_t value_len, int options)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct ly_err_item *err = NULL;
+    struct ly_ctx *ctx;
+    struct lysc_type *type;
+
+    assert(node);
+
+    ctx = node->schema->module->ctx;
+    type = ((struct lysc_node_leaf*)node->schema)->type;
+    if (type->plugin->validate) {
+        ret = type->plugin->validate(ctx, type, value, value_len, options, &node->value.canonized, &err);
+        if (ret) {
+            ly_err_print(err);
+            LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
+            ly_err_free(err);
+        }
+    } else if (options & LY_TYPE_VALIDATE_CANONIZE) {
+        node->value.canonized = lydict_insert(ctx, value, value_len);
+    }
+
+    return ret;
+}
+
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
new file mode 100644
index 0000000..ba0729e
--- /dev/null
+++ b/src/tree_data_internal.h
@@ -0,0 +1,76 @@
+/**
+ * @file tree_data_internal.h
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief internal functions for YANG schema trees.
+ *
+ * Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef LY_TREE_DATA_INTERNAL_H_
+#define LY_TREE_DATA_INTERNAL_H_
+
+#include "tree_data.h"
+
+/**
+ * @brief Get address of a node's child pointer if any.
+ *
+ * Decides the node's type and in case it has a children list, returns its address.
+ * @param[in] node Node to check.
+ * @return Address of the node's child member if any, NULL otherwise.
+ */
+struct lyd_node **lyd_node_children_p(struct lyd_node *node);
+
+/**
+ * @brief Check validity of data parser options.
+ *
+ * @param ctx libyang context
+ * @param options Data parser options to check
+ * @param func name of the function where called
+ * @return LY_SUCCESS when options are ok
+ * @return LY_EINVAL when multiple data types bits are set, or incompatible options are used together.
+ */
+LY_ERR lyd_parse_check_options(struct ly_ctx *ctx, int options, const char *func);
+
+/**
+ * @brief Validate the given value according to the type's rules.
+ *
+ * According to the given options, the value can be also canonized or stored into the node's value structure.
+ *
+ * @param[in] options [Type validation options ](@ref plugintypevalidateopts).
+ */
+LY_ERR lyd_value_validate(struct lyd_node_term *node, const char *value, size_t value_len, int options);
+
+/**
+ * @brief Parse XML string as YANG data tree.
+ *
+ * @param[in] ctx libyang context
+ * @param[in] data Pointer to the XML string representation of the YANG data to parse.
+ * @param[in] options @ref dataparseroptions
+ * @param[out] result Resulting list of the parsed data trees. Note that NULL can be a valid result.
+ * @reutn LY_ERR value.
+ */
+LY_ERR lyd_parse_xml(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **result);
+
+/**
+ * @defgroup datahash Data nodes hash manipulation
+ * @ingroup datatree
+ */
+
+/**
+ * @brief Maintain node's parent's children hash table when unlinking the node.
+ *
+ * When completely freeing data tree, it is expected to free the parent's children hash table first, at once.
+ *
+ * @param[in] node The data node being unlinked from its parent.
+ */
+void lyd_unlink_hash(struct lyd_node *node);
+
+/** @} datahash */
+
+#endif /* LY_TREE_DATA_INTERNAL_H_ */
diff --git a/src/tree_schema.c b/src/tree_schema.c
index ca093fc..4e5ffb3 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -14,19 +14,25 @@
 
 #include "common.h"
 
+#include <assert.h>
 #include <dirent.h>
 #include <errno.h>
-#include <limits.h>
 #include <fcntl.h>
+#include <limits.h>
+#include <stdint.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/stat.h>
-#include <sys/types.h>
 #include <unistd.h>
 
-#include "libyang.h"
 #include "context.h"
+#include "dict.h"
+#include "log.h"
+#include "set.h"
+#include "tree.h"
+#include "tree_schema.h"
 #include "tree_schema_internal.h"
-#include "xpath.h"
 
 API const struct lysc_node *
 lys_getnext(const struct lysc_node *last, const struct lysc_node *parent, const struct lysc_module *module, int options)
@@ -505,12 +511,12 @@
 }
 
 struct lysp_submodule *
-lys_parse_mem_submodule(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, struct ly_parser_ctx *main_ctx,
+lys_parse_mem_submodule(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, struct lys_parser_ctx *main_ctx,
                         LY_ERR (*custom_check)(struct ly_ctx*, struct lysp_module*, struct lysp_submodule*, void*), void *check_data)
 {
     LY_ERR ret = LY_EINVAL;
     struct lysp_submodule *submod = NULL, *latest_sp;
-    struct ly_parser_ctx context = {0};
+    struct lys_parser_ctx context = {0};
 
     LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
 
@@ -582,7 +588,7 @@
     struct lysp_include *inc;
     LY_ERR ret = LY_EINVAL;
     unsigned int u, i;
-    struct ly_parser_ctx context = {0};
+    struct lys_parser_ctx context = {0};
 
     LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
 
@@ -769,7 +775,7 @@
 }
 
 void *
-lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
+lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct lys_parser_ctx *main_ctx,
                     LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
                     void *check_data)
 {
@@ -821,7 +827,7 @@
 }
 
 struct lysp_submodule *
-lys_parse_fd_submodule(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, struct ly_parser_ctx *main_ctx,
+lys_parse_fd_submodule(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, struct lys_parser_ctx *main_ctx,
                        LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
                        void *check_data)
 {
diff --git a/src/tree_schema.h b/src/tree_schema.h
index b2d619d..20d1c17 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -21,115 +21,17 @@
 #include <stdint.h>
 #include <stdio.h>
 
+#include "log.h"
+#include "tree.h"
 #include "extensions.h"
 
+struct ly_ctx;
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /**
- * @brief XPath representation.
- */
-struct lyxp_expr;
-
-/**
- * @brief Macro selector for other LY_ARRAY_* macros, do not use directly!
- */
-#define LY_ARRAY_SELECT(_1, _2, NAME, ...) NAME
-
-/**
- * @brief Helper macro to go through sized-arrays with a pointer iterator.
- *
- * Use with opening curly bracket (`{`).
- *
- * @param[in] ARRAY Array to go through
- * @param[in] TYPE Type of the records in the ARRAY
- * @param[out] ITER Iterating pointer to the item being processed in each loop
- */
-#define LY_ARRAY_FOR_ITER(ARRAY, TYPE, ITER) \
-    for (ITER = ARRAY; \
-         (ARRAY) && ((void*)ITER - (void*)ARRAY)/(sizeof(TYPE)) < (*((uint32_t*)(ARRAY) - 1)); \
-         ITER = (void*)((TYPE*)ITER + 1))
-
-/**
- * @brief Helper macro to go through sized-arrays with a numeric iterator.
- *
- * Use with opening curly bracket (`{`).
- *
- * To access an item with the INDEX value, use always LY_ARRAY_INDEX macro!
- *
- * @param[in] ARRAY Array to go through
- * @param[out] INDEX Iterating index of the item being processed in each loop
- */
-#define LY_ARRAY_FOR_INDEX(ARRAY, INDEX) \
-    for (INDEX = 0; \
-         ARRAY && INDEX < (*((uint32_t*)(ARRAY) - 1)); \
-         ++INDEX)
-
-/**
- * @defgroup schematree Schema Tree
- * @{
- *
- * Data structures and functions to manipulate and access schema tree.
- */
-
-/**
- * @brief Get a number of records in the ARRAY.
- *
- * Does not check if array exists!
- */
-#define LY_ARRAY_SIZE(ARRAY) (*((uint32_t*)(ARRAY) - 1))
-
-/**
- * @brief Sized-array iterator (for-loop).
- *
- * Use with opening curly bracket (`{`).
- *
- * There are 2 variants:
- *
- *     LY_ARRAY_FOR(ARRAY, TYPE, ITER)
- *
- * Where ARRAY is a sized-array to go through, TYPE is the type of the items in the ARRAY and ITER is a pointer variable
- * providing the items of the ARRAY in the loops. This functionality is provided by LY_ARRAY_FOR_ITER macro
- *
- *     LY_ARRAY_FOR(ARRAY, INDEX)
- *
- * The ARRAY is again a sized-array to go through, the INDEX is a variable (unsigned integer) for storing iterating ARRAY's index
- * to access the items of ARRAY in the loops. This functionality is provided by LY_ARRAY_FOR_INDEX macro.
- */
-#define LY_ARRAY_FOR(ARRAY, ...) LY_ARRAY_SELECT(__VA_ARGS__, LY_ARRAY_FOR_ITER, LY_ARRAY_FOR_INDEX)(ARRAY, __VA_ARGS__)
-
-/**
- * @brief Macro to iterate via all sibling elements without affecting the list itself
- *
- * Works for all types of nodes despite it is data or schema tree, but all the
- * parameters must be pointers to the same type.
- *
- * Use with opening curly bracket (`{`). All parameters must be of the same type.
- *
- * @param START Pointer to the starting element.
- * @param ELEM Iterator.
- */
-#define LY_LIST_FOR(START, ELEM) \
-    for ((ELEM) = (START); \
-         (ELEM); \
-         (ELEM) = (ELEM)->next)
-
-/**
- * @brief Macro to iterate via all sibling elements allowing to modify the list itself (e.g. removing elements)
- *
- * Use with opening curly bracket (`{`). All parameters must be of the same type.
- *
- * @param START Pointer to the starting element.
- * @param NEXT Temporary storage to allow removing of the current iterator content.
- * @param ELEM Iterator.
- */
-#define LY_LIST_FOR_SAFE(START, NEXT, ELEM) \
-    for ((ELEM) = (START); \
-         (ELEM) ? (NEXT = (ELEM)->next, 1) : 0; \
-         (ELEM) = (NEXT))
-
-/**
  * @brief Schema input formats accepted by libyang [parser functions](@ref howtoschemasparsers).
  */
 typedef enum {
@@ -163,49 +65,18 @@
 #define LYS_ANYXML 0x0020         /**< anyxml statement node */
 #define LYS_ANYDATA 0x0120        /**< anydata statement node, in tests it can be used for both #LYS_ANYXML and #LYS_ANYDATA */
 
+#define LYS_ACTION 0x400          /**< RPC or action */
+#define LYS_NOTIF 0x800
+
 #define LYS_CASE 0x0040           /**< case statement node */
 #define LYS_USES 0x0080           /**< uses statement node */
 #define LYS_INPUT 0x100
 #define LYS_OUTPUT 0x200
 #define LYS_INOUT 0x300
-#define LYS_ACTION 0x400          /**< RPC or action */
-#define LYS_NOTIF 0x800
 #define LYS_GROUPING 0x1000
 #define LYS_AUGMENT 0x2000
 
 /**
- * @brief YANG built-in types
- */
-typedef enum {
-    LY_TYPE_UNKNOWN = 0,  /**< Unknown type */
-    LY_TYPE_BINARY,       /**< Any binary data ([RFC 6020 sec 9.8](http://tools.ietf.org/html/rfc6020#section-9.8)) */
-    LY_TYPE_UINT8,        /**< 8-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
-    LY_TYPE_UINT16,       /**< 16-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
-    LY_TYPE_UINT32,       /**< 32-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
-    LY_TYPE_UINT64,       /**< 64-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
-    LY_TYPE_STRING,       /**< Human-readable string ([RFC 6020 sec 9.4](http://tools.ietf.org/html/rfc6020#section-9.4)) */
-    LY_TYPE_BITS,         /**< A set of bits or flags ([RFC 6020 sec 9.7](http://tools.ietf.org/html/rfc6020#section-9.7)) */
-    LY_TYPE_BOOL,         /**< "true" or "false" ([RFC 6020 sec 9.5](http://tools.ietf.org/html/rfc6020#section-9.5)) */
-    LY_TYPE_DEC64,        /**< 64-bit signed decimal number ([RFC 6020 sec 9.3](http://tools.ietf.org/html/rfc6020#section-9.3))*/
-    LY_TYPE_EMPTY,        /**< A leaf that does not have any value ([RFC 6020 sec 9.11](http://tools.ietf.org/html/rfc6020#section-9.11)) */
-    LY_TYPE_ENUM,         /**< Enumerated strings ([RFC 6020 sec 9.6](http://tools.ietf.org/html/rfc6020#section-9.6)) */
-    LY_TYPE_IDENT,        /**< A reference to an abstract identity ([RFC 6020 sec 9.10](http://tools.ietf.org/html/rfc6020#section-9.10)) */
-    LY_TYPE_INST,         /**< References a data tree node ([RFC 6020 sec 9.13](http://tools.ietf.org/html/rfc6020#section-9.13)) */
-    LY_TYPE_LEAFREF,      /**< A reference to a leaf instance ([RFC 6020 sec 9.9](http://tools.ietf.org/html/rfc6020#section-9.9))*/
-    LY_TYPE_UNION,        /**< Choice of member types ([RFC 6020 sec 9.12](http://tools.ietf.org/html/rfc6020#section-9.12)) */
-    LY_TYPE_INT8,         /**< 8-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
-    LY_TYPE_INT16,        /**< 16-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
-    LY_TYPE_INT32,        /**< 32-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
-    LY_TYPE_INT64,        /**< 64-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
-} LY_DATA_TYPE;
-#define LY_DATA_TYPE_COUNT 20 /**< Number of different types */
-
-/**
- * @brief Stringified YANG built-in data types
- */
-extern const char* ly_data_type2str[LY_DATA_TYPE_COUNT];
-
-/**
  * @brief YANG import-stmt
  */
 struct lysp_import {
@@ -1066,12 +937,12 @@
 struct lysc_range {
     struct lysc_range_part {
         union {                      /**< min boundary */
-            int64_t min_64;          /**< for int8, int16, int32, int64 and decimal64 */
-            uint64_t min_u64;        /**< for uint8, uint16, uint32, uint64, string and binary */
+            int64_t min_64;          /**< for int8, int16, int32, int64 and decimal64 ( >= LY_TYPE_DEC64) */
+            uint64_t min_u64;        /**< for uint8, uint16, uint32, uint64, string and binary ( < LY_TYPE_DEC64) */
         };
         union {                      /**< max boundary */
-            int64_t max_64;          /**< for int8, int16, int32, int64 and decimal64 */
-            uint64_t max_u64;        /**< for uint8, uint16, uint32, uint64, string and binary */
+            int64_t max_64;          /**< for int8, int16, int32, int64 and decimal64 ( >= LY_TYPE_DEC64) */
+            uint64_t max_u64;        /**< for uint8, uint16, uint32, uint64, string and binary ( < LY_TYPE_DEC64) */
         };
     } *parts;                        /**< compiled range expression ([sized array](@ref sizedarrays)) */
     const char *dsc;                 /**< description */
@@ -1106,6 +977,7 @@
 struct lysc_type {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     const char *dflt;                /**< type's default value if any */
+    struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
 };
@@ -1113,6 +985,7 @@
 struct lysc_type_num {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     const char *dflt;                /**< type's default value if any */
+    struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     struct lysc_range *range;        /**< Optional range limitation */
@@ -1121,6 +994,7 @@
 struct lysc_type_dec {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     const char *dflt;                /**< type's default value if any */
+    struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     uint8_t fraction_digits;         /**< fraction digits specification */
@@ -1130,6 +1004,7 @@
 struct lysc_type_str {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     const char *dflt;                /**< type's default value if any */
+    struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     struct lysc_range *length;       /**< Optional length limitation */
@@ -1153,6 +1028,7 @@
 struct lysc_type_enum {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     const char *dflt;                /**< type's default value if any */
+    struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     struct lysc_type_bitenum_item *enums; /**< enumerations list ([sized array](@ref sizedarrays)), mandatory (at least 1 item) */
@@ -1161,6 +1037,7 @@
 struct lysc_type_bits {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     const char *dflt;                /**< type's default value if any */
+    struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     struct lysc_type_bitenum_item *bits; /**< bits list ([sized array](@ref sizedarrays)), mandatory (at least 1 item) */
@@ -1169,6 +1046,7 @@
 struct lysc_type_leafref {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     const char *dflt;                /**< type's default value if any */
+    struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     const char* path;                /**< target path */
@@ -1180,6 +1058,7 @@
 struct lysc_type_identityref {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     const char *dflt;                /**< type's default value if any */
+    struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     struct lysc_ident **bases;       /**< list of pointers to the base identities ([sized array](@ref sizedarrays)),
@@ -1189,6 +1068,7 @@
 struct lysc_type_instanceid {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     const char *dflt;                /**< type's default value if any */
+    struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     uint8_t require_instance;        /**< require-instance flag */
@@ -1197,6 +1077,7 @@
 struct lysc_type_union {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     const char *dflt;                /**< type's default value if any */
+    struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     struct lysc_type **types;        /**< list of types in the union ([sized array](@ref sizedarrays)), mandatory (at least 1 item) */
@@ -1205,6 +1086,7 @@
 struct lysc_type_bin {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     const char *dflt;                /**< type's default value if any */
+    struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
     struct lysc_range *length;       /**< Optional length limitation */
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 1f57db9..2f9246c 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -14,11 +14,20 @@
 
 #include "common.h"
 
+#include <assert.h>
 #include <ctype.h>
+#include <stddef.h>
+#include <stdint.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
-#include "libyang.h"
-#include "context.h"
+#include "dict.h"
+#include "log.h"
+#include "set.h"
+#include "plugins_types.h"
+#include "tree.h"
+#include "tree_schema.h"
 #include "tree_schema_internal.h"
 #include "xpath.h"
 
@@ -93,7 +102,7 @@
 static struct lysc_ext_instance *
 lysc_ext_instance_dup(struct ly_ctx *ctx, struct lysc_ext_instance *orig)
 {
-    /* TODO */
+    /* TODO - extensions */
     (void) ctx;
     (void) orig;
     return NULL;
@@ -2999,6 +3008,8 @@
         }
 
         (*type)->basetype = basetype;
+        /* TODO user type plugins */
+        (*type)->plugin = &ly_builtin_type_plugins[basetype];
         prev_type = *type;
         ret = lys_compile_type_(ctx, tctx->node, tctx->tpdf->flags, tctx->mod, tctx->tpdf->name, &((struct lysp_tpdf*)tctx->tpdf)->type,
                                 basetype & (LY_TYPE_LEAFREF | LY_TYPE_UNION) ? lysp_find_module(ctx->ctx, tctx->mod) : NULL,
@@ -3013,6 +3024,8 @@
     if (type_p->flags || !base || basetype == LY_TYPE_LEAFREF) {
         /* get restrictions from the node itself */
         (*type)->basetype = basetype;
+        /* TODO user type plugins */
+        (*type)->plugin = &ly_builtin_type_plugins[basetype];
         ++(*type)->refcount;
         ret = lys_compile_type_(ctx, context_node_p, context_flags, context_mod, context_name, type_p, ctx->mod_def, basetype, NULL, base, type);
         LY_CHECK_GOTO(ret, cleanup);
@@ -3766,7 +3779,6 @@
     struct lysp_node_choice *ch_p = (struct lysp_node_choice*)node_p;
     struct lysc_node_choice *ch = (struct lysc_node_choice*)node;
     struct lysp_node *child_p, *case_child_p;
-    struct lys_module;
     LY_ERR ret = LY_SUCCESS;
 
     LY_LIST_FOR(ch_p->child, child_p) {
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index c3948a0..283ba29 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -1,9 +1,9 @@
 /**
- * @file tree_schema.c
+ * @file tree_schema_free.c
  * @author Radek Krejci <rkrejci@cesnet.cz>
- * @brief Schema tree implementation
+ * @brief Freeing functions for schema tree structures.
  *
- * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
+ * Copyright (c) 2019 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -14,8 +14,11 @@
 
 #include "common.h"
 
-#include "libyang.h"
-#include "context.h"
+#include <stdlib.h>
+
+#include "dict.h"
+#include "tree.h"
+#include "tree_schema.h"
 #include "tree_schema_internal.h"
 #include "xpath.h"
 
@@ -621,7 +624,6 @@
     }
     FREE_ARRAY(ctx, type->exts, lysc_ext_instance_free);
     FREE_STRING(ctx, type->dflt);
-
     free(type);
 }
 
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index a4a93ee..9ba34e9 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -1,7 +1,7 @@
 /**
  * @file tree_schema_helpers.c
  * @author Radek Krejci <rkrejci@cesnet.cz>
- * @brief Parsing and validation helper functions
+ * @brief Parsing and validation helper functions for schema trees
  *
  * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
  *
@@ -13,18 +13,26 @@
  */
 #include "common.h"
 
+#include <assert.h>
+#include <bits/types/struct_tm.h>
 #include <ctype.h>
-#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
+#include <stdint.h>
 #include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
+#include <string.h>
 #include <unistd.h>
 #include <time.h>
 
-#include "libyang.h"
+#include "context.h"
+#include "dict.h"
+#include "extensions.h"
+#include "hash_table.h"
+#include "log.h"
+#include "set.h"
+#include "tree.h"
+#include "tree_schema.h"
 #include "tree_schema_internal.h"
 
 /**
@@ -201,7 +209,7 @@
 }
 
 LY_ERR
-lysp_check_prefix(struct ly_parser_ctx *ctx, struct lysp_import *imports, const char *module_prefix, const char **value)
+lysp_check_prefix(struct lys_parser_ctx *ctx, struct lysp_import *imports, const char *module_prefix, const char **value)
 {
     struct lysp_import *i;
 
@@ -244,7 +252,7 @@
 }
 
 LY_ERR
-lysp_check_date(struct ly_parser_ctx *ctx, const char *date, int date_len, const char *stmt)
+lysp_check_date(struct lys_parser_ctx *ctx, const char *date, int date_len, const char *stmt)
 {
     int i;
     struct tm tm, tm_;
@@ -487,7 +495,7 @@
  * @return LY_EEXIST in case of collision, LY_SUCCESS otherwise.
  */
 static LY_ERR
-lysp_check_typedef(struct ly_parser_ctx *ctx, struct lysp_node *node, const struct lysp_tpdf *tpdf,
+lysp_check_typedef(struct lys_parser_ctx *ctx, struct lysp_node *node, const struct lysp_tpdf *tpdf,
                    struct hash_table *tpdfs_global, struct hash_table *tpdfs_scoped)
 {
     struct lysp_node *parent;
@@ -562,7 +570,7 @@
 }
 
 LY_ERR
-lysp_check_typedefs(struct ly_parser_ctx *ctx, struct lysp_module *mod)
+lysp_check_typedefs(struct lys_parser_ctx *ctx, struct lysp_module *mod)
 {
     struct hash_table *ids_global;
     struct hash_table *ids_scoped;
@@ -679,7 +687,7 @@
 }
 
 LY_ERR
-lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct ly_parser_ctx *main_ctx,
+lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct lys_parser_ctx *main_ctx,
                      void **result)
 {
     int fd;
@@ -846,7 +854,7 @@
 }
 
 LY_ERR
-lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
+lysp_load_submodule(struct lys_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
 {
     struct lysp_submodule *submod = NULL;
     const char *submodule_data = NULL;
@@ -1182,6 +1190,11 @@
 lysp_node_children(const struct lysp_node *node)
 {
     struct lysp_node **children;
+
+    if (!node) {
+        return NULL;
+    }
+
     children = lysp_node_children_p((struct lysp_node*)node);
     if (children) {
         return *children;
@@ -1277,6 +1290,11 @@
 lysc_node_children(const struct lysc_node *node, uint16_t flags)
 {
     struct lysc_node **children;
+
+    if (!node) {
+        return NULL;
+    }
+
     children = lysc_node_children_p((struct lysc_node*)node, flags);
     if (children) {
         return *children;
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 6194649..2f5c063 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -46,7 +46,7 @@
 /**
  * @brief internal context for schema parsers
  */
-struct ly_parser_ctx {
+struct lys_parser_ctx {
     struct ly_ctx *ctx;
     struct ly_set tpdfs_nodes;
     struct ly_set grps_nodes;
@@ -83,7 +83,7 @@
  * @param[in] value Newly added prefix value (including its location to distinguish collision with itself).
  * @return LY_EEXIST when prefix is already used in the module, LY_SUCCESS otherwise
  */
-LY_ERR lysp_check_prefix(struct ly_parser_ctx *ctx, struct lysp_import *imports, const char *module_prefix, const char **value);
+LY_ERR lysp_check_prefix(struct lys_parser_ctx *ctx, struct lysp_import *imports, const char *module_prefix, const char **value);
 
 /**
  * @brief Check date string (4DIGIT "-" 2DIGIT "-" 2DIGIT)
@@ -94,7 +94,7 @@
  * @param[in] stmt Statement name for error message.
  * @return LY_ERR value.
  */
-LY_ERR lysp_check_date(struct ly_parser_ctx *ctx, const char *date, int date_len, const char *stmt);
+LY_ERR lysp_check_date(struct lys_parser_ctx *ctx, const char *date, int date_len, const char *stmt);
 
 /**
  * @brief Check names of typedefs in the parsed module to detect collisions.
@@ -103,7 +103,7 @@
  * @param[in] mod Module where the type is being defined.
  * @return LY_ERR value.
  */
-LY_ERR lysp_check_typedefs(struct ly_parser_ctx *ctx, struct lysp_module *mod);
+LY_ERR lysp_check_typedefs(struct lys_parser_ctx *ctx, struct lysp_module *mod);
 
 /**
  * @brief Just move the newest revision into the first position, does not sort the rest
@@ -150,7 +150,7 @@
  * submodule is stored into this structure.
  * @return LY_ERR value.
  */
-LY_ERR lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc);
+LY_ERR lysp_load_submodule(struct lys_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc);
 
 /**
  * @defgroup scflags Schema compile flags
@@ -405,7 +405,7 @@
  * @param[in] check_data Caller's data to pass to the custom_check callback.
  * @return Pointer to the data model structure or NULL on error.
  */
-struct lysp_submodule *lys_parse_mem_submodule(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, struct ly_parser_ctx *main_ctx,
+struct lysp_submodule *lys_parse_mem_submodule(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, struct lys_parser_ctx *main_ctx,
                                                LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *check_data),
                                                void *check_data);
 
@@ -427,7 +427,7 @@
  * @param[in] check_data Caller's data to pass to the custom_check callback.
  * @return Pointer to the data model structure or NULL on error.
  */
-void *lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
+void *lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct lys_parser_ctx *main_ctx,
                     LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
                     void *check_data);
 
@@ -467,7 +467,7 @@
  * @param[in] check_data Caller's data to pass to the custom_check callback.
  * @return Pointer to the data model structure or NULL on error.
  */
-struct lysp_submodule *lys_parse_fd_submodule(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, struct ly_parser_ctx *main_ctx,
+struct lysp_submodule *lys_parse_fd_submodule(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, struct lys_parser_ctx *main_ctx,
                                               LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *check_data),
                                               void *check_data);
 
@@ -506,7 +506,7 @@
  * If it is a module, it is already in the context!
  * @return LY_ERR value, in case of LY_SUCCESS, the \arg result is always provided.
  */
-LY_ERR lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct ly_parser_ctx *main_ctx,
+LY_ERR lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct lys_parser_ctx *main_ctx,
                             void **result);
 
 /**
@@ -657,7 +657,7 @@
  * @param[out] submod Pointer to the parsed submodule structure.
  * @return LY_ERR value - LY_SUCCESS, LY_EINVAL or LY_EVALID.
  */
-LY_ERR yang_parse_submodule(struct ly_parser_ctx *ctx, const char *data, struct lysp_submodule **submod);
+LY_ERR yang_parse_submodule(struct lys_parser_ctx *ctx, const char *data, struct lysp_submodule **submod);
 
 /**
  * @brief Parse module from YANG data.
@@ -667,7 +667,7 @@
  * module structure, will be filled in.
  * @return LY_ERR value - LY_SUCCESS, LY_EINVAL or LY_EVALID.
  */
-LY_ERR yang_parse_module(struct ly_parser_ctx *ctx, const char *data, struct lys_module *mod);
+LY_ERR yang_parse_module(struct lys_parser_ctx *ctx, const char *data, struct lys_module *mod);
 
 /**
  * @brief Make the specific module implemented, use the provided value as flag.
diff --git a/src/xml.c b/src/xml.c
index a7e40f7..195ce56 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -18,10 +18,11 @@
 #include <ctype.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
 
-#include "libyang.h"
 #include "xml.h"
+#include "printer_internal.h"
 
 /* Move input p by s characters, if EOF log with lyxml_context c */
 #define move_input(c,p,s) p += s; LY_CHECK_ERR_RET(!p[0], LOGVAL(c->ctx, LY_VLOG_LINE, &c->line, LY_VCODE_EOF), LY_EVALID)
@@ -218,6 +219,7 @@
         context->line += newlines;
         if (in[offset] == '<') {
             (*input) = in + offset;
+            context->status -= 1; /* LYXML_ELEMENT */;
             return LY_EINVAL;
         }
     }
@@ -739,3 +741,40 @@
     }
     ly_set_erase(&context->ns, NULL);
 }
+
+LY_ERR
+lyxml_dump_text(struct lyout *out, const char *text, int attribute)
+{
+    LY_ERR ret = LY_SUCCESS;
+    unsigned int u;
+
+    if (!text) {
+        return 0;
+    }
+
+    for (u = 0; text[u]; u++) {
+        switch (text[u]) {
+        case '&':
+            ret = ly_print(out, "&amp;");
+            break;
+        case '<':
+            ret = ly_print(out, "&lt;");
+            break;
+        case '>':
+            /* not needed, just for readability */
+            ret = ly_print(out, "&gt;");
+            break;
+        case '"':
+            if (attribute) {
+                ret = ly_print(out, "&quot;");
+                break;
+            }
+            /* falls through */
+        default:
+            ly_write(out, &text[u], 1);
+        }
+    }
+
+    return ret;
+}
+
diff --git a/src/xml.h b/src/xml.h
index 70431ea..3224e8d 100644
--- a/src/xml.h
+++ b/src/xml.h
@@ -15,11 +15,14 @@
 #ifndef LY_XML_H_
 #define LY_XML_H_
 
+#include <stddef.h>
 #include <stdint.h>
 
-#include "context.h"
+#include "log.h"
 #include "set.h"
 
+struct lyout;
+
 /* Macro to test if character is whitespace */
 #define is_xmlws(c) (c == 0x20 || c == 0x9 || c == 0xa || c == 0xd)
 
@@ -81,7 +84,7 @@
 /**
  * @brief Parse input expecting an XML element.
  *
- * Able to silently skip comments, PIs and CData. DOCTYPE is not parsable, so it is reported as LY_EVALID error.
+ * Able to silently skip comments, PIs and CData. DOCTYPE is not parseable, so it is reported as LY_EVALID error.
  * If '<' is not found in input, LY_EINVAL is returned (but no error is logged), so it is possible to continue
  * with parsing input as text content.
  *
@@ -200,6 +203,16 @@
 LY_ERR lyxml_ns_rm(struct lyxml_context *context, const char *element_name);
 
 /**
+ * @brief Print the given @p text as XML string which replaces some of the characters which cannot appear in XML data.
+ *
+ * @param[in] out Output structure for printing.
+ * @param[in] text String to print.
+ * @param[in] attribute Flag for attribute's value where a double quotes must be replaced.
+ * @return LY_ERR values.
+ */
+LY_ERR lyxml_dump_text(struct lyout *out, const char *text, int attribute);
+
+/**
  * @brief Remove the allocated working memory of the context.
  *
  * @param[in] context XML context to clear.
diff --git a/src/xpath.c b/src/xpath.c
index a73c2e0..ba818ca 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -15,16 +15,13 @@
 #include "common.h"
 
 #include <ctype.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdint.h>
 #include <string.h>
-#include <assert.h>
-#include <limits.h>
-#include <errno.h>
-#include <math.h>
 
 #include "xpath.h"
+#include "dict.h"
 #include "xml.h"
 
 /**
diff --git a/src/xpath.h b/src/xpath.h
index df3a4f9..5abd427 100644
--- a/src/xpath.h
+++ b/src/xpath.h
@@ -17,11 +17,11 @@
 
 #include <stdint.h>
 
-#include "libyang.h"
-#include "tree_schema.h"
-#if 0
-#include "tree_data.h"
-#endif
+#include "log.h"
+
+struct ly_ctx;
+struct lysc_node;
+
 /*
  * XPath evaluator fully compliant with http://www.w3.org/TR/1999/REC-xpath-19991116/
  * except the following restrictions in the grammar.
diff --git a/tests/src/test_context.c b/tests/src/test_context.c
index 756365e..839ec02 100644
--- a/tests/src/test_context.c
+++ b/tests/src/test_context.c
@@ -24,6 +24,7 @@
 #include "../../src/tree_schema_free.c"
 #include "../../src/tree_schema_compile.c"
 #include "../../src/tree_schema.c"
+#include "../../src/plugins_types.c"
 
 #include <stdarg.h>
 #include <stddef.h>
diff --git a/tests/src/test_hash_table.c b/tests/src/test_hash_table.c
index 2f10f0a..ca43aa8 100644
--- a/tests/src/test_hash_table.c
+++ b/tests/src/test_hash_table.c
@@ -26,6 +26,7 @@
 #include "../../src/tree_schema_free.c"
 #include "../../src/tree_schema_compile.c"
 #include "../../src/tree_schema.c"
+#include "../../src/plugins_types.c"
 
 #include <stdarg.h>
 #include <stddef.h>
diff --git a/tests/src/test_parser_yang.c b/tests/src/test_parser_yang.c
index 8dca6c5..c171402 100644
--- a/tests/src/test_parser_yang.c
+++ b/tests/src/test_parser_yang.c
@@ -23,6 +23,7 @@
 #include "../../src/tree_schema_free.c"
 #include "../../src/tree_schema_compile.c"
 #include "../../src/tree_schema.c"
+#include "../../src/plugins_types.c"
 
 #include <stdarg.h>
 #include <stddef.h>
@@ -108,7 +109,7 @@
     char *buf, *p;
     size_t len, size;
     int prefix;
-    struct ly_parser_ctx ctx;
+    struct lys_parser_ctx ctx;
     ctx.ctx = NULL;
     ctx.line = 1;
 
@@ -177,7 +178,7 @@
 {
     (void) state; /* unused */
 
-    struct ly_parser_ctx ctx;
+    struct lys_parser_ctx ctx;
     const char *str, *p;
     char *word, *buf;
     size_t len;
@@ -213,7 +214,7 @@
 {
     (void) state; /* unused */
 
-    struct ly_parser_ctx ctx;
+    struct lys_parser_ctx ctx;
     const char *str;
     char *word, *buf;
     size_t len;
@@ -337,7 +338,7 @@
 {
     (void) state; /* unused */
 
-    struct ly_parser_ctx ctx;
+    struct lys_parser_ctx ctx;
     const char *str, *p;
     enum yang_keyword kw;
     char *word;
@@ -673,7 +674,7 @@
 {
     *state = test_minmax;
 
-    struct ly_parser_ctx ctx = {0};
+    struct lys_parser_ctx ctx = {0};
     uint16_t flags = 0;
     uint32_t value = 0;
     struct lysp_ext_instance *ext = NULL;
@@ -765,7 +766,7 @@
 }
 
 static struct lysp_module *
-mod_renew(struct ly_parser_ctx *ctx)
+mod_renew(struct lys_parser_ctx *ctx)
 {
     struct lysp_module *mod_p;
     static struct lys_module mod = {0};
@@ -791,7 +792,7 @@
 }
 
 static struct lysp_submodule *
-submod_renew(struct ly_parser_ctx *ctx, struct lysp_submodule *submod)
+submod_renew(struct lys_parser_ctx *ctx, struct lysp_submodule *submod)
 {
     lysp_submodule_free(ctx->ctx, submod);
     submod = calloc(1, sizeof *submod);
@@ -814,7 +815,7 @@
 {
     *state = test_module;
 
-    struct ly_parser_ctx ctx;
+    struct lys_parser_ctx ctx;
     struct lysp_module *mod = NULL;
     struct lysp_submodule *submod = NULL;
     struct lys_module *m;
@@ -1086,7 +1087,7 @@
 {
     *state = test_identity;
 
-    struct ly_parser_ctx ctx;
+    struct lys_parser_ctx ctx;
     struct lysp_ident *ident = NULL;
     const char *str;
 
@@ -1131,7 +1132,7 @@
 {
     (void) state; /* unused */
 
-    struct ly_parser_ctx ctx;
+    struct lys_parser_ctx ctx;
     struct lysp_feature *features = NULL;
     const char *str;
 
@@ -1174,7 +1175,7 @@
 {
     (void) state; /* unused */
 
-    struct ly_parser_ctx ctx;
+    struct lys_parser_ctx ctx;
     struct lysp_deviation *d = NULL;
     const char *str;
 
@@ -1223,7 +1224,7 @@
 {
     (void) state; /* unused */
 
-    struct ly_parser_ctx ctx;
+    struct lys_parser_ctx ctx;
     struct lysp_deviate *d = NULL;
     const char *str;
 
@@ -1308,7 +1309,7 @@
 {
     (void) state; /* unused */
 
-    struct ly_parser_ctx ctx = {0};
+    struct lys_parser_ctx ctx = {0};
     struct lysp_node_container *c = NULL;
     const char *str;
 
@@ -1381,7 +1382,7 @@
 {
     *state = test_leaf;
 
-    struct ly_parser_ctx ctx = {0};
+    struct lys_parser_ctx ctx = {0};
     struct lysp_node_leaf *l = NULL;
     const char *str;
 
@@ -1459,7 +1460,7 @@
 {
     *state = test_leaf;
 
-    struct ly_parser_ctx ctx = {0};
+    struct lys_parser_ctx ctx = {0};
     struct lysp_node_leaflist *ll = NULL;
     const char *str;
 
@@ -1557,7 +1558,7 @@
 {
     *state = test_list;
 
-    struct ly_parser_ctx ctx = {0};
+    struct lys_parser_ctx ctx = {0};
     struct lysp_node_list *l = NULL;
     const char *str;
 
@@ -1627,7 +1628,7 @@
 {
     *state = test_choice;
 
-    struct ly_parser_ctx ctx = {0};
+    struct lys_parser_ctx ctx = {0};
     struct lysp_node_choice *ch = NULL;
     const char *str;
 
@@ -1694,7 +1695,7 @@
 {
     *state = test_case;
 
-    struct ly_parser_ctx ctx = {0};
+    struct lys_parser_ctx ctx = {0};
     struct lysp_node_case *cs = NULL;
     const char *str;
 
@@ -1748,7 +1749,7 @@
 {
     *state = test_any;
 
-    struct ly_parser_ctx ctx = {0};
+    struct lys_parser_ctx ctx = {0};
     struct lysp_node_anydata *any = NULL;
     const char *str;
 
@@ -1814,7 +1815,7 @@
 {
     *state = test_grouping;
 
-    struct ly_parser_ctx ctx = {0};
+    struct lys_parser_ctx ctx = {0};
     struct lysp_grp *grp = NULL;
     const char *str;
 
@@ -1870,7 +1871,7 @@
 {
     *state = test_action;
 
-    struct ly_parser_ctx ctx = {0};
+    struct lys_parser_ctx ctx = {0};
     struct lysp_action *rpcs = NULL;
     struct lysp_node_container *c = NULL;
     const char *str;
@@ -1947,7 +1948,7 @@
 {
     *state = test_notification;
 
-    struct ly_parser_ctx ctx = {0};
+    struct lys_parser_ctx ctx = {0};
     struct lysp_notif *notifs = NULL;
     struct lysp_node_container *c = NULL;
     const char *str;
@@ -2007,7 +2008,7 @@
 {
     *state = test_uses;
 
-    struct ly_parser_ctx ctx = {0};
+    struct lys_parser_ctx ctx = {0};
     struct lysp_node_uses *u = NULL;
     const char *str;
 
@@ -2057,7 +2058,7 @@
 {
     *state = test_augment;
 
-    struct ly_parser_ctx ctx = {0};
+    struct lys_parser_ctx ctx = {0};
     struct lysp_augment *a = NULL;
     const char *str;
 
diff --git a/tests/src/test_printer_yang.c b/tests/src/test_printer_yang.c
index c4ae63e..88b33bf 100644
--- a/tests/src/test_printer_yang.c
+++ b/tests/src/test_printer_yang.c
@@ -23,9 +23,8 @@
 #include "../../src/tree_schema_free.c"
 #include "../../src/tree_schema_compile.c"
 #include "../../src/tree_schema.c"
+#include "../../src/plugins_types.c"
 #include "../../src/printer_yang.c"
-#include "../../src/printer.c"
-
 #include <stdarg.h>
 #include <stddef.h>
 #include <setjmp.h>
@@ -34,6 +33,8 @@
 #include <stdio.h>
 #include <string.h>
 
+#include "../../src/printer.c"
+#include "../../src/printer_schema.c"
 #include "libyang.h"
 
 #define BUFSIZE 1024
diff --git a/tests/src/test_tree_schema.c b/tests/src/test_tree_schema.c
index 7dd29c1..c7f3023 100644
--- a/tests/src/test_tree_schema.c
+++ b/tests/src/test_tree_schema.c
@@ -20,6 +20,7 @@
 #include "../../src/tree_schema_compile.c"
 #include "../../src/tree_schema_free.c"
 #include "../../src/tree_schema_helpers.c"
+#include "../../src/plugins_types.c"
 #include "../../src/hash_table.c"
 #include "../../src/xpath.c"
 #include "../../src/context.c"
diff --git a/tests/src/test_tree_schema_compile.c b/tests/src/test_tree_schema_compile.c
index 0207bb7..8954d0d 100644
--- a/tests/src/test_tree_schema_compile.c
+++ b/tests/src/test_tree_schema_compile.c
@@ -21,6 +21,7 @@
 #include "../../src/tree_schema_free.c"
 #include "../../src/tree_schema_compile.c"
 #include "../../src/tree_schema.c"
+#include "../../src/plugins_types.c"
 #include "../../src/context.c"
 #include "../../src/hash_table.c"
 
@@ -125,7 +126,7 @@
     *state = test_module;
 
     const char *str;
-    struct ly_parser_ctx ctx = {0};
+    struct lys_parser_ctx ctx = {0};
     struct lys_module mod = {0};
     struct lysc_feature *f;
     struct lysc_iffeature *iff;
@@ -193,7 +194,7 @@
 {
     *state = test_feature;
 
-    struct ly_parser_ctx ctx = {0};
+    struct lys_parser_ctx ctx = {0};
     struct lys_module mod = {0}, *modp;
     const char *str;
     struct lysc_feature *f, *f1;
diff --git a/tests/src/test_tree_schema_helpers.c b/tests/src/test_tree_schema_helpers.c
index c3b3e50..02d571a 100644
--- a/tests/src/test_tree_schema_helpers.c
+++ b/tests/src/test_tree_schema_helpers.c
@@ -20,6 +20,7 @@
 #include "../../src/tree_schema_compile.c"
 #include "../../src/tree_schema_free.c"
 #include "../../src/tree_schema_helpers.c"
+#include "../../src/plugins_types.c"
 #include "../../src/hash_table.c"
 #include "../../src/xpath.c"
 #include "../../src/context.c"
diff --git a/tests/src/test_xml.c b/tests/src/test_xml.c
index c93be56..e153b92 100644
--- a/tests/src/test_xml.c
+++ b/tests/src/test_xml.c
@@ -17,7 +17,6 @@
 #include "../../src/xml.c"
 #include "../../src/common.c"
 #include "../../src/log.c"
-
 #include <stdarg.h>
 #include <stddef.h>
 #include <setjmp.h>
@@ -26,6 +25,7 @@
 #include <stdio.h>
 #include <string.h>
 
+#include "../../src/printer.c"
 #include "libyang.h"
 
 #define BUFSIZE 1024
diff --git a/tools/lint/commands.c b/tools/lint/commands.c
index 58ebe96..4b65a76 100644
--- a/tools/lint/commands.c
+++ b/tools/lint/commands.c
@@ -520,7 +520,7 @@
 
     return ret;
 }
-#if 0
+
 static LYD_FORMAT
 detect_data_format(char *filepath)
 {
@@ -531,10 +531,12 @@
     for (; isspace(filepath[len - 1]); len--, filepath[len] = '\0'); /* remove trailing whitespaces */
     if (len >= 5 && !strcmp(&filepath[len - 4], ".xml")) {
         return LYD_XML;
+#if 0
     } else if (len >= 6 && !strcmp(&filepath[len - 5], ".json")) {
         return LYD_JSON;
     } else if (len >= 5 && !strcmp(&filepath[len - 4], ".lyb")) {
         return LYD_LYB;
+#endif
     } else {
         return LYD_UNKNOWN;
     }
@@ -545,7 +547,6 @@
            struct lyd_node **result)
 {
     LYD_FORMAT informat = LYD_UNKNOWN;
-    struct lyxml_elem *xml = NULL;
     struct lyd_node *data = NULL, *rpc_act = NULL;
     int opts = *options;
 
@@ -556,8 +557,9 @@
         return EXIT_FAILURE;
     }
 
-    ly_errno = LY_SUCCESS;
+    ly_err_clean(ctx, NULL);
 
+#if 0
     if ((opts & LYD_OPT_TYPEMASK) == LYD_OPT_TYPEMASK) {
         /* automatically detect data type from the data top level */
         if (informat != LYD_XML) {
@@ -633,6 +635,7 @@
         }
         lyxml_free(ctx, xml);
     } else {
+#endif
         if (opts & LYD_OPT_RPCREPLY) {
             if (!rpc_act_file) {
                 fprintf(stderr, "RPC/action reply data require additional argument (file with the RPC/action).\n");
@@ -659,12 +662,14 @@
             }
             data = lyd_parse_path(ctx, filepath, informat, opts);
         }
+#if 0
     }
-    lyd_free_withsiblings(rpc_act);
+#endif
+    lyd_free_all(rpc_act);
 
-    if (ly_errno) {
+    if (ly_err_first(ctx)) {
         fprintf(stderr, "Failed to parse data.\n");
-        lyd_free_withsiblings(data);
+        lyd_free_all(data);
         return EXIT_FAILURE;
     }
 
@@ -719,6 +724,7 @@
         }
 
         switch (c) {
+#if 0
         case 'd':
             if (!strcmp(optarg, "all")) {
                 printopt = (printopt & ~LYP_WD_MASK) | LYP_WD_ALL;
@@ -730,6 +736,7 @@
                 printopt = (printopt & ~LYP_WD_MASK) | LYP_WD_IMPL_TAG;
             }
             break;
+#endif
         case 'h':
             cmd_data_help();
             ret = 0;
@@ -737,10 +744,12 @@
         case 'f':
             if (!strcmp(optarg, "xml")) {
                 outformat = LYD_XML;
+#if 0
             } else if (!strcmp(optarg, "json")) {
                 outformat = LYD_JSON;
             } else if (!strcmp(optarg, "lyb")) {
                 outformat = LYD_LYB;
+#endif
             } else {
                 fprintf(stderr, "Unknown output format \"%s\".\n", optarg);
                 goto cleanup;
@@ -827,9 +836,9 @@
 
     if (outformat != LYD_UNKNOWN) {
         if (options & LYD_OPT_RPCREPLY) {
-            lyd_print_file(output, data->child, outformat, LYP_WITHSIBLINGS | LYP_FORMAT | printopt);
+            lyd_print_file(output, lyd_node_children(data), outformat, LYDP_WITHSIBLINGS | LYDP_FORMAT | printopt);
         } else {
-            lyd_print_file(output, data, outformat, LYP_WITHSIBLINGS | LYP_FORMAT | printopt);
+            lyd_print_file(output, data, outformat, LYDP_WITHSIBLINGS | LYDP_FORMAT | printopt);
         }
     }
 
@@ -843,12 +852,12 @@
         fclose(output);
     }
 
-    lyd_free_withsiblings(val_tree);
-    lyd_free_withsiblings(data);
+    lyd_free_all(val_tree);
+    lyd_free_all(data);
 
     return ret;
 }
-
+#if 0
 int
 cmd_xpath(const char *arg)
 {
@@ -1540,8 +1549,8 @@
         {"add", cmd_add, cmd_add_help, "Add a new model from a specific file"},
         {"load", cmd_load, cmd_load_help, "Load a new model from the searchdirs"},
         {"print", cmd_print, cmd_print_help, "Print a model"},
-#if 0
         {"data", cmd_data, cmd_data_help, "Load, validate and optionally print instance data"},
+#if 0
         {"xpath", cmd_xpath, cmd_xpath_help, "Get data nodes satisfying an XPath expression"},
         {"list", cmd_list, cmd_list_help, "List all the loaded models"},
 #endif
diff --git a/tools/lint/main_ni.c b/tools/lint/main_ni.c
index e128649..8b72e15 100644
--- a/tools/lint/main_ni.c
+++ b/tools/lint/main_ni.c
@@ -202,26 +202,27 @@
  * 2 - data format
  */
 static int
-get_fileformat(const char *filename, LYS_INFORMAT *schema/* TODO , LYD_FORMAT *data */)
+get_fileformat(const char *filename, LYS_INFORMAT *schema, LYD_FORMAT *data)
 {
     char *ptr;
     LYS_INFORMAT informat_s;
-#if 0
     LYD_FORMAT informat_d;
-#endif
+
     /* get the file format */
     if ((ptr = strrchr(filename, '.')) != NULL) {
         ++ptr;
         if (!strcmp(ptr, "yang")) {
             informat_s = LYS_IN_YANG;
-#if 0
             informat_d = 0;
+#if 0
         } else if (!strcmp(ptr, "yin")) {
             informat_s = LYS_IN_YIN;
             informat_d = 0;
+#endif
         } else if (!strcmp(ptr, "xml")) {
             informat_s = 0;
             informat_d = LYD_XML;
+#if 0
         } else if (!strcmp(ptr, "json")) {
             informat_s = 0;
             informat_d = LYD_JSON;
@@ -234,24 +235,20 @@
         fprintf(stderr, "yanglint error: input file \"%s\" without file extension - unknown format.\n", filename);
         return 0;
     }
-#if 0
+
     if (data) {
         (*data) = informat_d;
     }
-#endif
+
     if (schema) {
         (*schema) = informat_s;
     }
 
-#if 0
     if (informat_s) {
         return 1;
     } else {
         return 2;
     }
-#else
-    return 1;
-#endif
 }
 
 int
@@ -289,9 +286,9 @@
 #if 0
         {"running",          required_argument, NULL, 'r'},
         {"operational",      required_argument, NULL, 'O'},
+#endif
         {"strict",           no_argument,       NULL, 's'},
         {"type",             required_argument, NULL, 't'},
-#endif
         {"version",          no_argument,       NULL, 'v'},
         {"verbose",          no_argument,       NULL, 'V'},
 #ifndef NDEBUG
@@ -305,8 +302,9 @@
     const struct lys_module *mod;
     LYS_OUTFORMAT outformat_s = 0;
     LYS_INFORMAT informat_s;
+    LYD_FORMAT informat_d, outformat_d = 0;
 #if 0
-    LYD_FORMAT informat_d, outformat_d = 0, ylformat = 0;
+    LYD_FORMAT ylformat = 0;
 #endif
     struct ly_set *searchpaths = NULL;
     const char *outtarget_s = NULL;
@@ -314,21 +312,23 @@
     struct stat st;
     uint32_t u;
     int options_ctx = LY_CTX_NOYANGLIBRARY, list = 0, outoptions_s = 0, outline_length_s = 0;
+    int autodetection = 0, options_parser = 0, merge = 0;
+    const char *oper_file = NULL;
 #if 0
-    const char *oper_file = NULL, *envelope_s = NULL;
+    const char *envelope_s = NULL;
     char *ylpath = NULL;
-    int options_dflt = 0, options_parser = 0, envelope = 0, autodetection = 0, merge = 0;
+    int options_dflt = 0, envelope = 0;
+    struct lyxml_elem *iter, *elem;
+    struct *subroot, *next, *node;
+#endif
+    struct lyd_node *oper = NULL;
     struct dataitem {
         const char *filename;
-        struct lyxml_elem *xml;
         struct lyd_node *tree;
         struct dataitem *next;
         LYD_FORMAT format;
         int type;
     } *data = NULL, *data_item, *data_prev = NULL;
-    struct lyxml_elem *iter, *elem;
-    struct lyd_node *oper = NULL, *subroot, *next, *node;
-#endif
     struct ly_set *mods = NULL;
     void *p;
     int index = 0;
@@ -367,8 +367,8 @@
         case 'f':
             if (!strcasecmp(optarg, "yang")) {
                 outformat_s = LYS_OUT_YANG;
-#if 0
                 outformat_d = 0;
+#if 0
             } else if (!strcasecmp(optarg, "tree")) {
                 outformat_s = LYS_OUT_TREE;
                 outformat_d = 0;
@@ -382,9 +382,11 @@
             } else if (!strcasecmp(optarg, "jsons")) {
                 outformat_s = LYS_OUT_JSON;
                 outformat_d = 0;
+#endif
             } else if (!strcasecmp(optarg, "xml")) {
                 outformat_s = 0;
                 outformat_d = LYD_XML;
+#if 0
             } else if (!strcasecmp(optarg, "json")) {
                 outformat_s = 0;
                 outformat_d = LYD_JSON;
@@ -504,6 +506,7 @@
                 oper_file = optarg;
             }
             break;
+#endif
         case 's':
             options_parser |= LYD_OPT_STRICT;
             break;
@@ -533,7 +536,6 @@
                 goto cleanup;
             }
             break;
-#endif
         case 'v':
             version();
             ret = EXIT_SUCCESS;
@@ -656,11 +658,11 @@
         /* ignore operational datastore file */
         oper_file = NULL;
     }
+#endif
     if ((options_parser & LYD_OPT_TYPEMASK) == LYD_OPT_DATA) {
         /* add option to ignore ietf-yang-library data for implicit data type */
         options_parser |= LYD_OPT_DATA_NO_YANGLIB;
     }
-#endif
 
     /* set callback for printing libyang messages */
     ly_set_log_clb(libyang_verbclb, 1);
@@ -695,7 +697,7 @@
     /* divide input files */
     for (i = 0; i < argc - optind; i++) {
         /* get the file format */
-        if (!get_fileformat(argv[optind + i], &informat_s/* TODO, &informat_d */)) {
+        if (!get_fileformat(argv[optind + i], &informat_s, &informat_d)) {
             goto cleanup;
         }
 
@@ -713,7 +715,6 @@
                 goto cleanup;
             }
             ly_set_add(mods, (void *)mod, 0);
-#if 0
         } else {
             if (autodetection && informat_d != LYD_XML) {
                 /* data file content autodetection is possible only for XML input */
@@ -733,17 +734,13 @@
             data_item->format = informat_d;
             data_item->type = options_parser & LYD_OPT_TYPEMASK;
             data_item->tree = NULL;
-            data_item->xml = NULL;
             data_item->next = NULL;
-#endif
         }
     }
-#if 0
     if (outformat_d && !data && !list) {
         fprintf(stderr, "yanglint error: no input data file for the specified data output format.\n");
         goto cleanup;
     }
-#endif
 
     /* enable specified features, if not specified, all the module's features are enabled */
     u = 4; /* skip internal libyang modules */
@@ -795,9 +792,7 @@
                 fputs("\n", out);
             }
         }
-#if 0
     } else if (data) {
-        ly_errno = 0;
 
         /* prepare operational datastore when specified for RPC/Notification */
         if (oper_file) {
@@ -817,6 +812,7 @@
 
         for (data_item = data, data_prev = NULL; data_item; data_prev = data_item, data_item = data_item->next) {
             /* parse data file - via LYD_OPT_TRUSTED postpone validation when all data are loaded and merged */
+#if 0
             if (autodetection) {
                 /* erase option not covered by LYD_OPT_TYPEMASK, but used according to the type */
                 options_parser &= ~LYD_OPT_DATA_NO_YANGLIB;
@@ -974,12 +970,15 @@
                     continue;
                 }
             } else {
+#else
+            {
+#endif
                 data_item->tree = lyd_parse_path(ctx, data_item->filename, data_item->format, options_parser, oper);
             }
-            if (ly_errno) {
+            if (ly_err_first(ctx)) {
                 goto cleanup;
             }
-
+#if 0
             if (merge && data != data_item) {
                 if (!data->tree) {
                     data->tree = data_item->tree;
@@ -992,8 +991,9 @@
                 }
                 data_item->tree = NULL;
             }
+#endif
         }
-
+#if 0
         if (merge) {
             /* validate the merged data tree, do not trust the input, invalidate all the data first */
             LY_TREE_FOR(data->tree, subroot) {
@@ -1025,13 +1025,14 @@
                 goto cleanup;
             }
         }
-
+#endif
         /* print only if data output format specified */
         if (outformat_d) {
             for (data_item = data; data_item; data_item = data_item->next) {
                 if (!merge && verbose >= 2) {
                     fprintf(stdout, "File %s:\n", data_item->filename);
                 }
+#if 0
                 if (outformat_d == LYD_XML && envelope) {
                     switch (data_item->type) {
                     case LYD_OPT_DATA:
@@ -1065,8 +1066,10 @@
                         fprintf(out, "<action xmlns=\"urn:ietf:params:xml:ns:yang:1\">\n");
                     }
                 }
-                lyd_print_file(out, (data_item->type == LYD_OPT_RPCREPLY) ? data_item->tree->child : data_item->tree,
-                               outformat_d, LYP_WITHSIBLINGS | LYP_FORMAT | options_dflt);
+#endif
+                lyd_print_file(out, (data_item->type == LYD_OPT_RPCREPLY) ? lyd_node_children(data_item->tree) : data_item->tree,
+                               outformat_d, LYDP_WITHSIBLINGS | LYDP_FORMAT /* TODO defaults | options_dflt */);
+#if 0
                 if (envelope_s) {
                     if (data_item->type == LYD_OPT_RPC && data_item->tree->schema->nodetype != LYS_RPC) {
                         fprintf(out, "</action>\n");
@@ -1077,9 +1080,9 @@
                     /* stop after first item */
                     break;
                 }
+#endif
             }
         }
-#endif
     }
 #if 0
     if (list) {
@@ -1099,15 +1102,12 @@
         free(feat[i]);
     }
     free(feat);
-#if 0
     for (; data; data = data_item) {
         data_item = data->next;
-        lyxml_free(ctx, data->xml);
-        lyd_free_withsiblings(data->tree);
+        lyd_free_all(data->tree);
         free(data);
     }
-    lyd_free_withsiblings(oper);
-#endif
+    lyd_free_all(oper);
     ly_ctx_destroy(ctx, NULL);
 
     return ret;