validation NEW duplicate instances

Also trees structure removed, some
refactoring included.
diff --git a/src/common.h b/src/common.h
index 99f5ec6..3be741d 100644
--- a/src/common.h
+++ b/src/common.h
@@ -233,6 +233,8 @@
 #define LY_VCODE_NOMIN          LYVE_DATA, "Too few \"%s\" instances."
 #define LY_VCODE_NOMAX          LYVE_DATA, "Too many \"%s\" instances."
 #define LY_VCODE_NOUNIQ         LYVE_DATA, "Unique data leaf(s) \"%s\" not satisfied in \"%s\" and \"%s\"."
+#define LY_VCODE_DUP            LYVE_DATA, "Duplicate instance of \"%s\"."
+#define LY_VCODE_DUPCASE        LYVE_DATA, "Data for both cases \"%s\" and \"%s\" exist."
 
 /******************************************************************************
  * Context
diff --git a/src/parser_xml.c b/src/parser_xml.c
index b23b5bf..be516d4 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -450,7 +450,7 @@
     }
     ly_set_erase(&attrs_data, free);
     if (ret && *node) {
-        lyd_free_withsiblings(*node);
+        lyd_free_siblings(*node);
         *node = NULL;
     }
     return ret;
@@ -460,7 +460,6 @@
 lyd_parse_xml(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **result)
 {
     LY_ERR ret = LY_SUCCESS;
-    const struct lyd_node **result_trees = NULL;
     struct lyd_xml_ctx xmlctx = {0};
 
     xmlctx.options = options;
@@ -478,19 +477,14 @@
         ret = lyd_validate_defaults_top(result, NULL, 0, ctx, &xmlctx.incomplete_type_validation, &xmlctx.when_check, options);
         LY_CHECK_GOTO(ret, cleanup);
 
-        /* prepare sized array for validator */
-        if (*result) {
-            result_trees = lyd_trees_new(1, *result);
-        }
-
         /* finish incompletely validated terminal values/attributes and when conditions */
         ret = lyd_validate_unres(&xmlctx.incomplete_type_validation, &xmlctx.incomplete_type_validation_attrs,
-                                 &xmlctx.when_check, LYD_XML, lydxml_resolve_prefix, ctx, result_trees);
+                                 &xmlctx.when_check, LYD_XML, lydxml_resolve_prefix, ctx, *result);
         LY_CHECK_GOTO(ret, cleanup);
 
         /* context node and other validation tasks that depend on other data nodes */
-        ret = lyd_validate_data(result_trees, NULL, 0, ctx, options);
-        LY_CHECK_GOTO(result, cleanup);
+        ret = lyd_validate_data(result, NULL, 0, ctx, options);
+        LY_CHECK_GOTO(ret, cleanup);
     }
 
 cleanup:
@@ -502,7 +496,6 @@
     ly_set_erase(&xmlctx.incomplete_type_validation_attrs, NULL);
     ly_set_erase(&xmlctx.when_check, NULL);
     lyxml_context_clear((struct lyxml_context *)&xmlctx);
-    lyd_trees_free(result_trees, 0);
     if (ret) {
         lyd_free_all(*result);
         *result = NULL;
diff --git a/src/plugins_types.c b/src/plugins_types.c
index bf0dd16..f05b5c2 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -484,7 +484,7 @@
 static LY_ERR
 ly_type_store_int(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                   ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                  const void *UNUSED(context_node), const struct lyd_node **UNUSED(trees),
+                  const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
                   struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     LY_ERR ret;
@@ -560,7 +560,7 @@
 static LY_ERR
 ly_type_store_uint(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                    ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                   const void *UNUSED(context_node), const struct lyd_node **UNUSED(trees),
+                   const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
                    struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     LY_ERR ret;
@@ -635,7 +635,7 @@
 static LY_ERR
 ly_type_store_decimal64(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                         ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                        const void *UNUSED(context_node), const struct lyd_node **UNUSED(trees),
+                        const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
                         struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     int64_t d;
@@ -719,7 +719,7 @@
 static LY_ERR
 ly_type_store_binary(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                      ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                     const void *UNUSED(context_node), const struct lyd_node **UNUSED(trees),
+                     const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
                      struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     size_t start = 0, stop = 0, count = 0, u, termination = 0;
@@ -824,7 +824,7 @@
 static LY_ERR
 ly_type_store_string(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                      ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                     const void *UNUSED(context_node), const struct lyd_node **UNUSED(trees),
+                     const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
                      struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     struct lysc_type_str *type_str = (struct lysc_type_str *)type;
@@ -868,7 +868,7 @@
 static LY_ERR
 ly_type_store_bits(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                    ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                   const void *UNUSED(context_node), const struct lyd_node **UNUSED(trees),
+                   const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
                    struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     LY_ERR ret = LY_EVALID;
@@ -1053,7 +1053,7 @@
 static LY_ERR
 ly_type_store_enum(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                    ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                   const void *UNUSED(context_node), const struct lyd_node **UNUSED(trees),
+                   const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
                    struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     unsigned int u, v;
@@ -1129,7 +1129,7 @@
 static LY_ERR
 ly_type_store_boolean(struct ly_ctx *ctx, struct lysc_type *UNUSED(type), const char *value, size_t value_len, int options,
                       ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                      const void *UNUSED(context_node), const struct lyd_node **UNUSED(trees),
+                      const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
                       struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     int8_t i;
@@ -1185,7 +1185,7 @@
 static LY_ERR
 ly_type_store_empty(struct ly_ctx *ctx, struct lysc_type *UNUSED(type), const char *value, size_t value_len, int options,
                     ly_clb_resolve_prefix UNUSED(resolve_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                    const void *UNUSED(context_node), const struct lyd_node **UNUSED(trees),
+                    const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
                     struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     if (options & LY_TYPE_OPTS_SECOND_CALL) {
@@ -1246,7 +1246,7 @@
 static LY_ERR
 ly_type_store_identityref(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                           ly_clb_resolve_prefix resolve_prefix, void *parser, LYD_FORMAT UNUSED(format),
-                          const void *UNUSED(context_node), const struct lyd_node **UNUSED(trees),
+                          const void *UNUSED(context_node), const struct lyd_node *UNUSED(tree),
                           struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     struct lysc_type_identityref *type_ident = (struct lysc_type_identityref *)type;
@@ -1402,7 +1402,7 @@
 ly_type_store_instanceid_checknodeid(const char *orig, size_t orig_len, int options, int require_instance,
                                      const char **token, struct lyd_value_prefix *prefixes, LYD_FORMAT format,
                                      const struct lysc_node **node_s, const struct lyd_node **node_d,
-                                     const struct lyd_node **trees, char **errmsg)
+                                     const struct lyd_node *tree, char **errmsg)
 {
     const char *id, *prefix;
     size_t id_len, prefix_len;
@@ -1463,12 +1463,7 @@
             }
         } else {
             /* top-level node */
-            LY_ARRAY_FOR(trees, u) {
-                lyd_find_sibling_next(trees[u], mod, id, id_len, NULL, 0, (struct lyd_node **)node_d);
-                if (*node_d) {
-                    break;
-                }
-            }
+            lyd_find_sibling_next(tree, mod, id, id_len, NULL, 0, (struct lyd_node **)node_d);
             if (!(*node_d)) {
                 /* node not found */
                 asprintf(errmsg, "Invalid instance-identifier \"%.*s\" value - path \"%.*s\" does not exists in the data tree(s).",
@@ -1588,7 +1583,7 @@
 static LY_ERR
 ly_type_store_instanceid(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                          ly_clb_resolve_prefix resolve_prefix, void *parser, LYD_FORMAT format,
-                         const void *UNUSED(context_node), const struct lyd_node **trees,
+                         const void *UNUSED(context_node), const struct lyd_node *tree,
                          struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     LY_ERR ret = LY_EVALID;
@@ -1620,7 +1615,7 @@
 
     if (!(options & LY_TYPE_OPTS_SCHEMA) && (options & LY_TYPE_OPTS_SECOND_CALL) && (options & LY_TYPE_OPTS_STORE)) {
         /* the second run in data tree, the first one ended with LY_EINCOMPLETE, but we have prepared the target structure */
-        if (!lyd_target(storage->target, trees)) {
+        if (!lyd_target(storage->target, tree)) {
             /* in error message we print the JSON format of the instance-identifier - in case of XML, it is not possible
              * to get the exactly same string as original, JSON is less demanding and still well readable/understandable. */
             int dynamic = 0;
@@ -1663,7 +1658,7 @@
 
             token++;
             if (ly_type_store_instanceid_checknodeid(value, value_len, options, type_inst->require_instance,
-                                                     &token, prefixes, format, &node_s, &node_d, trees, &errmsg)) {
+                                                     &token, prefixes, format, &node_s, &node_d, tree, &errmsg)) {
                 goto error;
             }
 
@@ -1724,7 +1719,7 @@
 
                 /* resolve the key in predicate */
                 if (ly_type_store_instanceid_checknodeid(value, value_len, options, type_inst->require_instance,
-                                                            &t, prefixes, format, &key_s, &key_d, trees, &errmsg)) {
+                                                            &t, prefixes, format, &key_s, &key_d, tree, &errmsg)) {
                     goto error;
                 }
                 if (key_d) {
@@ -1740,7 +1735,7 @@
 
                 if (node_d) {
                     while (node_d) {
-                        if (!lyd_value_compare((const struct lyd_node_term*)key_d, val, val_len, resolve_prefix, parser, format, trees)) {
+                        if (!lyd_value_compare((const struct lyd_node_term*)key_d, val, val_len, resolve_prefix, parser, format, tree)) {
                             /* match */
                             break;
                         }
@@ -1818,7 +1813,7 @@
 
                 if (key_d) {
                     while (key_d) {
-                        if (!lyd_value_compare((const struct lyd_node_term*)key_d, val, val_len, resolve_prefix, parser, format, trees)) {
+                        if (!lyd_value_compare((const struct lyd_node_term*)key_d, val, val_len, resolve_prefix, parser, format, tree)) {
                             /* match */
                             break;
                         }
@@ -2167,12 +2162,11 @@
  */
 const struct lyd_node *
 ly_type_find_leafref(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len,
-                     const struct lyd_node *context_node, const struct lyd_node **trees, struct lyd_value *storage, char **errmsg)
+                     const struct lyd_node *context_node, const struct lyd_node *tree, struct lyd_value *storage, char **errmsg)
 {
     struct lysc_type_leafref *type_lr = (struct lysc_type_leafref*)type;
     const char *first_pred = NULL;
     const struct lyd_node *start_search;
-    unsigned int u = 0;
     const char *prefix, *id;
     size_t prefix_len, id_len;
     const struct lys_module *mod_node = NULL;
@@ -2219,14 +2213,9 @@
                 }
             } else {
                 /* top-level node */
-                LY_ARRAY_FOR(trees, u) {
-                    start_search = trees[u];
+                start_search = tree;
 next_instance_toplevel:
-                    lyd_find_sibling_next(start_search, mod_node, id, id_len, NULL, 0, (struct lyd_node **)&node);
-                    if (node) {
-                        break;
-                    }
-                }
+                lyd_find_sibling_next(start_search, mod_node, id, id_len, NULL, 0, (struct lyd_node **)&node);
             }
             if (!node) {
                 /* node not found */
@@ -2299,12 +2288,7 @@
 
                 if (!value) {
                     /* top-level search */
-                    LY_ARRAY_FOR(trees, u) {
-                        lyd_find_sibling_next(trees[u], mod_pred, src, src_len, NULL, 0, (struct lyd_node **)&value);
-                        if (value) {
-                            break;
-                        }
-                    }
+                    lyd_find_sibling_next(tree, mod_pred, src, src_len, NULL, 0, (struct lyd_node **)&value);
                 } else {
                     /* inner node */
                     lyd_find_sibling_next(lyd_node_children(value), mod_pred, src, src_len, NULL, 0, (struct lyd_node **)&value);
@@ -2369,7 +2353,7 @@
 static LY_ERR
 ly_type_store_leafref(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                       ly_clb_resolve_prefix resolve_prefix, void *parser, LYD_FORMAT format,
-                      const void *context_node, const struct lyd_node **trees,
+                      const void *context_node, const struct lyd_node *tree,
                       struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     LY_ERR ret;
@@ -2388,7 +2372,7 @@
 
     /* check value according to the real type of the leafref target */
     ret = type_lr->realtype->plugin->store(ctx, type_lr->realtype, value, value_len, options,
-                                           resolve_prefix, parser, format, context_node, trees,
+                                           resolve_prefix, parser, format, context_node, tree,
                                            storage, canonized, err);
     if (ret != LY_SUCCESS && ret != LY_EINCOMPLETE) {
         return ret;
@@ -2400,7 +2384,7 @@
         }
 
         /* find corresponding data instance */
-        if (!ly_type_find_leafref(ctx, type, value, value_len, (const struct lyd_node *)context_node, trees, storage, &errmsg)) {
+        if (!ly_type_find_leafref(ctx, type, value, value_len, (const struct lyd_node *)context_node, tree, storage, &errmsg)) {
             goto error;
         }
     }
@@ -2474,7 +2458,7 @@
 static LY_ERR
 ly_type_store_union(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                     ly_clb_resolve_prefix resolve_prefix, void *parser, LYD_FORMAT format,
-                    const void *context_node, const struct lyd_node **trees,
+                    const void *context_node, const struct lyd_node *tree,
                     struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     LY_ERR ret;
@@ -2490,7 +2474,7 @@
         ret = subvalue->value->realtype->plugin->store(ctx, subvalue->value->realtype, value, value_len,
                                                        options & ~(LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_DYNAMIC),
                                                        ly_type_stored_prefixes_clb, subvalue->prefixes, format,
-                                                       context_node, trees, subvalue->value, canonized, err);
+                                                       context_node, tree, subvalue->value, canonized, err);
         if (ret) {
             /* second call failed, we have to try another subtype of the union.
              * Unfortunately, since the realtype can change (e.g. in leafref), we are not able to detect
@@ -2519,7 +2503,7 @@
             subvalue->value->realtype = type_u->types[u];
             ret = type_u->types[u]->plugin->store(ctx, type_u->types[u], value, value_len, options & ~LY_TYPE_OPTS_DYNAMIC,
                                                   ly_type_stored_prefixes_clb, subvalue->prefixes, format,
-                                                  context_node, trees, subvalue->value, canonized, err);
+                                                  context_node, tree, subvalue->value, canonized, err);
             if (ret == LY_SUCCESS || ret == LY_EINCOMPLETE) {
                 /* success (or not yet complete) */
                 break;
diff --git a/src/plugins_types.h b/src/plugins_types.h
index bdff1f7..2987382 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -145,8 +145,7 @@
  * @param[in] context_node The @p value's node for the case that the require-instance restriction is supposed to be resolved.
  *            This argument is a lys_node (in case LY_TYPE_OPTS_INCOMPLETE_DATA or LY_TYPE_OPTS_SCHEMA set in @p options)
  *            or lyd_node structure.
- * @param[in] trees ([Sized array](@ref sizedarrays)) of external data trees (e.g. when validating RPC/Notification)
- *            where the required data instance can be placed.
+ * @param[in] tree External data tree (e.g. when validating RPC/Notification) where the required data instance can be placed.
  * @param[in,out] storage If LY_TYPE_OPTS_STORE option set, the parsed data are stored into this structure in the type's specific way.
  *             If the @p canonized differs from the storage's canonized member, the canonized value is also stored here despite the
  *             LY_TYPE_OPTS_CANONIZE option.
@@ -161,7 +160,7 @@
  */
 typedef LY_ERR (*ly_type_store_clb)(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                                     ly_clb_resolve_prefix resolve_prefix, void *parser, LYD_FORMAT format,
-                                    const void *context_node, const struct lyd_node **trees,
+                                    const void *context_node, const struct lyd_node *tree,
                                     struct lyd_value *storage, const char **canonized, struct ly_err_item **err);
 
 /**
@@ -335,7 +334,7 @@
  *            It is never NULL, empty string is represented as "" with zero @p value_len.
  * @param[in] value_len Length (number of bytes) of the given \p value.
  * @param[in] context_node The @p value's node for the case that the require-instance restriction is supposed to be resolved.
- * @param[in] trees ([Sized array](@ref sizedarrays)) of external data trees (e.g. when validating RPC/Notification) where the required data
+ * @param[in] tree External data tree (e.g. when validating RPC/Notification) where the required data
  *            instance can be placed.
  *
  * @param[in] storage Parsed @p value.
@@ -343,7 +342,7 @@
  * @return Leafref target node or NULL on error when @p errmsg is always set.
  */
 const struct lyd_node *ly_type_find_leafref(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len,
-                                            const struct lyd_node *context_node, const struct lyd_node **trees,
+                                            const struct lyd_node *context_node, const struct lyd_node *tree,
                                             struct lyd_value *storage, char **errmsg);
 
 /**
diff --git a/src/tree_data.c b/src/tree_data.c
index 78529f5..bf3402c 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -42,89 +42,16 @@
     size_t key_count;
 };
 
-API void
-lyd_trees_free(const struct lyd_node **trees, int free_data)
-{
-    if (!trees) {
-        return;
-    }
-
-    if (free_data) {
-        unsigned int u;
-        LY_ARRAY_FOR(trees, u) {
-            lyd_free_all((struct lyd_node *)trees[u]);
-        }
-    }
-    LY_ARRAY_FREE(trees);
-}
-
-static const struct lyd_node *
-lyd_trees_getstart(const struct lyd_node *tree)
-{
-    if (!tree) {
-        return NULL;
-    }
-    while (tree->prev->next) {
-        tree = tree->prev;
-    }
-    return tree;
-}
-
-API const struct lyd_node **
-lyd_trees_new(size_t count, const struct lyd_node *tree, ...)
-{
-    LY_ERR ret;
-    const struct lyd_node **trees = NULL;
-    va_list ap;
-
-    LY_CHECK_ARG_RET(NULL, tree, count > 0, NULL);
-
-    va_start(ap, tree);
-
-    LY_ARRAY_CREATE_GOTO(tree->schema->module->ctx, trees, count, ret, error);
-    /* first, mandatory, tree to insert */
-    trees[0] = lyd_trees_getstart(tree);
-    LY_ARRAY_INCREMENT(trees);
-
-    /* variable arguments */
-    for (unsigned int u = 1; u < count; ++u) {
-        trees[u] = lyd_trees_getstart(va_arg(ap, const struct lyd_node *));
-        LY_ARRAY_INCREMENT(trees);
-    }
-
-    va_end(ap);
-    return trees;
-
-error:
-    (void)ret; /* unused */
-    lyd_trees_free(trees, 1);
-    va_end(ap);
-    return NULL;
-}
-
-API const struct lyd_node **
-lyd_trees_add(const struct lyd_node **trees, const struct lyd_node *tree)
-{
-    const struct lyd_node **t = NULL;
-
-    LY_CHECK_ARG_RET(NULL, tree, trees, trees);
-
-    LY_ARRAY_NEW_RET(tree->schema->module->ctx, trees, t, NULL);
-    *t = lyd_trees_getstart(tree);
-
-    return trees;
-}
-
 LY_ERR
 lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int *dynamic, int second,
-                ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node **trees)
+                ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node *tree)
 {
     LY_ERR ret = LY_SUCCESS;
     struct ly_err_item *err = NULL;
     struct ly_ctx *ctx;
     struct lysc_type *type;
     int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
-            (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
+            (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
     assert(node);
 
     ctx = node->schema->module->ctx;
@@ -134,7 +61,7 @@
         node->value.realtype = type;
     }
     ret = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format,
-                             trees ? (void*)node : (void*)node->schema, trees,
+                             tree ? (void *)node : (void *)node->schema, tree,
                              &node->value, NULL, &err);
     if (ret && (ret != LY_EINCOMPLETE)) {
         if (err) {
@@ -187,15 +114,15 @@
 LY_ERR
 lyd_value_parse_attr(struct ly_ctx *ctx, struct lyd_attr *attr, const char *value, size_t value_len, int *dynamic,
                      int second, ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
-                     const struct lysc_node *ctx_snode, const struct lyd_node **trees)
+                     const struct lysc_node *ctx_snode, const struct lyd_node *tree)
 {
     LY_ERR ret = LY_SUCCESS;
     struct ly_err_item *err = NULL;
     struct lyext_metadata *ant;
     int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
-            (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
+            (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
 
-    assert(ctx && attr && ((trees && attr->parent) || ctx_snode));
+    assert(ctx && attr && ((tree && attr->parent) || ctx_snode));
 
     ant = attr->annotation->data;
 
@@ -203,7 +130,7 @@
         attr->value.realtype = ant->type;
     }
     ret = ant->type->plugin->store(ctx, ant->type, value, value_len, options, get_prefix, parser, format,
-                                  trees ? (void *)attr->parent : (void *)ctx_snode, trees, &attr->value, NULL, &err);
+                                  tree ? (void *)attr->parent : (void *)ctx_snode, tree, &attr->value, NULL, &err);
     if (ret && (ret != LY_EINCOMPLETE)) {
         if (err) {
             ly_err_print(err);
@@ -256,18 +183,18 @@
 
 API LY_ERR
 lyd_value_validate(struct ly_ctx *ctx, const struct lyd_node_term *node, const char *value, size_t value_len,
-                   ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node **trees)
+                   ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node *tree)
 {
     LY_ERR rc;
     struct ly_err_item *err = NULL;
     struct lysc_type *type;
-    int options = (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
+    int options = (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
 
     LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
 
     type = ((struct lysc_node_leaf*)node->schema)->type;
     rc = type->plugin->store(ctx ? ctx : node->schema->module->ctx, type, value, value_len, options,
-                             get_prefix, get_prefix_data, format, trees ? (void*)node : (void*)node->schema, trees,
+                             get_prefix, get_prefix_data, format, tree ? (void*)node : (void*)node->schema, tree,
                              NULL, NULL, &err);
     if (rc == LY_EINCOMPLETE) {
         return rc;
@@ -287,21 +214,21 @@
 
 API LY_ERR
 lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len,
-                  ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node **trees)
+                  ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node *tree)
 {
     LY_ERR ret = LY_SUCCESS, rc;
     struct ly_err_item *err = NULL;
     struct ly_ctx *ctx;
     struct lysc_type *type;
     struct lyd_value data = {0};
-    int options = LY_TYPE_OPTS_STORE | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
+    int options = LY_TYPE_OPTS_STORE | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
 
     LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
 
     ctx = node->schema->module->ctx;
     type = ((struct lysc_node_leaf*)node->schema)->type;
     rc = type->plugin->store(ctx, type, value, value_len, options, get_prefix, get_prefix_data, format, (struct lyd_node*)node,
-                             trees, &data, NULL, &err);
+                             tree, &data, NULL, &err);
     if (rc == LY_EINCOMPLETE) {
         ret = rc;
         /* continue with comparing, just remember what to return if storing is ok */
@@ -605,7 +532,12 @@
 
     memset(keys, 0, sizeof *keys);
 
-    keys->str = strndup(keys_str, keys_len ? keys_len : strlen(keys_str));
+    if (!keys_str) {
+        /* nothing to parse */
+        return LY_SUCCESS;
+    }
+
+    keys->str = strndup(keys_str, keys_len);
     LY_CHECK_ERR_GOTO(!keys->str, LOGMEM(list->module->ctx); ret = LY_EMEM, cleanup);
 
     next_key = keys->str;
@@ -686,8 +618,8 @@
 
     /* create and insert all the keys */
     for (i = 0; i < keys.key_count; ++i) {
-        LY_CHECK_GOTO(ret = lyd_create_term((struct lysc_node *)keys.keys[i].schema, keys.keys[i].value, 0, 0,
-                                            lydjson_resolve_prefix, NULL, LYD_JSON, &key), cleanup);
+        LY_CHECK_GOTO(ret = lyd_create_term((struct lysc_node *)keys.keys[i].schema, keys.keys[i].value,
+                                            strlen(keys.keys[i].value), NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &key), cleanup);
         lyd_insert_node(list, NULL, key);
     }
 
@@ -735,6 +667,10 @@
 
     LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
 
+    if (!module) {
+        module = parent->schema->module;
+    }
+
     schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_CONTAINER | LYS_NOTIF | LYS_ACTION, 0);
     LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Inner node \"%s\" not found.", name), NULL);
 
@@ -756,6 +692,10 @@
 
     LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
 
+    if (!module) {
+        module = parent->schema->module;
+    }
+
     schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, 0);
     LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), NULL);
 
@@ -768,7 +708,8 @@
     for (key_s = lysc_node_children(schema, 0); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
         key_val = va_arg(ap, const char *);
 
-        LY_CHECK_GOTO(rc = lyd_create_term(key_s, key_val, 0, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &key), cleanup);
+        rc = lyd_create_term(key_s, key_val, key_val ? strlen(key_val) : 0, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &key);
+        LY_CHECK_GOTO(rc, cleanup);
         lyd_insert_node(ret, NULL, key);
     }
 
@@ -797,10 +738,14 @@
 
     LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
 
+    if (!module) {
+        module = parent->schema->module;
+    }
+
     schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, 0);
     LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), NULL);
 
-    if (!lyd_create_list(schema, keys, 0, &ret) && parent) {
+    if (!lyd_create_list(schema, keys, keys ? strlen(keys) : 0, &ret) && parent) {
         lyd_insert_node(parent, NULL, ret);
     }
     return ret;
@@ -815,10 +760,15 @@
 
     LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
 
+    if (!module) {
+        module = parent->schema->module;
+    }
+
     schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_TERM, 0);
     LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Term node \"%s\" not found.", name), NULL);
 
-    if (!lyd_create_term(schema, val_str, 0, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &ret) && parent) {
+    if (!lyd_create_term(schema, val_str, val_str ? strlen(val_str) : 0, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &ret)
+            && parent) {
         lyd_insert_node(parent, NULL, ret);
     }
     return ret;
@@ -834,6 +784,10 @@
 
     LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
 
+    if (!module) {
+        module = parent->schema->module;
+    }
+
     schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_ANY, 0);
     LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Any node \"%s\" not found.", name), NULL);
 
@@ -867,7 +821,7 @@
  * @param[in] node Node to insert.
  */
 static void
-lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
+lyd_insert_after_node(struct lyd_node *sibling, struct lyd_node *node)
 {
     assert(!node->next && (node->prev == node));
 
@@ -896,7 +850,7 @@
  * @param[in] node Node to insert.
  */
 static void
-lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
+lyd_insert_before_node(struct lyd_node *sibling, struct lyd_node *node)
 {
     assert(!node->next && (node->prev == node));
 
@@ -921,7 +875,7 @@
  * @param[in] node Node to insert.
  */
 static void
-lyd_insert_last(struct lyd_node *parent, struct lyd_node *node)
+lyd_insert_last_node(struct lyd_node *parent, struct lyd_node *node)
 {
     struct lyd_node_inner *par;
 
@@ -956,15 +910,15 @@
             /* it is key and we need to insert it at the correct place */
             anchor = lyd_get_prev_key_anchor(lyd_node_children(parent), node->schema);
             if (anchor) {
-                lyd_insert_after(anchor, node);
+                lyd_insert_after_node(anchor, node);
             } else if (lyd_node_children(parent)) {
-                lyd_insert_before((struct lyd_node *)lyd_node_children(parent), node);
+                lyd_insert_before_node((struct lyd_node *)lyd_node_children(parent), node);
             } else {
-                lyd_insert_last(parent, node);
+                lyd_insert_last_node(parent, node);
             }
         } else {
             /* last child */
-            lyd_insert_last(parent, node);
+            lyd_insert_last_node(parent, node);
         }
     } else if (*first_sibling) {
         /* top-level siblings, find the last one from this module, or simply the last */
@@ -974,7 +928,7 @@
         }
 
         /* insert */
-        lyd_insert_after(anchor, node);
+        lyd_insert_after_node(anchor, node);
     } else {
         /* the only sibling */
         *first_sibling = node;
@@ -992,6 +946,187 @@
     lyd_insert_hash(node);
 }
 
+static LY_ERR
+lyd_insert_check_schema(const struct lysc_node *parent, const struct lysc_node *schema)
+{
+    const struct lysc_node *par2;
+
+    assert(schema);
+
+    /* adjust parent first */
+    while (parent && (parent->nodetype & (LYS_CASE | LYS_CHOICE))) {
+        parent = parent->parent;
+    }
+
+    /* find schema parent */
+    for (par2 = schema->parent; par2 && (par2->nodetype & (LYS_CASE | LYS_CHOICE)); par2 = par2->parent);
+
+    if (parent) {
+        /* inner node */
+        if (par2 != parent) {
+            LOGERR(parent->module->ctx, LY_EINVAL, "Cannot insert, parent of \"%s\" is not \"%s\".", schema->name, parent->name);
+            return LY_EINVAL;
+        }
+    } else {
+        /* top-level node */
+        if (par2) {
+            LOGERR(parent->module->ctx, LY_EINVAL, "Cannot insert, node \"%s\" is not top-level.", schema->name);
+            return LY_EINVAL;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+API LY_ERR
+lyd_insert(struct lyd_node *parent, struct lyd_node *node)
+{
+    struct lyd_node *iter;
+
+    LY_CHECK_ARG_RET(NULL, parent, node, !(parent->schema->nodetype & LYD_NODE_INNER), LY_EINVAL);
+
+    LY_CHECK_RET(lyd_insert_check_schema(parent->schema, node->schema));
+
+    if (node->schema->flags & LYS_KEY) {
+        LOGERR(parent->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
+        return LY_EINVAL;
+    }
+
+    if (node->parent || node->prev->next) {
+        lyd_unlink_tree(node);
+    }
+
+    while (node) {
+        iter = node->next;
+        lyd_unlink_tree(node);
+        lyd_insert_node(parent, NULL, node);
+        node = iter;
+    }
+    return LY_SUCCESS;
+}
+
+API LY_ERR
+lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
+{
+    struct lyd_node *iter;
+
+    LY_CHECK_ARG_RET(NULL, sibling, node, LY_EINVAL);
+
+    LY_CHECK_RET(lyd_insert_check_schema(sibling->schema->parent, node->schema));
+
+    if (node->schema->flags & LYS_KEY) {
+        LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
+        return LY_EINVAL;
+    } else if (sibling->schema->flags & LYS_KEY) {
+        LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert into keys.");
+        return LY_EINVAL;
+    }
+
+    if (node->parent || node->prev->next) {
+        lyd_unlink_tree(node);
+    }
+
+    /* insert in reverse order to get the original order */
+    node = node->prev;
+    while (node) {
+        iter = node->prev;
+        lyd_unlink_tree(node);
+
+        lyd_insert_before_node(sibling, node);
+        /* move the anchor accordingly */
+        sibling = node;
+
+        node = (iter == node) ? NULL : iter;
+    }
+    return LY_SUCCESS;
+}
+
+API LY_ERR
+lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
+{
+    struct lyd_node *iter;
+
+    LY_CHECK_ARG_RET(NULL, sibling, node, LY_EINVAL);
+
+    LY_CHECK_RET(lyd_insert_check_schema(sibling->schema->parent, node->schema));
+
+    if (node->schema->flags & LYS_KEY) {
+        LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
+        return LY_EINVAL;
+    } else if (sibling->next && (sibling->next->schema->flags & LYS_KEY)) {
+        LOGERR(sibling->schema->module->ctx, LY_EINVAL, "Cannot insert into keys.");
+        return LY_EINVAL;
+    }
+
+    if (node->parent || node->prev->next) {
+        lyd_unlink_tree(node);
+    }
+
+    while (node) {
+        iter = node->next;
+        lyd_unlink_tree(node);
+
+        lyd_insert_after_node(sibling, node);
+        /* move the anchor accordingly */
+        sibling = node;
+
+        node = iter;
+    }
+    return LY_SUCCESS;
+}
+
+API void
+lyd_unlink_tree(struct lyd_node *node)
+{
+    struct lyd_node *iter;
+
+    if (!node) {
+        return;
+    }
+
+    /* 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 = node->parent->child;
+        } 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 (node->parent->child == node) {
+            /* the node is the first child */
+            node->parent->child = node->next;
+        }
+
+        lyd_unlink_hash(node);
+
+        /* check for keyless list and update its hash */
+        for (iter = (struct lyd_node *)node->parent; iter; iter = (struct lyd_node *)iter->parent) {
+            if (iter->schema->flags & LYS_KEYLESS) {
+                lyd_hash(iter);
+            }
+        }
+
+        node->parent = NULL;
+    }
+
+    node->next = NULL;
+    node->prev = node;
+}
+
 LY_ERR
 lyd_create_attr(struct lyd_node *parent, struct lyd_attr **attr, const struct lys_module *mod, const char *name,
                 size_t name_len, const char *value, size_t value_len, int *dynamic, ly_clb_resolve_prefix get_prefix,
@@ -1056,14 +1191,14 @@
 }
 
 API const struct lyd_node_term *
-lyd_target(struct lyd_value_path *path, const struct lyd_node **trees)
+lyd_target(struct lyd_value_path *path, const struct lyd_node *tree)
 {
-    unsigned int u, v, x;
+    unsigned int u, x;
     const struct lyd_node *parent = NULL, *start_search;
     struct lyd_node *node = NULL;
     uint64_t pos = 1;
 
-    LY_CHECK_ARG_RET(NULL, path, trees, NULL);
+    LY_CHECK_ARG_RET(NULL, path, tree, NULL);
 
     LY_ARRAY_FOR(path, u) {
         if (parent) {
@@ -1071,15 +1206,10 @@
 search_inner:
             lyd_find_sibling_next(start_search, path[u].node->module, path[u].node->name, 0, NULL, 0, &node);
         } else {
-            LY_ARRAY_FOR(trees, v) {
-                start_search = trees[v];
+            start_search = tree;
 search_toplevel:
-                /* WARNING! to use search_toplevel label correctly, variable v must be preserved and not changed! */
-                lyd_find_sibling_next(start_search, path[u].node->module, path[u].node->name, 0, NULL, 0, &node);
-                if (node) {
-                    break;
-                }
-            }
+            /* WARNING! to use search_toplevel label correctly, variable v must be preserved and not changed! */
+            lyd_find_sibling_next(start_search, path[u].node->module, path[u].node->name, 0, NULL, 0, &node);
         }
         if (!node) {
             return NULL;
@@ -1498,7 +1628,7 @@
     if (top) {
         lyd_free_tree(top);
     } else {
-        lyd_free_withsiblings(first);
+        lyd_free_siblings(first);
     }
     return NULL;
 }
@@ -1864,7 +1994,7 @@
     struct lyd_node **match_p;
     struct lyd_node_inner *parent;
 
-    LY_CHECK_ARG_RET(NULL, target, match, LY_EINVAL);
+    LY_CHECK_ARG_RET(NULL, target, LY_EINVAL);
 
     if (!siblings) {
         /* no data */
@@ -2101,6 +2231,10 @@
         return LY_ENOTFOUND;
     }
 
+    if (key_or_value && !val_len) {
+        val_len = strlen(key_or_value);
+    }
+
     /* create data node if needed and find it */
     switch (schema->nodetype) {
     case LYS_CONTAINER:
diff --git a/src/tree_data.h b/src/tree_data.h
index 0bb4e8b..4943b49 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -309,7 +309,7 @@
 };
 
 /**
- * @brief Data node structure for the terminal data tree nodes - leafs and leaf-lists.
+ * @brief Data node structure for the terminal data tree nodes - leaves and leaf-lists.
  */
 struct lyd_node_term {
     uint32_t hash;                   /**< hash of this particular node (module name + schema name + key string values if list or
@@ -517,10 +517,21 @@
 struct lyd_node *lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options);
 
 /**
+ * @brief Fully validate a data tree.
+ *
+ * @param[in] ctx libyang context. Can be NULL if @p node is set.
+ * @param[in,out] node Root data tree node to recursively validate. May be changed by validation.
+ * @param[in] val_opts Validation options (@ref datavalidationoptions).
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR error on error.
+ */
+LY_ERR lyd_validate(const struct ly_ctx *ctx, struct lyd_node **node, int val_opts);
+
+/**
  * @brief Create a new inner node in a data tree.
  *
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
- * @param[in] module Module with the node being created.
+ * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
  * @param[in] name Schema node name of the new data node. The node can be #LYS_CONTAINER, #LYS_NOTIF, #LYS_RPC, or #LYS_ACTION.
  * @return New created node.
  * @return NULL on error.
@@ -531,7 +542,7 @@
  * @brief Create a new list node in a data tree.
  *
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
- * @param[in] module Module with the node being created.
+ * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
  * @param[in] name Schema node name of the new data node. The node must be #LYS_LIST.
  * @param[in] ... Ordered key values of the new list instance, all must be set. In case of an instance-identifier
  * or identityref value, the JSON format is expected (module names instead of prefixes).
@@ -544,7 +555,7 @@
  * @brief Create a new list node in a data tree.
  *
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
- * @param[in] module Module with the node being created.
+ * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
  * @param[in] name Schema node name of the new data node. The node must be #LYS_LIST.
  * @param[in] keys All key values predicate in the form of "[key1='val1'][key2='val2']...", they do not have to be ordered.
  * In case of an instance-identifier or identityref value, the JSON format is expected (module names instead of prefixes).
@@ -557,7 +568,7 @@
  * @brief Create a new term node in a data tree.
  *
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
- * @param[in] module Module with the node being created.
+ * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
  * @param[in] name Schema node name of the new data node. The node can be #LYS_LEAF or #LYS_LEAFLIST.
  * @param[in] val_str String form of the value of the node being created. In case of an instance-identifier or identityref
  * value, the JSON format is expected (module names instead of prefixes).
@@ -570,7 +581,7 @@
  * @brief Create a new any node in a data tree.
  *
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
- * @param[in] module Module with the node being created.
+ * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
  * @param[in] name Schema node name of the new data node. The node can be #LYS_ANYDATA or #LYS_ANYXML.
  * @param[in] value Value to be directly assigned to the node. Expected type is determined by @p value_type.
  * @param[in] value_type Type of the provided value in @p value.
@@ -581,6 +592,52 @@
                              const void *value, LYD_ANYDATA_VALUETYPE value_type);
 
 /**
+ * @brief Insert a child into a parent. It is inserted as the last child.
+ *
+ * - if the node is part of some other tree, it is automatically unlinked.
+ * - if the node is the first node of a node list (with no parent), all the subsequent nodes are also inserted.
+ *
+ * @param[in] parent Parent node to insert into.
+ * @param[in] node Node to insert.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR error on error.
+ */
+LY_ERR lyd_insert(struct lyd_node *parent, struct lyd_node *node);
+
+/**
+ * @brief Insert a node before another node that is its schema sibling.
+ *
+ * - if the node is part of some other tree, it is automatically unlinked.
+ * - if the node is the first node of a node list (with no parent), all the subsequent nodes are also inserted.
+ *
+ * @param[in] sibling Sibling node to insert before.
+ * @param[in] node Node to insert.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR error on error.
+ */
+LY_ERR lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node);
+
+/**
+ * @brief Insert a node after another node that is its schema sibling.
+ *
+ * - if the node is part of some other tree, it is automatically unlinked.
+ * - if the node is the first node of a node list (with no parent), all the subsequent nodes are also inserted.
+ *
+ * @param[in] sibling Sibling node to insert after.
+ * @param[in] node Node to insert.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR error on error.
+ */
+LY_ERR lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node);
+
+/**
+ * @brief Unlink the specified data subtree.
+ *
+ * @param[in] node Data tree node to be unlinked (together with all the children).
+ */
+void lyd_unlink_tree(struct lyd_node *node);
+
+/**
  * @brief Free all the nodes (even parents of the node) in the data tree.
  *
  * @param[in] node Any of the nodes inside the tree.
@@ -592,33 +649,16 @@
  *
  * @param[in] node Any of the sibling nodes to free.
  */
-void lyd_free_withsiblings(struct lyd_node *node);
+void lyd_free_siblings(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.
@@ -629,33 +669,6 @@
 void lyd_free_attr(struct ly_ctx *ctx, struct lyd_attr *attr, int recursive);
 
 /**
- * @brief Prepare ([sized array](@ref sizedarrays)) of data trees required by various (mostly validation) functions.
- *
- * @param[in] count Number of trees to include (including the mandatory @p tree).
- * @param[in] tree First (and mandatory) tree to be included into the resulting ([sized array](@ref sizedarrays)).
- * @return NULL in case of memory allocation failure or invalid argument, prepared ([sized array](@ref sizedarrays)) otherwise.
- */
-const struct lyd_node **lyd_trees_new(size_t count, const struct lyd_node *tree, ...);
-
-/**
- * @brief Add tree into the ([sized array](@ref sizedarrays)) of data trees created by lyd_trees_new(),
- *
- * @param[in] trees Existing [sized array](@ref sizedarrays)) of data trees to be extended.
- * @param[in] tree Data tree to be included into the provided @p trees ([sized array](@ref sizedarrays)).
- * @return NULL in case of memory allocation failure or invalid argument, extended @p trees ([sized array](@ref sizedarrays)) otherwise.
- */
-const struct lyd_node **lyd_trees_add(const struct lyd_node **trees, const struct lyd_node *tree);
-
-/**
- * @brief Free the trees ([sized array](@ref sizedarrays)).
- *
- * @param[in] trees ([Sized array](@ref sizedarrays)) of data trees.
- * @param[in] free_data Flag to free also the particular trees in the @p trees ([sized array](@ref sizedarrays)).
- * If set to zero, only the trees envelope is freed and data are untouched.
- */
-void lyd_trees_free(const struct lyd_node **trees, int free_data);
-
-/**
  * @brief Check type restrictions applicable to the particular leaf/leaf-list with the given string @p value.
  *
  * The given node is not modified in any way - it is just checked if the @p value can be set to the node.
@@ -670,15 +683,15 @@
  * @param[in] get_prefix Callback function to resolve prefixes used in the @p value string.
  * @param[in] get_prefix_data Private data for the @p get_prefix callback.
  * @param[in] format Input format of the data.
- * @param[in] trees ([Sized array](@ref sizedarrays)) of data trees (e.g. when validating RPC/Notification) where the required
- *            data instance (leafref target, instance-identifier) can be placed. NULL in case the data tree are not yet complete,
- *            then LY_EINCOMPLETE can be returned. To simply prepare this structure, use lyd_trees_new().
+ * @param[in] tree Data tree (e.g. when validating RPC/Notification) where the required data instance (leafref target,
+ *            instance-identifier) can be placed. NULL in case the data tree is not yet complete,
+ *            then LY_EINCOMPLETE can be returned.
  * @return LY_SUCCESS on success
  * @return LY_EINCOMPLETE in case the @p trees is not provided and it was needed to finish the validation (e.g. due to require-instance).
  * @return LY_ERR value if an error occurred.
  */
 LY_ERR lyd_value_validate(struct ly_ctx *ctx, const struct lyd_node_term *node, const char *value, size_t value_len,
-                          ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node **trees);
+                          ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node *tree);
 
 /**
  * @brief Compare the node's value with the given string value. The string value is first validated according to the node's type.
@@ -690,17 +703,16 @@
  * @param[in] get_prefix Callback function to resolve prefixes used in the @p value string.
  * @param[in] get_prefix_data Private data for the @p get_prefix callback.
  * @param[in] format Input format of the data.
- * @param[in] trees ([Sized array](@ref sizedarrays)) of data trees (e.g. when validating RPC/Notification) where the required
- *            data instance (leafref target, instance-identifier) can be placed. NULL in case the data tree are not yet complete,
- *            then LY_EINCOMPLETE can be returned in case the validation was not completed, but values matches. To simply prepare
- *            this structure, use lyd_trees_new(). To simply prepare this structure, use lyd_trees_new().
+ * @param[in] tree Data tree (e.g. when validating RPC/Notification) where the required data instance (leafref target,
+ *            instance-identifier) can be placed. NULL in case the data tree is not yet complete,
+ *            then LY_EINCOMPLETE can be returned.
  * @return LY_SUCCESS on success
  * @return LY_EINCOMPLETE in case of success when the @p trees is not provided and it was needed to finish the validation of
  * the given string @p value (e.g. due to require-instance).
  * @return LY_ERR value if an error occurred.
  */
 LY_ERR lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len,
-                         ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node **trees);
+                         ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node *tree);
 
 /**
  * @defgroup datacompareoptions Data compare options
@@ -773,11 +785,10 @@
  * @brief Resolve instance-identifier defined by lyd_value_path structure.
  *
  * @param[in] path Path structure specifying the instance-identifier target.
- * @param[in] trees ([Sized array](@ref sizedarrays)) of data trees to be searched.
- *            To simply prepare this structure, use lyd_trees_new().
- * @return Target node of the instance-identifier present in the given data @p trees.
+ * @param[in] tree Data tree to be searched.
+ * @return Target node of the instance-identifier present in the given data @p tree.
  */
-const struct lyd_node_term *lyd_target(struct lyd_value_path *path, const struct lyd_node **trees);
+const struct lyd_node_term *lyd_target(struct lyd_value_path *path, const struct lyd_node *tree);
 
 /**
  * @brief Get string value of a term data \p node.
@@ -824,7 +835,7 @@
  * @param[in] first Starting sibling node for search, only succeeding ones are searched.
  * @param[in] module Module of the node to find.
  * @param[in] name Name of the node to find.
- * @param[in] name_len Optional length of the @p name argument in case it is not NULL-terminated string.
+ * @param[in] name_len Optional length of @p name in case it is not 0-terminated string.
  * @param[in] key_or_value Expected value depends on the type of @p name node:
  *              LYS_CONTAINER:
  *              LYS_ANYXML:
@@ -843,7 +854,7 @@
  *              Note that any explicit values (leaf, leaf-list or list key values) will be canonized first
  *              before comparison. But values that do not have a canonical value are expected to be in the
  *              JSON format!
- * @param[in] val_len Optional length of the @p key_or_value argument in case it is not NULL-terminated string.
+ * @param[in] val_len Optional length of @p key_or_value in case it is not 0-terminated string.
  * @param[out] match Found data node.
  * @return LY_SUCCESS on success, @p match set.
  * @return LY_ENOTFOUND if not found, @p match set to NULL.
@@ -903,6 +914,7 @@
  *              Note that any explicit values (leaf-list or list key values) will be canonized first
  *              before comparison. But values that do not have a canonical value are expected to be in the
  *              JSON format!
+ * @param[in] val_len Optional length of @p key_or_value in case it is not 0-terminated.
  * @param[out] match Can be NULL, otherwise the found data node.
  * @return LY_SUCCESS on success, @p match set.
  * @return LY_ENOTFOUND if not found, @p match set to NULL.
diff --git a/src/tree_data_free.c b/src/tree_data_free.c
index 9ff54c4..aea9f7b 100644
--- a/src/tree_data_free.c
+++ b/src/tree_data_free.c
@@ -42,54 +42,6 @@
     LY_ARRAY_FREE(path);
 }
 
-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;
-}
-
 API void
 lyd_free_attr(struct ly_ctx *ctx, struct lyd_attr *attr, int recursive)
 {
@@ -222,7 +174,7 @@
 }
 
 API void
-lyd_free_withsiblings(struct lyd_node *node)
+lyd_free_siblings(struct lyd_node *node)
 {
     lyd_free_(node, 0);
 }
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index 7cd5d34..4da2d49 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -34,7 +34,7 @@
  *
  * @param[in] schema Schema node of the new data node.
  * @param[in] value String value to be parsed.
- * @param[in] value_len Length of @p value.
+ * @param[in] value_len Length of @p value, must be set correctly.
  * @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
  * @param[in] get_prefix Parser-specific getter to resolve prefixes used in the @p value string.
  * @param[in] prefix_data User data for @p get_prefix.
@@ -82,7 +82,7 @@
  * @param[in] schema Schema node of the new data node.
  * @param[in] keys_str List instance key values in the form of "[key1='val1'][key2='val2']...".
  *            The keys do not have to be ordered but all of them must be set.
- * @param[in] keys_len Length of @p keys_str.
+ * @param[in] keys_len Length of @p keys_str, must be set correctly.
  * @param[out] node Created node.
  * @return LY_SUCCESS on success.
  * @return LY_ERR value if an error occurred.
@@ -132,9 +132,9 @@
  * @param[in,out] attr Attribute list to add at its end if @p parent is NULL, returned created attribute.
  * @param[in] mod Attribute module (with the annotation definition).
  * @param[in] name Attribute name.
- * @param[in] name_len Length of @p name.
+ * @param[in] name_len Length of @p name, must be set correctly.
  * @param[in] value String value to be parsed.
- * @param[in] value_len Length of @p value.
+ * @param[in] value_len Length of @p value, must be set correctly.
  * @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
  * @param[in] get_prefix Parser-specific getter to resolve prefixes used in the @p value string.
  * @param[in] prefix_data User data for @p get_prefix.
@@ -153,13 +153,13 @@
  *
  * @param[in] node Data node for the @p value.
  * @param[in] value String value to be parsed, must not be NULL.
- * @param[in] value_len Length of the give @p value (mandatory).
+ * @param[in] value_len Length of the give @p value, must be set correctly.
  * @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
  * @param[in] second Flag for the second call after returning LY_EINCOMPLETE
  * @param[in] get_prefix Parser-specific getter to resolve prefixes used in the @p value string.
  * @param[in] parser Parser's data for @p get_prefix
  * @param[in] format Input format of @p value.
- * @param[in] trees ([Sized array](@ref sizedarrays)) of data trees (e.g. when validating RPC/Notification) where the required
+ * @param[in] tree Data tree (e.g. when validating RPC/Notification) where the required
  *            data instance (leafref target, instance-identifier) can be placed. NULL in case the data tree are not yet complete,
  *            then LY_EINCOMPLETE can be returned.
  * @return LY_SUCCESS on success
@@ -167,7 +167,7 @@
  * @return LY_ERR value if an error occurred.
  */
 LY_ERR lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int *dynamic, int second,
-                       ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node **trees);
+                       ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node *tree);
 
 /**
  * @brief Validate, canonize and store the given @p value into the attribute according to the metadata annotation type's rules.
@@ -175,14 +175,14 @@
  * @param[in] ctx libyang context.
  * @param[in] attr Data attribute for the @p value.
  * @param[in] value String value to be parsed, must not be NULL.
- * @param[in] value_len Length of the give @p value (mandatory).
+ * @param[in] value_len Length of the give @p value, must be set correctly.
  * @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
  * @param[in] second Flag for the second call after returning LY_EINCOMPLETE
  * @param[in] get_prefix Parser-specific getter to resolve prefixes used in the @p value string.
  * @param[in] parser Parser's data for @p get_prefix
  * @param[in] format Input format of the data.
  * @param[in] ctx_snode Context node for value resolution in schema.
- * @param[in] trees ([Sized array](@ref sizedarrays)) of data trees (e.g. when validating RPC/Notification) where the required
+ * @param[in] tree Data tree (e.g. when validating RPC/Notification) where the required
  *            data instance (leafref target, instance-identifier) can be placed. NULL in case the data tree are not yet complete,
  *            then LY_EINCOMPLETE can be returned.
  * @return LY_SUCCESS on success
@@ -191,7 +191,7 @@
  */
 LY_ERR lyd_value_parse_attr(struct ly_ctx *ctx, struct lyd_attr *attr, const char *value, size_t value_len, int *dynamic,
                             int second, ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
-                            const struct lysc_node *ctx_snode, const struct lyd_node **trees);
+                            const struct lysc_node *ctx_snode, const struct lyd_node *tree);
 
 /**
  * @brief Parse XML string as YANG data tree.
diff --git a/src/validation.c b/src/validation.c
index 97f02d6..96246cd 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -20,16 +20,67 @@
 #include "tree_data_internal.h"
 #include "tree_schema_internal.h"
 
+static struct lyd_node *
+lys_getnext_data(const struct lyd_node *last, const struct lyd_node *sibling, const struct lysc_node **slast,
+                 const struct lysc_node *parent, const struct lysc_module *module)
+{
+    const struct lysc_node *siter = NULL;
+    struct lyd_node *match = NULL;
+
+    assert(parent || module);
+    assert(!last || (slast && *slast));
+
+    if (slast) {
+        siter = *slast;
+    }
+
+    if (last && last->next) {
+        /* find next data instance */
+        lyd_find_sibling_next2(last->next, siter, NULL, 0, &match);
+        if (match) {
+            return match;
+        }
+    }
+
+    /* find next schema node data instance */
+    while ((siter = lys_getnext(siter, parent, module, 0))) {
+        switch (siter->nodetype) {
+        case LYS_CONTAINER:
+        case LYS_ANYXML:
+        case LYS_ANYDATA:
+        case LYS_LEAF:
+            lyd_find_sibling_val(sibling, siter, NULL, 0, &match);
+            break;
+        case LYS_LIST:
+        case LYS_LEAFLIST:
+            lyd_find_sibling_next2(sibling, siter, NULL, 0, &match);
+            break;
+        default:
+            assert(0);
+            LOGINT(NULL);
+        }
+
+        if (match) {
+            break;
+        }
+    }
+
+    if (slast) {
+        *slast = siter;
+    }
+    return match;
+}
+
 /**
  * @brief Evaluate a single "when" condition.
  *
  * @param[in] when When to evaluate.
  * @param[in] node Node whose existence depends on this when.
- * @param[in] trees Array of all data trees.
+ * @param[in] tree Data tree.
  * @return LY_ERR value (LY_EINCOMPLETE if a referenced node does not have its when evaluated)
  */
 static LY_ERR
-lyd_val_when(struct lysc_when *when, struct lyd_node *node, const struct lyd_node **trees)
+lyd_val_when(struct lysc_when *when, struct lyd_node *node, const struct lyd_node *tree)
 {
     LY_ERR ret;
     const struct lyd_node *ctx_node;
@@ -46,7 +97,7 @@
 
     /* evaluate when */
     ret = lyxp_eval(when->cond, LYD_UNKNOWN, when->module, ctx_node, ctx_node ? LYXP_NODE_ELEM : LYXP_NODE_ROOT_CONFIG,
-                    trees, &xp_set, LYXP_SCHEMA);
+                    tree, &xp_set, LYXP_SCHEMA);
     lyxp_set_cast(&xp_set, LYXP_SET_BOOLEAN);
 
     /* return error or LY_EINCOMPLETE for dependant unresolved when */
@@ -72,7 +123,7 @@
 
 LY_ERR
 lyd_validate_unres(struct ly_set *node_types, struct ly_set *attr_types, struct ly_set *node_when, LYD_FORMAT format,
-                   ly_clb_resolve_prefix get_prefix_clb, void *parser_data, const struct lyd_node **trees)
+                   ly_clb_resolve_prefix get_prefix_clb, void *parser_data, const struct lyd_node *tree)
 {
     LY_ERR ret = LY_SUCCESS;
     uint32_t u;
@@ -83,7 +134,7 @@
 
         /* validate and store the value of the node */
         ret = lyd_value_parse(node, node->value.original, strlen(node->value.original), 0, 1, get_prefix_clb,
-                            parser_data, format, trees);
+                            parser_data, format, tree);
         LY_CHECK_RET(ret);
     }
 
@@ -93,7 +144,7 @@
 
         /* validate and store the value of the node */
         ret = lyd_value_parse_attr(attr->parent->schema->module->ctx, attr, attr->value.original,
-                                   strlen(attr->value.original), 0, 1, get_prefix_clb, parser_data, format, NULL, trees);
+                                   strlen(attr->value.original), 0, 1, get_prefix_clb, parser_data, format, NULL, tree);
         LY_CHECK_RET(ret);
     }
 
@@ -116,7 +167,7 @@
             do {
                 uint32_t i;
                 LY_ARRAY_FOR(schema->when, i) {
-                    ret = lyd_val_when(schema->when[i], node, trees);
+                    ret = lyd_val_when(schema->when[i], node, tree);
                     if (ret) {
                         break;
                     }
@@ -160,47 +211,12 @@
     return ly_ctx_get_module_iter(ctx, i);
 }
 
-static int
-lyd_val_has_choice_data(const struct lysc_node *snode, struct lyd_node *sibling)
-{
-    const struct lysc_node *iter = NULL;
-
-    assert(snode->nodetype == LYS_CHOICE);
-
-    while ((iter = lys_getnext(iter, snode, NULL, 0))) {
-        switch (iter->nodetype) {
-        case LYS_CONTAINER:
-        case LYS_ANYXML:
-        case LYS_ANYDATA:
-        case LYS_LEAF:
-            if (!lyd_find_sibling_val(sibling, iter, NULL, 0, NULL)) {
-                /* one case child data instance found */
-                return 1;
-            }
-            break;
-        case LYS_LIST:
-        case LYS_LEAFLIST:
-            if (!lyd_find_sibling_next2(sibling, iter, NULL, 0, NULL)) {
-                /* one case child data instance found */
-                return 1;
-            }
-            break;
-        default:
-            assert(0);
-            LOGINT(snode->module->ctx);
-            return 0;
-        }
-    }
-
-    return 0;
-}
-
 static LY_ERR
 lyd_validate_mandatory(const struct lysc_node *snode, struct lyd_node *sibling)
 {
     if (snode->nodetype == LYS_CHOICE) {
         /* some data of a choice case exist */
-        if (lyd_val_has_choice_data(snode, sibling)) {
+        if (lys_getnext_data(NULL, sibling, NULL, snode, NULL)) {
             return LY_SUCCESS;
         }
     } else {
@@ -501,15 +517,70 @@
 }
 
 static LY_ERR
-lyd_validate_cases(const struct lysc_node_case *cases, struct lyd_node *sibling)
+lyd_validate_cases(const struct lysc_node_choice *choic, struct lyd_node **sibling)
 {
-    /* TODO check there are nodes only from a single case,
-     * what if not? validation error or autodelete */
+    const struct lysc_node *scase, *iter, *old_case = NULL, *new_case = NULL;
+    struct lyd_node *match, *to_del;
+    int found;
+
+    LY_LIST_FOR((struct lysc_node *)choic->cases, scase) {
+        found = 0;
+        iter = NULL;
+        match = NULL;
+        while ((match = lys_getnext_data(match, *sibling, &iter, scase, NULL))) {
+            if (match->flags & LYD_NEW) {
+                /* a new case data found, nothing more to look for */
+                found = 2;
+                break;
+            } else {
+                /* and old case data found */
+                if (found == 0) {
+                    found = 1;
+                }
+            }
+        }
+
+        if (found == 1) {
+            /* there cannot be 2 old cases */
+            assert(!old_case);
+
+            /* remember an old existing case */
+            old_case = scase;
+        } else if (found == 2) {
+            if (new_case) {
+                /* new data from 2 cases */
+                LOGVAL(choic->module->ctx, LY_VLOG_LYSC, choic, LY_VCODE_DUPCASE, new_case->name, scase->name);
+                return LY_EVALID;
+            }
+
+            /* remember a new existing case */
+            new_case = scase;
+        }
+    }
+
+    if (old_case && new_case) {
+        /* auto-delete old case */
+        iter = NULL;
+        match = NULL;
+        to_del = NULL;
+        while ((match = lys_getnext_data(match, *sibling, &iter, old_case, NULL))) {
+            if ((*sibling == to_del) && !(*sibling)->parent) {
+                *sibling = (*sibling)->next;
+            }
+            lyd_free_tree(to_del);
+            to_del = match;
+        }
+        if ((*sibling == to_del) && !(*sibling)->parent) {
+            *sibling = (*sibling)->next;
+        }
+        lyd_free_tree(to_del);
+    }
+
     return LY_SUCCESS;
 }
 
 static LY_ERR
-lyd_validate_siblings_schema_r(struct lyd_node *sibling, const struct lysc_node *sparent, const struct lysc_module *mod,
+lyd_validate_siblings_schema_r(struct lyd_node **sibling, const struct lysc_node *sparent, const struct lysc_module *mod,
                                int options)
 {
     const struct lysc_node *snode = NULL;
@@ -521,25 +592,25 @@
         if (snode->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
             slist = (struct lysc_node_list *)snode;
             if (slist->min || slist->max) {
-                LY_CHECK_RET(lyd_validate_minmax(snode, slist->min, slist->max, sibling));
+                LY_CHECK_RET(lyd_validate_minmax(snode, slist->min, slist->max, *sibling));
             }
 
         /* check generic mandatory existence */
         } else if (snode->flags & LYS_MAND_TRUE) {
-            LY_CHECK_RET(lyd_validate_mandatory(snode, sibling));
+            LY_CHECK_RET(lyd_validate_mandatory(snode, *sibling));
         }
 
         /* check unique */
         if (snode->nodetype == LYS_LIST) {
             slist = (struct lysc_node_list *)snode;
             if (slist->uniques) {
-                LY_CHECK_RET(lyd_validate_unique(snode, slist->uniques, sibling));
+                LY_CHECK_RET(lyd_validate_unique(snode, slist->uniques, *sibling));
             }
         }
 
         /* check case duplicites */
         if (snode->nodetype == LYS_CHOICE) {
-            LY_CHECK_RET(lyd_validate_cases(((struct lysc_node_choice *)snode)->cases, sibling));
+            LY_CHECK_RET(lyd_validate_cases((struct lysc_node_choice *)snode, sibling));
         }
 
         if (snode->nodetype & (LYS_CHOICE | LYS_CASE)) {
@@ -552,50 +623,115 @@
 }
 
 static LY_ERR
-lyd_validate_siblings_r(struct lyd_node *sibling, const struct lysc_node *sparent, const struct lysc_module *mod, int options)
+lyd_validate_dup_nodes(struct lyd_node *sibling, struct lyd_node *node)
 {
-    struct lyd_node *node;
+    struct lyd_node **match_p;
+    int fail = 0;
+
+    if ((node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) && (node->schema->flags & LYS_CONFIG_R)) {
+        /* duplicate instances allowed */
+        return LY_SUCCESS;
+    }
+
+    /* find exactly the same next instance using hashes if possible */
+    if (node->parent && node->parent->children_ht) {
+        if (!lyht_find_next(node->parent->children_ht, &node, node->hash, (void **)&match_p)) {
+            fail = 1;
+        }
+    } else {
+        for (; sibling; sibling = sibling->next) {
+            if (sibling == node) {
+                continue;
+            }
+
+            if (node->schema->nodetype & (LYD_NODE_ANY | LYS_LEAF)) {
+                if (sibling->schema == node->schema) {
+                    fail = 1;
+                    break;
+                }
+            } else if (!lyd_compare(sibling, node, 0)) {
+                fail = 1;
+                break;
+            }
+        }
+    }
+
+    if (fail) {
+        LOGVAL(node->schema->module->ctx, LY_VLOG_LYD, node, LY_VCODE_DUP, node->schema->name);
+        return LY_EVALID;
+    }
+    return LY_SUCCESS;
+}
+
+static LY_ERR
+lyd_validate_siblings_r(struct lyd_node **sibling, const struct lysc_node *sparent, const struct lysc_module *mod, int options)
+{
+    struct lyd_node *next, *node, *match;
+
+    assert(sibling);
 
     /* validate all restrictions of nodes themselves */
-    LY_LIST_FOR(sibling, node) {
-        /* TODO node instance duplicities */
+    LY_LIST_FOR_SAFE(*sibling, next, node) {
+        if (node->flags & LYD_NEW) {
+            /* new node instance duplicities */
+            LY_CHECK_RET(lyd_validate_dup_nodes(*sibling, node));
+        } else if (node->flags & LYD_DEFAULT) {
+            /* remove default if there is an explicit instance */
+            assert(node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_CONTAINER));
+            if (node->schema->nodetype == LYS_LEAFLIST) {
+                lyd_find_sibling_next2(*sibling, node->schema, NULL, 0, &match);
+            } else {
+                lyd_find_sibling_val(*sibling, node->schema, NULL, 0, &match);
+            }
+            while (match && (match->flags & LYD_DEFAULT) && !(match->flags & LYD_NEW)) {
+                lyd_find_sibling_next2(match->next, node->schema, NULL, 0, &match);
+            }
+
+            if (match) {
+                /* non-default (or at least new for container) instance found, remove the default one */
+                if ((*sibling == node) && !(*sibling)->parent) {
+                    *sibling = (*sibling)->next;
+                }
+                lyd_free_tree(node);
+                continue;
+            }
+        }
+
         /* TODO node's must */
         /* TODO node status */
         /* TODO node's if-features */
-        /* TODO node list keys */
+        /* TODO list all keys existence */
         /* node value including if-feature is checked by plugins */
     }
 
     /* validate schema-based restrictions */
     LY_CHECK_RET(lyd_validate_siblings_schema_r(sibling, sparent, mod, options));
 
-    LY_LIST_FOR(sibling, node) {
+    LY_LIST_FOR(*sibling, node) {
         /* this sibling is valid */
         node->flags &= ~LYD_NEW;
 
         /* validate all children recursively */
-        LY_CHECK_RET(lyd_validate_siblings_r((struct lyd_node *)lyd_node_children(node), node->schema, mod, options));
+        if (node->schema->nodetype & LYD_NODE_INNER) {
+            LY_CHECK_RET(lyd_validate_siblings_r(lyd_node_children_p(node), node->schema, mod, options));
+        }
     }
 
     return LY_SUCCESS;
 }
 
 LY_ERR
-lyd_validate_data(const struct lyd_node **trees, const struct lys_module **modules, int mod_count, struct ly_ctx *ctx,
+lyd_validate_data(struct lyd_node **tree, const struct lys_module **modules, int mod_count, struct ly_ctx *ctx,
                   int val_opts)
 {
-    uint32_t i = 0, j;
+    uint32_t i = 0;
     const struct lys_module *mod;
-    struct lyd_node *tree;
 
     if (val_opts & LYD_VALOPT_DATA_ONLY) {
-        if (trees) {
-            for (j = 0; j < LY_ARRAY_SIZE(trees); ++j) {
-                tree = (struct lyd_node *)trees[j];
-
-                /* validate all top-level nodes and then inner nodes recursively */
-                LY_CHECK_RET(lyd_validate_siblings_r(tree, NULL, tree->schema->module->compiled, val_opts));
-            }
+        if (*tree) {
+            /* TODO all modules, not just first */
+            /* validate all top-level nodes and then inner nodes recursively */
+            LY_CHECK_RET(lyd_validate_siblings_r(tree, NULL, (*tree)->schema->module->compiled, val_opts));
         }
     } else {
         while ((mod = lyd_val_next_module(modules, mod_count, ctx, &i))) {
@@ -603,17 +739,6 @@
                 continue;
             }
 
-            /* find data of this module, if any */
-            tree = NULL;
-            if (trees) {
-                for (j = 0; j < LY_ARRAY_SIZE(trees); ++j) {
-                    if (trees[j]->schema->module == mod) {
-                        tree = (struct lyd_node *)trees[j];
-                        break;
-                    }
-                }
-            }
-
             /* validate all top-level nodes and then inner nodes recursively */
             LY_CHECK_RET(lyd_validate_siblings_r(tree, NULL, mod->compiled, val_opts));
         }
@@ -636,7 +761,7 @@
     while ((iter = lys_getnext(iter, schema, mod, LYS_GETNEXT_WITHCHOICE))) {
         switch (iter->nodetype) {
         case LYS_CHOICE:
-            if (((struct lysc_node_choice *)iter)->dflt && !lyd_val_has_choice_data(iter, *first)) {
+            if (((struct lysc_node_choice *)iter)->dflt && !lys_getnext_data(NULL, *first, NULL, iter, NULL)) {
                 /* create default case data */
                 LY_CHECK_RET(lyd_validate_defaults_r(parent, first, (struct lysc_node *)((struct lysc_node_choice *)iter)->dflt,
                                                      NULL, node_types, node_when));
@@ -726,3 +851,58 @@
 
     return LY_SUCCESS;
 }
+
+API LY_ERR
+lyd_validate(const struct ly_ctx *ctx, struct lyd_node **tree, int val_opts)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct lyd_node *root, *next, *elem;
+    const struct lyd_attr *attr;
+    struct ly_set type_check = {0}, type_attr_check = {0}, when_check = {0};
+
+    LY_CHECK_ARG_RET(ctx, tree, ctx || *tree, LY_EINVAL);
+
+    if (!ctx) {
+        ctx = (*tree)->schema->module->ctx;
+    }
+
+    /* add nested defaults, collect all types and nodes with when condition */
+    LY_LIST_FOR(*tree, root) {
+        LYD_TREE_DFS_BEGIN(root, next, elem) {
+            LY_LIST_FOR(elem->attr, attr) {
+                ly_set_add(&type_attr_check, (void *)attr, LY_SET_OPT_USEASLIST);
+            }
+            if (elem->schema->nodetype & LYD_NODE_TERM) {
+                ly_set_add(&type_check, (void *)elem, LY_SET_OPT_USEASLIST);
+            } else if (elem->schema->nodetype & LYD_NODE_INNER) {
+                ret = lyd_validate_defaults_r((struct lyd_node_inner *)elem, lyd_node_children_p((struct lyd_node *)elem),
+                                              elem->schema, NULL, &type_check, &when_check);
+                LY_CHECK_GOTO(ret, cleanup);
+            }
+            if (!(elem->schema->nodetype & (LYS_ACTION | LYS_NOTIF)) && elem->schema->when) {
+                ly_set_add(&when_check, (void *)elem, LY_SET_OPT_USEASLIST);
+            }
+
+            LYD_TREE_DFS_END(root, next, elem);
+        }
+    }
+
+    /* add top-level default nodes */
+    ret = lyd_validate_defaults_top(tree, NULL, 0, (struct ly_ctx *)ctx, &type_check, &when_check, val_opts);
+    LY_CHECK_GOTO(ret, cleanup);
+
+    /* finish incompletely validated terminal values/attributes and when conditions */
+    ret = lyd_validate_unres(&type_check, &type_attr_check, &when_check, LYD_JSON, lydjson_resolve_prefix, NULL,
+                             (const struct lyd_node *)tree);
+    LY_CHECK_GOTO(ret, cleanup);
+
+    /* context node and other validation tasks that depend on other data nodes */
+    ret = lyd_validate_data(tree, NULL, 0, (struct ly_ctx *)ctx, val_opts);
+    LY_CHECK_GOTO(ret, cleanup);
+
+cleanup:
+    ly_set_erase(&type_check, NULL);
+    ly_set_erase(&type_attr_check, NULL);
+    ly_set_erase(&when_check, NULL);
+    return ret;
+}
diff --git a/src/validation.h b/src/validation.h
index dfc81d0..d8b62a4 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -27,23 +27,23 @@
  * @param[in] format Format of the unresolved data.
  * @param[in] get_prefix_clb Format-specific getter to resolve prefixes.
  * @param[in] parser_data Parser's data for @p get_prefix_clb.
- * @param[in] trees Array of all data trees.
+ * @param[in] tree Data tree.
  * @return LY_ERR value.
  */
 LY_ERR lyd_validate_unres(struct ly_set *node_types, struct ly_set *attr_types, struct ly_set *node_when, LYD_FORMAT format,
-                          ly_clb_resolve_prefix get_prefix_clb, void *parser_data, const struct lyd_node **trees);
+                          ly_clb_resolve_prefix get_prefix_clb, void *parser_data, const struct lyd_node *tree);
 
 /**
  * @brief Perform all validation tasks, the data tree must be complete when calling this function.
  *
- * @param[in] trees Array of all data trees.
+ * @param[in,out] tree Data tree.
  * @param[in] modules Array of modules that should be validated, NULL for all modules.
  * @param[in] mod_count Modules count.
  * @param[in] ctx Context if all modules should be validated, NULL for only selected modules.
- * @param[in] val_opts Validation options.
+ * @param[in] val_opts Validation options (@ref datavalidationoptions).
  * @return LY_ERR value.
  */
-LY_ERR lyd_validate_data(const struct lyd_node **trees, const struct lys_module **modules, int mod_count,
+LY_ERR lyd_validate_data(struct lyd_node **tree, const struct lys_module **modules, int mod_count,
                          struct ly_ctx *ctx, int val_opts);
 
 /**
diff --git a/src/xpath.c b/src/xpath.c
index c5e3259..9cbc30a 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -751,7 +751,7 @@
         new->ctx_node = set->ctx_node;
         new->root_type = set->root_type;
         new->local_mod = set->local_mod;
-        new->trees = set->trees;
+        new->tree = set->tree;
         new->format = set->format;
     }
 }
@@ -3560,7 +3560,7 @@
                 /* find leafref target */
                 val = lyd_value2str(leaf, &dynamic);
                 node = ly_type_find_leafref(set->ctx, sleaf->type, val, strlen(val), (struct lyd_node *)leaf,
-                                            set->trees, &leaf->value, &errmsg);
+                                            set->tree, &leaf->value, &errmsg);
                 if (dynamic) {
                     free((char *)val);
                 }
@@ -3574,7 +3574,7 @@
                 set_insert_node(set, node, 0, LYXP_NODE_ELEM, 0);
             } else {
                 assert(sleaf->type->basetype == LY_TYPE_INST);
-                node = (struct lyd_node *)lyd_target(leaf->value.target, set->trees);
+                node = (struct lyd_node *)lyd_target(leaf->value.target, set->tree);
                 if (!node) {
                     val = lyd_value2str(leaf, &dynamic);
                     LOGERR(set->ctx, LY_EVALID, "Invalid instance-identifier \"%s\" value - required instance not found.", val);
@@ -3649,7 +3649,7 @@
                 /* store args[1] into ident */
                 rc = sleaf->type->plugin->store(set->ctx, sleaf->type, args[1]->val.str, strlen(args[1]->val.str),
                                                 LY_TYPE_OPTS_STORE, lys_resolve_prefix, (void *)sleaf->dflt_mod, set->format,
-                                                (struct lyd_node *)leaf, set->trees, &data, NULL, &err);
+                                                (struct lyd_node *)leaf, set->tree, &data, NULL, &err);
                 if (err) {
                     ly_err_print(err);
                     ly_err_free(err);
@@ -3732,7 +3732,7 @@
                 /* store args[1] into ident */
                 rc = sleaf->type->plugin->store(set->ctx, sleaf->type, args[1]->val.str, strlen(args[1]->val.str),
                                                 LY_TYPE_OPTS_STORE, lys_resolve_prefix, (void *)sleaf->dflt_mod, set->format,
-                                                (struct lyd_node *)leaf, set->trees, &data, NULL, &err);
+                                                (struct lyd_node *)leaf, set->tree, &data, NULL, &err);
                 if (err) {
                     ly_err_print(err);
                     ly_err_free(err);
@@ -5326,7 +5326,7 @@
 static LY_ERR
 moveto_node(struct lyxp_set *set, const char *qname, uint16_t qname_len)
 {
-    uint32_t i, j;
+    uint32_t i;
     int replaced;
     const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
     const struct lys_module *moveto_mod;
@@ -5354,22 +5354,20 @@
         if ((set->val.nodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.nodes[i].type == LYXP_NODE_ROOT)) {
             assert(!set->val.nodes[i].node);
             /* search in all the trees */
-            LY_ARRAY_FOR(set->trees, j) {
-                for (sub = set->trees[j]; sub; sub = sub->next) {
-                    rc = moveto_node_check(sub, set->root_type, name_dict, moveto_mod);
-                    if (rc == LY_SUCCESS) {
-                        /* pos filled later */
-                        if (!replaced) {
-                            set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
-                            replaced = 1;
-                        } else {
-                            set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
-                        }
-                        ++i;
-                    } else if (rc == LY_EINCOMPLETE) {
-                        lydict_remove(set->ctx, name_dict);
-                        return rc;
+            for (sub = set->tree; sub; sub = sub->next) {
+                rc = moveto_node_check(sub, set->root_type, name_dict, moveto_mod);
+                if (rc == LY_SUCCESS) {
+                    /* pos filled later */
+                    if (!replaced) {
+                        set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
+                        replaced = 1;
+                    } else {
+                        set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
                     }
+                    ++i;
+                } else if (rc == LY_EINCOMPLETE) {
+                    lydict_remove(set->ctx, name_dict);
+                    return rc;
                 }
             }
 
@@ -8025,7 +8023,7 @@
 
 LY_ERR
 lyxp_eval(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lyd_node *ctx_node,
-          enum lyxp_node_type ctx_node_type, const struct lyd_node **trees, struct lyxp_set *set, int options)
+          enum lyxp_node_type ctx_node_type, const struct lyd_node *tree, struct lyxp_set *set, int options)
 {
     uint16_t exp_idx = 0;
     LY_ERR rc;
@@ -8041,7 +8039,7 @@
     set->ctx_node = ctx_node;
     set->root_type = lyxp_get_root_type(ctx_node, NULL, options);
     set->local_mod = local_mod;
-    set->trees = trees;
+    set->tree = tree;
     set->format = format;
 
     /* evaluate */
diff --git a/src/xpath.h b/src/xpath.h
index b2f2eb5..d645920 100644
--- a/src/xpath.h
+++ b/src/xpath.h
@@ -251,7 +251,7 @@
     };
     enum lyxp_node_type root_type;
     const struct lys_module *local_mod;
-    const struct lyd_node **trees;
+    const struct lyd_node *tree;
     LYD_FORMAT format;
 };
 
@@ -268,7 +268,7 @@
  * this case just pass NULL for @p ctx_node and use an enum value for this kind of root (#LYXP_NODE_ROOT_CONFIG if
  * @p ctx_node has config true, otherwise #LYXP_NODE_ROOT). #LYXP_NODE_TEXT and #LYXP_NODE_ATTR can also be used,
  * but there are no use-cases in YANG.
- * @param[in] trees Data trees on which to perform the evaluation, they must include all the available tree (including
+ * @param[in] tree Data tree on which to perform the evaluation, it must include all the available data (including
  * the tree of @p ctx_node).
  * @param[out] set Result set. Must be valid and in the same libyang context as @p ctx_node.
  * To be safe, always either zero or cast the @p set to empty. After done using, either cast
@@ -279,7 +279,7 @@
  * LY_EINCOMPLETE for unresolved when).
  */
 LY_ERR lyxp_eval(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lyd_node *ctx_node,
-                 enum lyxp_node_type ctx_node_type, const struct lyd_node **trees, struct lyxp_set *set, int options);
+                 enum lyxp_node_type ctx_node_type, const struct lyd_node *tree, struct lyxp_set *set, int options);
 
 #define LYXP_SCHEMA 0x01 /**< Apply data node access restrictions defined for 'when' and 'must' evaluation. */
 
diff --git a/tests/features/test_types.c b/tests/features/test_types.c
index a08b3ce..a30e5db 100644
--- a/tests/features/test_types.c
+++ b/tests/features/test_types.c
@@ -785,7 +785,6 @@
     s->func = test_instanceid;
 
     struct lyd_node *tree;
-    const struct lyd_node **trees;
     const struct lyd_node_term *leaf;
     struct lyd_value value = {0};
 
@@ -926,16 +925,14 @@
            "<list2 xmlns=\"urn:tests:types\"><id>a</id><value>b</value></list2>"
            "<a:inst xmlns:a=\"urn:tests:types\">/a:list2[a:id='a'][a:value='b']/a:id</a:inst>";
     assert_non_null(tree = lyd_parse_mem(s->ctx, data, LYD_XML, LYD_VALOPT_DATA_ONLY));
-    tree = tree->prev->prev;
-    assert_int_equal(LYS_LEAF, tree->schema->nodetype);
-    assert_string_equal("inst", tree->schema->name);
-    leaf = (const struct lyd_node_term*)tree;
+    leaf = (const struct lyd_node_term*)tree->prev->prev;
+    assert_int_equal(LYS_LEAF, leaf->schema->nodetype);
+    assert_string_equal("inst", leaf->schema->name);
     assert_null(leaf->value.canonical_cache);
-    trees = lyd_trees_new(1, tree);
-    assert_non_null(leaf = lyd_target(leaf->value.target, trees));
+    assert_non_null(leaf = lyd_target(leaf->value.target, tree));
     assert_string_equal("a", leaf->value.canonical_cache);
     assert_string_equal("b", ((struct lyd_node_term*)leaf->next)->value.canonical_cache);
-    lyd_trees_free(trees, 1);
+    lyd_free_all(tree);
 
     /* invalid value */
     data =  "<t:inst xmlns:t=\"urn:tests:types\">/t:cont/t:1leaftarget</t:inst>";
@@ -1079,31 +1076,30 @@
            "<leaflisttarget xmlns=\"urn:tests:types\">b</leaflisttarget>"
            "<a:inst xmlns:a=\"urn:tests:types\">/a:list2[a:id='a'][a:value='a']/a:id</a:inst>";
     assert_non_null(tree = lyd_parse_mem(s->ctx, data, LYD_XML, LYD_VALOPT_DATA_ONLY));
-    trees = lyd_trees_new(1, tree);
     /* key-predicate */
     data = "/a:list2[a:id='a'][a:value='b']/a:id";
     assert_int_equal(LY_EVALID, lyd_value_validate(s->ctx, (const struct lyd_node_term*)tree->prev->prev, data, strlen(data),
-                                                   test_instanceid_getprefix, tree->schema->module, LYD_XML, trees));
+                                                   test_instanceid_getprefix, tree->schema->module, LYD_XML, tree));
     logbuf_assert("Invalid instance-identifier \"/a:list2[a:id='a'][a:value='b']/a:id\" value - "
                   "key-predicate \"[a:id='a'][a:value='b']\" does not match any \"list2\" instance. /");
     /* leaf-list-predicate */
     data = "/a:leaflisttarget[.='c']";
     assert_int_equal(LY_EVALID, lyd_value_validate(s->ctx, (const struct lyd_node_term*)tree->prev->prev, data, strlen(data),
-                                                   test_instanceid_getprefix, tree->schema->module, LYD_XML, trees));
+                                                   test_instanceid_getprefix, tree->schema->module, LYD_XML, tree));
     logbuf_assert("Invalid instance-identifier \"/a:leaflisttarget[.='c']\" value - "
                   "leaf-list-predicate \"[.='c']\" does not match any \"leaflisttarget\" instance. /");
     /* position predicate */
     data = "/a:list2[4]";
     assert_int_equal(LY_EVALID, lyd_value_validate(s->ctx, (const struct lyd_node_term*)tree->prev->prev, data, strlen(data),
-                                                   test_instanceid_getprefix, tree->schema->module, LYD_XML, trees));
+                                                   test_instanceid_getprefix, tree->schema->module, LYD_XML, tree));
     logbuf_assert("Invalid instance-identifier \"/a:list2[4]\" value - "
                   "position-predicate 4 is bigger than number of instances in the data tree (2). /");
-    lyd_trees_free(trees, 1);
 
     data = "<leaflisttarget xmlns=\"urn:tests:types\">b</leaflisttarget>"
            "<inst xmlns=\"urn:tests:types\">/a:leaflisttarget[1]</inst>";
     assert_null(lyd_parse_mem(s->ctx, data, LYD_XML, LYD_VALOPT_DATA_ONLY));
     logbuf_assert("Invalid instance-identifier \"/a:leaflisttarget[1]\" value - unable to map prefix \"a\" to YANG schema. /");
+    lyd_free_siblings(tree);
 
     s->func = NULL;
 }
@@ -1249,12 +1245,12 @@
      * }
      */
 
-    const char *data = "<int8 xmlns=\"urn:tests:types\">11</int8><int8 xmlns=\"urn:tests:types\">12</int8>"
+    const char *data = "<int8 xmlns=\"urn:tests:types\">12</int8>"
             "<un1 xmlns=\"urn:tests:types\">12</un1>";
 
     /* valid data */
     assert_non_null(tree = lyd_parse_mem(s->ctx, data, LYD_XML, LYD_VALOPT_DATA_ONLY));
-    tree = tree->prev->prev;
+    tree = tree->next;
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("un1", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
@@ -1279,10 +1275,10 @@
     value.realtype->plugin->free(s->ctx, &value);
     lyd_free_all(tree);
 
-    data = "<int8 xmlns=\"urn:tests:types\">11</int8><int8 xmlns=\"urn:tests:types\">12</int8>"
+    data = "<int8 xmlns=\"urn:tests:types\">12</int8>"
            "<un1 xmlns=\"urn:tests:types\">2</un1>";
     assert_non_null(tree = lyd_parse_mem(s->ctx, data, LYD_XML, LYD_VALOPT_DATA_ONLY));
-    tree = tree->prev->prev;
+    tree = tree->next;
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("un1", tree->schema->name);
     leaf = (struct lyd_node_term*)tree;
diff --git a/tests/modules/yang/ietf-netconf-with-defaults@2011-06-01.yang b/tests/modules/yang/ietf-netconf-with-defaults@2011-06-01.yang
new file mode 100644
index 0000000..e19d2b3
--- /dev/null
+++ b/tests/modules/yang/ietf-netconf-with-defaults@2011-06-01.yang
@@ -0,0 +1,140 @@
+module ietf-netconf-with-defaults {
+
+   namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults";
+
+   prefix ncwd;
+
+   import ietf-netconf { prefix nc; }
+
+   organization
+    "IETF NETCONF (Network Configuration Protocol) Working Group";
+
+   contact
+    "WG Web:   <http://tools.ietf.org/wg/netconf/>
+
+     WG List:  <netconf@ietf.org>
+
+     WG Chair: Bert Wijnen
+               <bertietf@bwijnen.net>
+
+     WG Chair: Mehmet Ersue
+               <mehmet.ersue@nsn.com>
+
+     Editor: Andy Bierman
+             <andy.bierman@brocade.com>
+
+     Editor: Balazs Lengyel
+             <balazs.lengyel@ericsson.com>";
+
+   description
+    "This module defines an extension to the NETCONF protocol
+     that allows the NETCONF client to control how default
+     values are handled by the server in particular NETCONF
+     operations.
+
+     Copyright (c) 2011 IETF Trust and the persons identified as
+     the document authors.  All rights reserved.
+
+     Redistribution and use in source and binary forms, with or
+     without modification, is permitted pursuant to, and subject
+     to the license terms contained in, the Simplified BSD License
+     set forth in Section 4.c of the IETF Trust's Legal Provisions
+     Relating to IETF Documents
+     (http://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC 6243; see
+     the RFC itself for full legal notices.";
+
+   revision 2011-06-01 {
+     description
+       "Initial version.";
+     reference
+      "RFC 6243: With-defaults Capability for NETCONF";
+   }
+
+   typedef with-defaults-mode {
+      description
+        "Possible modes to report default data.";
+      reference
+         "RFC 6243; Section 3.";
+      type enumeration {
+         enum report-all {
+             description
+               "All default data is reported.";
+             reference
+               "RFC 6243; Section 3.1";
+         }
+         enum report-all-tagged {
+             description
+               "All default data is reported.
+                Any nodes considered to be default data
+                will contain a 'default' XML attribute,
+                set to 'true' or '1'.";
+             reference
+               "RFC 6243; Section 3.4";
+         }
+         enum trim {
+             description
+               "Values are not reported if they contain the default.";
+             reference
+               "RFC 6243; Section 3.2";
+         }
+         enum explicit {
+             description
+               "Report values that contain the definition of
+                explicitly set data.";
+             reference
+               "RFC 6243; Section 3.3";
+         }
+     }
+   }
+
+   grouping with-defaults-parameters {
+     description
+       "Contains the <with-defaults> parameter for control
+        of defaults in NETCONF retrieval operations.";
+
+     leaf with-defaults {
+       description
+         "The explicit defaults processing mode requested.";
+       reference
+         "RFC 6243; Section 4.5.1";
+
+       type with-defaults-mode;
+     }
+   }
+
+   // extending the get-config operation
+   augment /nc:get-config/nc:input {
+       description
+         "Adds the <with-defaults> parameter to the
+          input of the NETCONF <get-config> operation.";
+       reference
+         "RFC 6243; Section 4.5.1";
+
+       uses with-defaults-parameters;
+   }
+
+   // extending the get operation
+   augment /nc:get/nc:input {
+       description
+         "Adds the <with-defaults> parameter to
+          the input of the NETCONF <get> operation.";
+       reference
+         "RFC 6243; Section 4.5.1";
+
+       uses with-defaults-parameters;
+   }
+
+   // extending the copy-config operation
+   augment /nc:copy-config/nc:input {
+       description
+         "Adds the <with-defaults> parameter to
+          the input of the NETCONF <copy-config> operation.";
+       reference
+         "RFC 6243; Section 4.5.1";
+
+       uses with-defaults-parameters;
+   }
+
+}
diff --git a/tests/modules/yang/ietf-netconf@2011-06-01.yang b/tests/modules/yang/ietf-netconf@2011-06-01.yang
new file mode 100644
index 0000000..6449421
--- /dev/null
+++ b/tests/modules/yang/ietf-netconf@2011-06-01.yang
@@ -0,0 +1,934 @@
+module ietf-netconf {
+
+  // the namespace for NETCONF XML definitions is unchanged
+  // from RFC 4741, which this document replaces
+  namespace "urn:ietf:params:xml:ns:netconf:base:1.0";
+
+  prefix nc;
+
+  import ietf-inet-types {
+    prefix inet;
+  }
+
+  import ietf-netconf-acm { prefix nacm; }
+
+  organization
+    "IETF NETCONF (Network Configuration) Working Group";
+
+  contact
+    "WG Web:   <http://tools.ietf.org/wg/netconf/>
+     WG List:  <netconf@ietf.org>
+
+     WG Chair: Bert Wijnen
+               <bertietf@bwijnen.net>
+
+     WG Chair: Mehmet Ersue
+               <mehmet.ersue@nsn.com>
+
+     Editor:   Martin Bjorklund
+               <mbj@tail-f.com>
+
+     Editor:   Juergen Schoenwaelder
+               <j.schoenwaelder@jacobs-university.de>
+
+     Editor:   Andy Bierman
+               <andy.bierman@brocade.com>";
+  description
+    "NETCONF Protocol Data Types and Protocol Operations.
+
+     Copyright (c) 2011 IETF Trust and the persons identified as
+     the document authors.  All rights reserved.
+
+     Redistribution and use in source and binary forms, with or
+     without modification, is permitted pursuant to, and subject
+     to the license terms contained in, the Simplified BSD License
+     set forth in Section 4.c of the IETF Trust's Legal Provisions
+     Relating to IETF Documents
+     (http://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC 6241; see
+     the RFC itself for full legal notices.";
+
+  revision 2011-06-01 {
+    description
+      "Initial revision;
+       2013-09-29: Updated to include NACM attributes, 
+       as specified in RFC 6536: sec 3.2.5 and 3.2.8";
+    reference
+      "RFC 6241: Network Configuration Protocol";
+  }
+
+  extension get-filter-element-attributes {
+    description
+      "If this extension is present within an 'anyxml'
+       statement named 'filter', which must be conceptually
+       defined within the RPC input section for the <get>
+       and <get-config> protocol operations, then the
+       following unqualified XML attribute is supported
+       within the <filter> element, within a <get> or
+       <get-config> protocol operation:
+
+         type : optional attribute with allowed
+                value strings 'subtree' and 'xpath'.
+                If missing, the default value is 'subtree'.
+
+       If the 'xpath' feature is supported, then the
+       following unqualified XML attribute is
+       also supported:
+
+         select: optional attribute containing a
+                 string representing an XPath expression.
+                 The 'type' attribute must be equal to 'xpath'
+                 if this attribute is present.";
+  }
+
+  // NETCONF capabilities defined as features
+  feature writable-running {
+    description
+      "NETCONF :writable-running capability;
+       If the server advertises the :writable-running
+       capability for a session, then this feature must
+       also be enabled for that session.  Otherwise,
+       this feature must not be enabled.";
+    reference "RFC 6241, Section 8.2";
+  }
+
+  feature candidate {
+    description
+      "NETCONF :candidate capability;
+       If the server advertises the :candidate
+       capability for a session, then this feature must
+       also be enabled for that session.  Otherwise,
+       this feature must not be enabled.";
+    reference "RFC 6241, Section 8.3";
+  }
+
+  feature confirmed-commit {
+    if-feature candidate;
+    description
+      "NETCONF :confirmed-commit:1.1 capability;
+       If the server advertises the :confirmed-commit:1.1
+       capability for a session, then this feature must
+       also be enabled for that session.  Otherwise,
+       this feature must not be enabled.";
+
+    reference "RFC 6241, Section 8.4";
+  }
+
+  feature rollback-on-error {
+    description
+      "NETCONF :rollback-on-error capability;
+       If the server advertises the :rollback-on-error
+       capability for a session, then this feature must
+       also be enabled for that session.  Otherwise,
+       this feature must not be enabled.";
+    reference "RFC 6241, Section 8.5";
+  }
+
+  feature validate {
+    description
+      "NETCONF :validate:1.1 capability;
+       If the server advertises the :validate:1.1
+       capability for a session, then this feature must
+       also be enabled for that session.  Otherwise,
+       this feature must not be enabled.";
+    reference "RFC 6241, Section 8.6";
+  }
+
+  feature startup {
+    description
+      "NETCONF :startup capability;
+       If the server advertises the :startup
+       capability for a session, then this feature must
+       also be enabled for that session.  Otherwise,
+       this feature must not be enabled.";
+    reference "RFC 6241, Section 8.7";
+  }
+
+  feature url {
+    description
+      "NETCONF :url capability;
+       If the server advertises the :url
+       capability for a session, then this feature must
+       also be enabled for that session.  Otherwise,
+       this feature must not be enabled.";
+    reference "RFC 6241, Section 8.8";
+  }
+
+  feature xpath {
+    description
+      "NETCONF :xpath capability;
+       If the server advertises the :xpath
+       capability for a session, then this feature must
+       also be enabled for that session.  Otherwise,
+       this feature must not be enabled.";
+    reference "RFC 6241, Section 8.9";
+  }
+
+  // NETCONF Simple Types
+
+  typedef session-id-type {
+    type uint32 {
+      range "1..max";
+    }
+    description
+      "NETCONF Session Id";
+  }
+
+  typedef session-id-or-zero-type {
+    type uint32;
+    description
+      "NETCONF Session Id or Zero to indicate none";
+  }
+  typedef error-tag-type {
+    type enumeration {
+       enum in-use {
+         description
+           "The request requires a resource that
+            already is in use.";
+       }
+       enum invalid-value {
+         description
+           "The request specifies an unacceptable value for one
+            or more parameters.";
+       }
+       enum too-big {
+         description
+           "The request or response (that would be generated) is
+            too large for the implementation to handle.";
+       }
+       enum missing-attribute {
+         description
+           "An expected attribute is missing.";
+       }
+       enum bad-attribute {
+         description
+           "An attribute value is not correct; e.g., wrong type,
+            out of range, pattern mismatch.";
+       }
+       enum unknown-attribute {
+         description
+           "An unexpected attribute is present.";
+       }
+       enum missing-element {
+         description
+           "An expected element is missing.";
+       }
+       enum bad-element {
+         description
+           "An element value is not correct; e.g., wrong type,
+            out of range, pattern mismatch.";
+       }
+       enum unknown-element {
+         description
+           "An unexpected element is present.";
+       }
+       enum unknown-namespace {
+         description
+           "An unexpected namespace is present.";
+       }
+       enum access-denied {
+         description
+           "Access to the requested protocol operation or
+            data model is denied because authorization failed.";
+       }
+       enum lock-denied {
+         description
+           "Access to the requested lock is denied because the
+            lock is currently held by another entity.";
+       }
+       enum resource-denied {
+         description
+           "Request could not be completed because of
+            insufficient resources.";
+       }
+       enum rollback-failed {
+         description
+           "Request to roll back some configuration change (via
+            rollback-on-error or <discard-changes> operations)
+            was not completed for some reason.";
+
+       }
+       enum data-exists {
+         description
+           "Request could not be completed because the relevant
+            data model content already exists.  For example,
+            a 'create' operation was attempted on data that
+            already exists.";
+       }
+       enum data-missing {
+         description
+           "Request could not be completed because the relevant
+            data model content does not exist.  For example,
+            a 'delete' operation was attempted on
+            data that does not exist.";
+       }
+       enum operation-not-supported {
+         description
+           "Request could not be completed because the requested
+            operation is not supported by this implementation.";
+       }
+       enum operation-failed {
+         description
+           "Request could not be completed because the requested
+            operation failed for some reason not covered by
+            any other error condition.";
+       }
+       enum partial-operation {
+         description
+           "This error-tag is obsolete, and SHOULD NOT be sent
+            by servers conforming to this document.";
+       }
+       enum malformed-message {
+         description
+           "A message could not be handled because it failed to
+            be parsed correctly.  For example, the message is not
+            well-formed XML or it uses an invalid character set.";
+       }
+     }
+     description "NETCONF Error Tag";
+     reference "RFC 6241, Appendix A";
+  }
+
+  typedef error-severity-type {
+    type enumeration {
+      enum error {
+        description "Error severity";
+      }
+      enum warning {
+        description "Warning severity";
+      }
+    }
+    description "NETCONF Error Severity";
+    reference "RFC 6241, Section 4.3";
+  }
+
+  typedef edit-operation-type {
+    type enumeration {
+      enum merge {
+        description
+          "The configuration data identified by the
+           element containing this attribute is merged
+           with the configuration at the corresponding
+           level in the configuration datastore identified
+           by the target parameter.";
+      }
+      enum replace {
+        description
+          "The configuration data identified by the element
+           containing this attribute replaces any related
+           configuration in the configuration datastore
+           identified by the target parameter.  If no such
+           configuration data exists in the configuration
+           datastore, it is created.  Unlike a
+           <copy-config> operation, which replaces the
+           entire target configuration, only the configuration
+           actually present in the config parameter is affected.";
+      }
+      enum create {
+        description
+          "The configuration data identified by the element
+           containing this attribute is added to the
+           configuration if and only if the configuration
+           data does not already exist in the configuration
+           datastore.  If the configuration data exists, an
+           <rpc-error> element is returned with an
+           <error-tag> value of 'data-exists'.";
+      }
+      enum delete {
+        description
+          "The configuration data identified by the element
+           containing this attribute is deleted from the
+           configuration if and only if the configuration
+           data currently exists in the configuration
+           datastore.  If the configuration data does not
+           exist, an <rpc-error> element is returned with
+           an <error-tag> value of 'data-missing'.";
+      }
+      enum remove {
+        description
+          "The configuration data identified by the element
+           containing this attribute is deleted from the
+           configuration if the configuration
+           data currently exists in the configuration
+           datastore.  If the configuration data does not
+           exist, the 'remove' operation is silently ignored
+           by the server.";
+      }
+    }
+    default "merge";
+    description "NETCONF 'operation' attribute values";
+    reference "RFC 6241, Section 7.2";
+  }
+
+  // NETCONF Standard Protocol Operations
+
+  rpc get-config {
+    description
+      "Retrieve all or part of a specified configuration.";
+
+    reference "RFC 6241, Section 7.1";
+
+    input {
+      container source {
+        description
+          "Particular configuration to retrieve.";
+
+        choice config-source {
+          mandatory true;
+          description
+            "The configuration to retrieve.";
+          leaf candidate {
+            if-feature candidate;
+            type empty;
+            description
+              "The candidate configuration is the config source.";
+          }
+          leaf running {
+            type empty;
+            description
+              "The running configuration is the config source.";
+          }
+          leaf startup {
+            if-feature startup;
+            type empty;
+            description
+              "The startup configuration is the config source.
+               This is optional-to-implement on the server because
+               not all servers will support filtering for this
+               datastore.";
+          }
+        }
+      }
+
+      anyxml filter {
+        description
+          "Subtree or XPath filter to use.";
+        nc:get-filter-element-attributes;
+      }
+    }
+
+    output {
+      anyxml data {
+        description
+          "Copy of the source datastore subset that matched
+           the filter criteria (if any).  An empty data container
+           indicates that the request did not produce any results.";
+      }
+    }
+  }
+
+  rpc edit-config {
+    description
+      "The <edit-config> operation loads all or part of a specified
+       configuration to the specified target configuration.";
+
+    reference "RFC 6241, Section 7.2";
+
+    input {
+      container target {
+        description
+          "Particular configuration to edit.";
+
+        choice config-target {
+          mandatory true;
+          description
+            "The configuration target.";
+
+          leaf candidate {
+            if-feature candidate;
+            type empty;
+            description
+              "The candidate configuration is the config target.";
+          }
+          leaf running {
+            if-feature writable-running;
+            type empty;
+            description
+              "The running configuration is the config source.";
+          }
+        }
+      }
+
+      leaf default-operation {
+        type enumeration {
+          enum merge {
+            description
+              "The default operation is merge.";
+          }
+          enum replace {
+            description
+              "The default operation is replace.";
+          }
+          enum none {
+            description
+              "There is no default operation.";
+          }
+        }
+        default "merge";
+        description
+          "The default operation to use.";
+      }
+
+      leaf test-option {
+        if-feature validate;
+        type enumeration {
+          enum test-then-set {
+            description
+              "The server will test and then set if no errors.";
+          }
+          enum set {
+            description
+              "The server will set without a test first.";
+          }
+
+          enum test-only {
+            description
+              "The server will only test and not set, even
+               if there are no errors.";
+          }
+        }
+        default "test-then-set";
+        description
+          "The test option to use.";
+      }
+
+      leaf error-option {
+        type enumeration {
+          enum stop-on-error {
+            description
+              "The server will stop on errors.";
+          }
+          enum continue-on-error {
+            description
+              "The server may continue on errors.";
+          }
+          enum rollback-on-error {
+            description
+              "The server will roll back on errors.
+               This value can only be used if the 'rollback-on-error'
+               feature is supported.";
+          }
+        }
+        default "stop-on-error";
+        description
+          "The error option to use.";
+      }
+
+      choice edit-content {
+        mandatory true;
+        description
+          "The content for the edit operation.";
+
+        anyxml config {
+          description
+            "Inline Config content.";
+        }
+        leaf url {
+          if-feature url;
+          type inet:uri;
+          description
+            "URL-based config content.";
+        }
+      }
+    }
+  }
+
+  rpc copy-config {
+    description
+      "Create or replace an entire configuration datastore with the
+       contents of another complete configuration datastore.";
+
+    reference "RFC 6241, Section 7.3";
+
+    input {
+      container target {
+        description
+          "Particular configuration to copy to.";
+
+        choice config-target {
+          mandatory true;
+          description
+            "The configuration target of the copy operation.";
+
+          leaf candidate {
+            if-feature candidate;
+            type empty;
+            description
+              "The candidate configuration is the config target.";
+          }
+          leaf running {
+            if-feature writable-running;
+            type empty;
+            description
+              "The running configuration is the config target.
+               This is optional-to-implement on the server.";
+          }
+          leaf startup {
+            if-feature startup;
+            type empty;
+            description
+              "The startup configuration is the config target.";
+          }
+          leaf url {
+            if-feature url;
+            type inet:uri;
+            description
+              "The URL-based configuration is the config target.";
+          }
+        }
+      }
+
+      container source {
+        description
+          "Particular configuration to copy from.";
+
+        choice config-source {
+          mandatory true;
+          description
+            "The configuration source for the copy operation.";
+
+          leaf candidate {
+            if-feature candidate;
+            type empty;
+            description
+              "The candidate configuration is the config source.";
+          }
+          leaf running {
+            type empty;
+            description
+              "The running configuration is the config source.";
+          }
+          leaf startup {
+            if-feature startup;
+            type empty;
+            description
+              "The startup configuration is the config source.";
+          }
+          leaf url {
+            if-feature url;
+            type inet:uri;
+            description
+              "The URL-based configuration is the config source.";
+          }
+          anyxml config {
+            description
+              "Inline Config content: <config> element.  Represents
+               an entire configuration datastore, not
+               a subset of the running datastore.";
+          }
+        }
+      }
+    }
+  }
+
+  rpc delete-config {
+    nacm:default-deny-all;
+    description
+      "Delete a configuration datastore.";
+
+    reference "RFC 6241, Section 7.4";
+
+    input {
+      container target {
+        description
+          "Particular configuration to delete.";
+
+        choice config-target {
+          mandatory true;
+          description
+            "The configuration target to delete.";
+
+          leaf startup {
+            if-feature startup;
+            type empty;
+            description
+              "The startup configuration is the config target.";
+          }
+          leaf url {
+            if-feature url;
+            type inet:uri;
+            description
+              "The URL-based configuration is the config target.";
+          }
+        }
+      }
+    }
+  }
+
+  rpc lock {
+    description
+      "The lock operation allows the client to lock the configuration
+       system of a device.";
+
+    reference "RFC 6241, Section 7.5";
+
+    input {
+      container target {
+        description
+          "Particular configuration to lock.";
+
+        choice config-target {
+          mandatory true;
+          description
+            "The configuration target to lock.";
+
+          leaf candidate {
+            if-feature candidate;
+            type empty;
+            description
+              "The candidate configuration is the config target.";
+          }
+          leaf running {
+            type empty;
+            description
+              "The running configuration is the config target.";
+          }
+          leaf startup {
+            if-feature startup;
+            type empty;
+            description
+              "The startup configuration is the config target.";
+          }
+        }
+      }
+    }
+  }
+
+  rpc unlock {
+    description
+      "The unlock operation is used to release a configuration lock,
+       previously obtained with the 'lock' operation.";
+
+    reference "RFC 6241, Section 7.6";
+
+    input {
+      container target {
+        description
+          "Particular configuration to unlock.";
+
+        choice config-target {
+          mandatory true;
+          description
+            "The configuration target to unlock.";
+
+          leaf candidate {
+            if-feature candidate;
+            type empty;
+            description
+              "The candidate configuration is the config target.";
+          }
+          leaf running {
+            type empty;
+            description
+              "The running configuration is the config target.";
+          }
+          leaf startup {
+            if-feature startup;
+            type empty;
+            description
+              "The startup configuration is the config target.";
+          }
+        }
+      }
+    }
+  }
+
+  rpc get {
+    description
+      "Retrieve running configuration and device state information.";
+
+    reference "RFC 6241, Section 7.7";
+
+    input {
+      anyxml filter {
+        description
+          "This parameter specifies the portion of the system
+           configuration and state data to retrieve.";
+        nc:get-filter-element-attributes;
+      }
+    }
+
+    output {
+      anyxml data {
+        description
+          "Copy of the running datastore subset and/or state
+           data that matched the filter criteria (if any).
+           An empty data container indicates that the request did not
+           produce any results.";
+      }
+    }
+  }
+
+  rpc close-session {
+    description
+      "Request graceful termination of a NETCONF session.";
+
+    reference "RFC 6241, Section 7.8";
+  }
+
+  rpc kill-session {
+    nacm:default-deny-all;
+    description
+      "Force the termination of a NETCONF session.";
+
+    reference "RFC 6241, Section 7.9";
+
+    input {
+      leaf session-id {
+        type session-id-type;
+        mandatory true;
+        description
+          "Particular session to kill.";
+      }
+    }
+  }
+
+  rpc commit {
+    if-feature candidate;
+
+    description
+      "Commit the candidate configuration as the device's new
+       current configuration.";
+
+    reference "RFC 6241, Section 8.3.4.1";
+
+    input {
+      leaf confirmed {
+        if-feature confirmed-commit;
+        type empty;
+        description
+          "Requests a confirmed commit.";
+        reference "RFC 6241, Section 8.3.4.1";
+      }
+
+      leaf confirm-timeout {
+        if-feature confirmed-commit;
+        type uint32 {
+          range "1..max";
+        }
+        units "seconds";
+        default "600";   // 10 minutes
+        description
+          "The timeout interval for a confirmed commit.";
+        reference "RFC 6241, Section 8.3.4.1";
+      }
+
+      leaf persist {
+        if-feature confirmed-commit;
+        type string;
+        description
+          "This parameter is used to make a confirmed commit
+           persistent.  A persistent confirmed commit is not aborted
+           if the NETCONF session terminates.  The only way to abort
+           a persistent confirmed commit is to let the timer expire,
+           or to use the <cancel-commit> operation.
+
+           The value of this parameter is a token that must be given
+           in the 'persist-id' parameter of <commit> or
+           <cancel-commit> operations in order to confirm or cancel
+           the persistent confirmed commit.
+
+           The token should be a random string.";
+        reference "RFC 6241, Section 8.3.4.1";
+      }
+
+      leaf persist-id {
+        if-feature confirmed-commit;
+        type string;
+        description
+          "This parameter is given in order to commit a persistent
+           confirmed commit.  The value must be equal to the value
+           given in the 'persist' parameter to the <commit> operation.
+           If it does not match, the operation fails with an
+          'invalid-value' error.";
+        reference "RFC 6241, Section 8.3.4.1";
+      }
+
+    }
+  }
+
+  rpc discard-changes {
+    if-feature candidate;
+
+    description
+      "Revert the candidate configuration to the current
+       running configuration.";
+    reference "RFC 6241, Section 8.3.4.2";
+  }
+
+  rpc cancel-commit {
+    if-feature confirmed-commit;
+    description
+      "This operation is used to cancel an ongoing confirmed commit.
+       If the confirmed commit is persistent, the parameter
+       'persist-id' must be given, and it must match the value of the
+       'persist' parameter.";
+    reference "RFC 6241, Section 8.4.4.1";
+
+    input {
+      leaf persist-id {
+        type string;
+        description
+          "This parameter is given in order to cancel a persistent
+           confirmed commit.  The value must be equal to the value
+           given in the 'persist' parameter to the <commit> operation.
+           If it does not match, the operation fails with an
+          'invalid-value' error.";
+      }
+    }
+  }
+
+  rpc validate {
+    if-feature validate;
+
+    description
+      "Validates the contents of the specified configuration.";
+
+    reference "RFC 6241, Section 8.6.4.1";
+
+    input {
+      container source {
+        description
+          "Particular configuration to validate.";
+
+        choice config-source {
+          mandatory true;
+          description
+            "The configuration source to validate.";
+
+          leaf candidate {
+            if-feature candidate;
+            type empty;
+            description
+              "The candidate configuration is the config source.";
+          }
+          leaf running {
+            type empty;
+            description
+              "The running configuration is the config source.";
+          }
+          leaf startup {
+            if-feature startup;
+            type empty;
+            description
+              "The startup configuration is the config source.";
+          }
+          leaf url {
+            if-feature url;
+            type inet:uri;
+            description
+              "The URL-based configuration is the config source.";
+          }
+          anyxml config {
+            description
+              "Inline Config content: <config> element.  Represents
+               an entire configuration datastore, not
+               a subset of the running datastore.";
+          }
+        }
+      }
+    }
+  }
+
+}
diff --git a/tests/src/test_validation.c b/tests/src/test_validation.c
index 660f856..6f0ef9f 100644
--- a/tests/src/test_validation.c
+++ b/tests/src/test_validation.c
@@ -20,8 +20,11 @@
 #include <stdio.h>
 #include <string.h>
 
+#include "tests/config.h"
+
 #include "../../src/context.h"
 #include "../../src/tree_data_internal.h"
+#include "../../src/printer_data.h"
 
 #define BUFSIZE 1024
 char logbuf[BUFSIZE] = {0};
@@ -177,16 +180,127 @@
                 "}"
             "}"
         "}";
+    const char *schema_e =
+        "module e {"
+            "namespace urn:tests:e;"
+            "prefix e;"
+            "yang-version 1.1;"
+
+            "choice choic {"
+                "leaf a {"
+                    "type string;"
+                "}"
+                "case b {"
+                    "leaf-list l {"
+                        "type string;"
+                    "}"
+                "}"
+            "}"
+            "list lt {"
+                "key \"k\";"
+                "leaf k {"
+                    "type string;"
+                "}"
+            "}"
+            "leaf d {"
+                "type uint32;"
+            "}"
+            "leaf-list ll {"
+                "type string;"
+            "}"
+            "container cont {"
+                "list lt {"
+                    "key \"k\";"
+                    "leaf k {"
+                        "type string;"
+                    "}"
+                "}"
+                "leaf d {"
+                    "type uint32;"
+                "}"
+                "leaf-list ll {"
+                    "type string;"
+                "}"
+            "}"
+        "}";
+    const char *schema_f =
+        "module f {"
+            "namespace urn:tests:f;"
+            "prefix f;"
+            "yang-version 1.1;"
+
+            "choice choic {"
+                "default \"c\";"
+                "leaf a {"
+                    "type string;"
+                "}"
+                "case b {"
+                    "leaf l {"
+                        "type string;"
+                    "}"
+                "}"
+                "case c {"
+                    "leaf-list ll1 {"
+                        "type string;"
+                        "default \"def1\";"
+                        "default \"def2\";"
+                        "default \"def3\";"
+                    "}"
+                "}"
+            "}"
+            "leaf d {"
+                "type uint32;"
+                "default 15;"
+            "}"
+            "leaf-list ll2 {"
+                "type string;"
+                "default \"dflt1\";"
+                "default \"dflt2\";"
+            "}"
+            "container cont {"
+                "choice choic {"
+                    "default \"c\";"
+                    "leaf a {"
+                        "type string;"
+                    "}"
+                    "case b {"
+                        "leaf l {"
+                            "type string;"
+                        "}"
+                    "}"
+                    "case c {"
+                        "leaf-list ll1 {"
+                            "type string;"
+                            "default \"def1\";"
+                            "default \"def2\";"
+                            "default \"def3\";"
+                        "}"
+                    "}"
+                "}"
+                "leaf d {"
+                    "type uint32;"
+                    "default 15;"
+                "}"
+                "leaf-list ll2 {"
+                    "type string;"
+                    "default \"dflt1\";"
+                    "default \"dflt2\";"
+                "}"
+            "}"
+        "}";
 
 #if ENABLE_LOGGER_CHECKING
     ly_set_log_clb(logger, 1);
 #endif
 
-    assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx));
+    assert_int_equal(LY_SUCCESS, ly_ctx_new(TESTS_DIR_MODULES_YANG, 0, &ctx));
+    assert_non_null(ly_ctx_load_module(ctx, "ietf-netconf-with-defaults", "2011-06-01"));
     assert_non_null(lys_parse_mem(ctx, schema_a, LYS_IN_YANG));
     assert_non_null(lys_parse_mem(ctx, schema_b, LYS_IN_YANG));
     assert_non_null(lys_parse_mem(ctx, schema_c, LYS_IN_YANG));
     assert_non_null(lys_parse_mem(ctx, schema_d, LYS_IN_YANG));
+    assert_non_null(lys_parse_mem(ctx, schema_e, LYS_IN_YANG));
+    assert_non_null(lys_parse_mem(ctx, schema_f, LYS_IN_YANG));
 
     return 0;
 }
@@ -285,7 +399,7 @@
     data = "<a xmlns=\"urn:tests:b\">string</a><c xmlns=\"urn:tests:b\">string2</c>";
     assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
-    lyd_free_withsiblings(tree);
+    lyd_free_siblings(tree);
 
     *state = NULL;
 }
@@ -316,7 +430,7 @@
     "<l xmlns=\"urn:tests:c\">val3</l>";
     assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
-    lyd_free_withsiblings(tree);
+    lyd_free_siblings(tree);
 
     data =
     "<l xmlns=\"urn:tests:c\">val1</l>"
@@ -352,7 +466,7 @@
     "</lt>";
     assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
-    lyd_free_withsiblings(tree);
+    lyd_free_siblings(tree);
 
     data =
     "<lt xmlns=\"urn:tests:d\">"
@@ -365,7 +479,7 @@
     "</lt>";
     assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
-    lyd_free_withsiblings(tree);
+    lyd_free_siblings(tree);
 
     data =
     "<lt xmlns=\"urn:tests:d\">"
@@ -416,7 +530,7 @@
     "</lt>";
     assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
-    lyd_free_withsiblings(tree);
+    lyd_free_siblings(tree);
 
     data =
     "<lt xmlns=\"urn:tests:d\">"
@@ -450,7 +564,7 @@
     "</lt>";
     assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
-    lyd_free_withsiblings(tree);
+    lyd_free_siblings(tree);
 
     data =
     "<lt xmlns=\"urn:tests:d\">"
@@ -556,7 +670,7 @@
     "</lt2>";
     assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY | LYD_OPT_STRICT, &tree));
     assert_non_null(tree);
-    lyd_free_withsiblings(tree);
+    lyd_free_siblings(tree);
 
     data =
     "<lt2 xmlns=\"urn:tests:d\">"
@@ -711,6 +825,193 @@
     *state = NULL;
 }
 
+static void
+test_dup(void **state)
+{
+    *state = test_dup;
+
+    const char *data;
+    struct lyd_node *tree;
+
+    data = "<d xmlns=\"urn:tests:e\">25</d><d xmlns=\"urn:tests:e\">50</d>";
+    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_null(tree);
+    logbuf_assert("Duplicate instance of \"d\". /e:d");
+
+    data = "<lt xmlns=\"urn:tests:e\"><k>A</k></lt><lt xmlns=\"urn:tests:e\"><k>B</k></lt><lt xmlns=\"urn:tests:e\"><k>A</k></lt>";
+    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_null(tree);
+    logbuf_assert("Duplicate instance of \"lt\". /e:lt[k='A']");
+
+    data = "<ll xmlns=\"urn:tests:e\">A</ll><ll xmlns=\"urn:tests:e\">B</ll><ll xmlns=\"urn:tests:e\">B</ll>";
+    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_null(tree);
+    logbuf_assert("Duplicate instance of \"ll\". /e:ll[.='B']");
+
+    data = "<cont xmlns=\"urn:tests:e\"></cont><cont xmlns=\"urn:tests:e\"/>";
+    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_null(tree);
+    logbuf_assert("Duplicate instance of \"cont\". /e:cont");
+
+    /* same tests again but using hashes */
+    data = "<cont xmlns=\"urn:tests:e\"><d>25</d><d>50</d><ll>1</ll><ll>2</ll><ll>3</ll><ll>4</ll></cont>";
+    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_null(tree);
+    logbuf_assert("Duplicate instance of \"d\". /e:cont/d");
+
+    data = "<cont xmlns=\"urn:tests:e\"><ll>1</ll><ll>2</ll><ll>3</ll><ll>4</ll>"
+        "<lt><k>a</k></lt><lt><k>b</k></lt><lt><k>c</k></lt><lt><k>d</k></lt><lt><k>c</k></lt></cont>";
+    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_null(tree);
+    logbuf_assert("Duplicate instance of \"lt\". /e:cont/lt[k='c']");
+
+    data = "<cont xmlns=\"urn:tests:e\"><ll>1</ll><ll>2</ll><ll>3</ll><ll>4</ll>"
+        "<ll>a</ll><ll>b</ll><ll>c</ll><ll>d</ll><ll>d</ll></cont>";
+    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_null(tree);
+    logbuf_assert("Duplicate instance of \"ll\". /e:cont/ll[.='d']");
+
+    /* cases */
+    data = "<l xmlns=\"urn:tests:e\">a</l><l xmlns=\"urn:tests:e\">b</l><l xmlns=\"urn:tests:e\">c</l><l xmlns=\"urn:tests:e\">b</l>";
+    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_null(tree);
+    logbuf_assert("Duplicate instance of \"l\". /e:l[.='b']");
+
+    data = "<l xmlns=\"urn:tests:e\">a</l><l xmlns=\"urn:tests:e\">b</l><l xmlns=\"urn:tests:e\">c</l><a xmlns=\"urn:tests:e\">aa</a>";
+    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_null(tree);
+    logbuf_assert("Data for both cases \"a\" and \"b\" exist. /e:choic");
+
+    *state = NULL;
+}
+
+static void
+test_defaults(void **state)
+{
+    *state = test_defaults;
+
+    const char *data;
+    char *str;
+    struct lyd_node *tree, *node;
+    const struct lys_module *mod = ly_ctx_get_module_latest(ctx, "f");
+
+    data = "<cont xmlns=\"urn:tests:f\"/>";
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_non_null(tree);
+
+    /* check all defaults exist */
+    lyd_print_mem(&str, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_IMPL_TAG);
+    assert_string_equal(str,
+        "<cont xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">"
+            "<ll1 ncwd:default=\"true\">def1</ll1>"
+            "<ll1 ncwd:default=\"true\">def2</ll1>"
+            "<ll1 ncwd:default=\"true\">def3</ll1>"
+            "<d ncwd:default=\"true\">15</d>"
+            "<ll2 ncwd:default=\"true\">dflt1</ll2>"
+            "<ll2 ncwd:default=\"true\">dflt2</ll2>"
+        "</cont>"
+        "<ll1 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def1</ll1>"
+        "<ll1 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def2</ll1>"
+        "<ll1 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def3</ll1>"
+        "<d xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">15</d>"
+        "<ll2 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt1</ll2>"
+        "<ll2 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt2</ll2>");
+    free(str);
+
+    /* create another explicit case and validate */
+    node = lyd_new_term(NULL, mod, "l", "value");
+    assert_non_null(node);
+    assert_int_equal(lyd_insert_after(tree->prev, node), LY_SUCCESS);
+    assert_int_equal(lyd_validate(ctx, &tree, LYD_VALOPT_DATA_ONLY), LY_SUCCESS);
+
+    /* check data tree */
+    lyd_print_mem(&str, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_IMPL_TAG);
+    assert_string_equal(str,
+        "<cont xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">"
+            "<ll1 ncwd:default=\"true\">def1</ll1>"
+            "<ll1 ncwd:default=\"true\">def2</ll1>"
+            "<ll1 ncwd:default=\"true\">def3</ll1>"
+            "<d ncwd:default=\"true\">15</d>"
+            "<ll2 ncwd:default=\"true\">dflt1</ll2>"
+            "<ll2 ncwd:default=\"true\">dflt2</ll2>"
+        "</cont>"
+        "<d xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">15</d>"
+        "<ll2 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt1</ll2>"
+        "<ll2 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt2</ll2>"
+        "<l xmlns=\"urn:tests:f\">value</l>");
+    free(str);
+
+    /* create explicit leaf-list and leaf and validate */
+    node = lyd_new_term(NULL, mod, "d", "15");
+    assert_non_null(node);
+    assert_int_equal(lyd_insert_after(tree->prev, node), LY_SUCCESS);
+    node = lyd_new_term(NULL, mod, "ll2", "dflt2");
+    assert_non_null(node);
+    assert_int_equal(lyd_insert_after(tree->prev, node), LY_SUCCESS);
+    assert_int_equal(lyd_validate(ctx, &tree, LYD_VALOPT_DATA_ONLY), LY_SUCCESS);
+
+    /* check data tree */
+    lyd_print_mem(&str, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_IMPL_TAG);
+    assert_string_equal(str,
+        "<cont xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">"
+            "<ll1 ncwd:default=\"true\">def1</ll1>"
+            "<ll1 ncwd:default=\"true\">def2</ll1>"
+            "<ll1 ncwd:default=\"true\">def3</ll1>"
+            "<d ncwd:default=\"true\">15</d>"
+            "<ll2 ncwd:default=\"true\">dflt1</ll2>"
+            "<ll2 ncwd:default=\"true\">dflt2</ll2>"
+        "</cont>"
+        "<l xmlns=\"urn:tests:f\">value</l>"
+        "<d xmlns=\"urn:tests:f\">15</d>"
+        "<ll2 xmlns=\"urn:tests:f\">dflt2</ll2>");
+    free(str);
+
+//     /* create explicit container, which automatically becomes implicit */
+//     node = lyd_new_inner(NULL, mod, "cont");
+//     assert_non_null(node);
+//     assert_int_equal(lyd_insert_after(tree->prev, node), LY_SUCCESS);
+//     assert_int_equal(lyd_validate(ctx, &tree, LYD_VALOPT_DATA_ONLY), LY_SUCCESS);
+//
+//     /* check data tree */
+//     lyd_print_mem(&str, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_IMPL_TAG);
+//     assert_string_equal(str,
+//         "<cont xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">"
+//             "<ll1 ncwd:default=\"true\">def1</ll1>"
+//             "<ll1 ncwd:default=\"true\">def2</ll1>"
+//             "<ll1 ncwd:default=\"true\">def3</ll1>"
+//             "<d ncwd:default=\"true\">15</d>"
+//             "<ll2 ncwd:default=\"true\">dflt1</ll2>"
+//             "<ll2 ncwd:default=\"true\">dflt2</ll2>"
+//         "</cont>"
+//         "<l xmlns=\"urn:tests:f\">value</l>"
+//         "<d xmlns=\"urn:tests:f\">15</d>"
+//         "<ll2 xmlns=\"urn:tests:f\">dflt2</ll2>");
+//     free(str);
+
+    /* similar changes for nested defaults */
+    assert_non_null(lyd_new_term(tree, NULL, "ll1", "def3"));
+    assert_non_null(lyd_new_term(tree, NULL, "d", "5"));
+    assert_non_null(lyd_new_term(tree, NULL, "ll2", "non-dflt"));
+    assert_int_equal(lyd_validate(ctx, &tree, LYD_VALOPT_DATA_ONLY), LY_SUCCESS);
+
+    /* check data tree */
+    lyd_print_mem(&str, tree, LYD_XML, LYDP_WITHSIBLINGS | LYDP_WD_IMPL_TAG);
+    assert_string_equal(str,
+        "<cont xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">"
+            "<ll1>def3</ll1>"
+            "<d>5</d>"
+            "<ll2>non-dflt</ll2>"
+        "</cont>"
+        "<l xmlns=\"urn:tests:f\">value</l>"
+        "<d xmlns=\"urn:tests:f\">15</d>"
+        "<ll2 xmlns=\"urn:tests:f\">dflt2</ll2>");
+    free(str);
+
+    lyd_free_siblings(tree);
+
+    *state = NULL;
+}
+
 int main(void)
 {
     const struct CMUnitTest tests[] = {
@@ -719,6 +1020,8 @@
         cmocka_unit_test_teardown(test_minmax, teardown_s),
         cmocka_unit_test_teardown(test_unique, teardown_s),
         cmocka_unit_test_teardown(test_unique_nested, teardown_s),
+        cmocka_unit_test_teardown(test_dup, teardown_s),
+        cmocka_unit_test_teardown(test_defaults, teardown_s),
     };
 
     return cmocka_run_group_tests(tests, setup, teardown);
diff --git a/tools/lint/commands.c b/tools/lint/commands.c
index 67c0e53..b397950 100644
--- a/tools/lint/commands.c
+++ b/tools/lint/commands.c
@@ -545,7 +545,7 @@
 }
 
 static int
-parse_data(char *filepath, int *options, const struct lyd_node **trees, const char *rpc_act_file,
+parse_data(char *filepath, int *options, const struct lyd_node *tree, const char *rpc_act_file,
            struct lyd_node **result)
 {
     LYD_FORMAT informat = LYD_UNKNOWN;
@@ -696,8 +696,8 @@
     int options = 0, printopt = 0;
     char **argv = NULL, *ptr;
     const char *out_path = NULL;
-    struct lyd_node *data = NULL, *val_tree = NULL;
-    const struct lyd_node **trees = NULL;
+    struct lyd_node *data = NULL;
+    struct lyd_node *tree = NULL;
     LYD_FORMAT outformat = LYD_UNKNOWN;
     FILE *output = stdout;
     static struct option long_options[] = {
@@ -829,7 +829,7 @@
         goto cleanup;
     }
 
-    if (parse_data(argv[optind], &options, trees, argv[optind + 1], &data)) {
+    if (parse_data(argv[optind], &options, tree, argv[optind + 1], &data)) {
         goto cleanup;
     }
 
@@ -855,7 +855,6 @@
         fclose(output);
     }
 
-    lyd_trees_free(trees, 1);
     lyd_free_all(data);
 
     return ret;
diff --git a/tools/lint/main_ni.c b/tools/lint/main_ni.c
index 60ecfe1..99e7ce2 100644
--- a/tools/lint/main_ni.c
+++ b/tools/lint/main_ni.c
@@ -319,8 +319,7 @@
     struct lyxml_elem *iter, *elem;
     struct *subroot, *next, *node;
 #endif
-    struct lyd_node *oper = NULL;
-    const struct lyd_node **trees = NULL;
+    struct lyd_node *tree = NULL;
     struct dataitem {
         const char *filename;
         struct lyd_node *tree;
@@ -797,12 +796,11 @@
                 fprintf(stderr, "yanglint error: The operational data are expected in XML or JSON format.\n");
                 goto cleanup;
             }
-            oper = lyd_parse_path(ctx, oper_file, informat_d, LYD_OPT_PARSE_ONLY);
-            if (!oper) {
+            tree = lyd_parse_path(ctx, oper_file, informat_d, LYD_OPT_PARSE_ONLY);
+            if (!tree) {
                 fprintf(stderr, "yanglint error: Failed to parse the operational datastore file for RPC/Notification validation.\n");
                 goto cleanup;
             }
-            trees = lyd_trees_new(1, oper);
         }
 
         for (data_item = data, data_prev = NULL; data_item; data_prev = data_item, data_item = data_item->next) {
@@ -1101,7 +1099,6 @@
         lyd_free_all(data->tree);
         free(data);
     }
-    lyd_trees_free(trees, 1);
     ly_ctx_destroy(ctx, NULL);
 
     return ret;