libyang REFACTOR return values and options changes

Unified, all functions that return a variety
of errors return LY_ERR. Any options such as
NOSIBLINGS, WITHSIBLINGS and so on were replaced
by function variants with suffixes _single, _all,
_tree, and _siblings.
diff --git a/src/context.c b/src/context.c
index 302638e..b2637ff 100644
--- a/src/context.c
+++ b/src/context.c
@@ -257,10 +257,9 @@
     /* load internal modules */
     for (i = 0; i < ((options & LY_CTX_NOYANGLIBRARY) ? (LY_INTERNAL_MODS_COUNT - 2) : LY_INTERNAL_MODS_COUNT); i++) {
         ly_in_memory(in, internal_modules[i].data);
-        module = (struct lys_module *)lys_parse_mem_module(ctx, in, internal_modules[i].format,
-                                                           internal_modules[i].implemented, NULL, NULL);
-        LY_CHECK_ERR_GOTO(!module, rc = ly_errcode(ctx), error);
-        LY_CHECK_GOTO((rc = lys_compile(&module, 0)), error);
+        LY_CHECK_GOTO(rc = lys_parse_mem_module(ctx, in, internal_modules[i].format, internal_modules[i].implemented,
+                                                NULL, NULL, &module), error);
+        LY_CHECK_GOTO(rc = lys_compile(&module, 0), error);
     }
 
     ly_in_free(in, 0);
@@ -551,7 +550,6 @@
 ylib_feature(struct lyd_node *parent, const struct lys_module *cur_mod)
 {
     LY_ARRAY_COUNT_TYPE i;
-    struct lyd_node *node;
 
     if (!cur_mod->implemented) {
         /* no features can be enabled */
@@ -563,8 +561,7 @@
             continue;
         }
 
-        node = lyd_new_term(parent, NULL, "feature", cur_mod->compiled->features[i].name);
-        LY_CHECK_RET(!node, LY_EOTHER);
+        LY_CHECK_RET(lyd_new_term(parent, NULL, "feature", cur_mod->compiled->features[i].name, NULL));
     }
 
     return LY_SUCCESS;
@@ -574,7 +571,6 @@
 ylib_deviation(struct lyd_node *parent, const struct lys_module *cur_mod, int bis)
 {
     LY_ARRAY_COUNT_TYPE i;
-    struct lyd_node *node;
     struct lys_module *mod;
 
     if (!cur_mod->implemented) {
@@ -586,11 +582,10 @@
         mod = cur_mod->compiled->deviated_by[i];
 
         if (bis) {
-            node = lyd_new_term(parent, NULL, "deviation", mod->name);
-            LY_CHECK_RET(!node, LY_EOTHER);
+            LY_CHECK_RET(lyd_new_term(parent, NULL, "deviation", mod->name, NULL));
         } else {
-            node = lyd_new_list(parent, NULL, "deviation", mod->name, (mod->parsed->revs ? mod->parsed->revs[0].date : ""));
-            LY_CHECK_RET(!node, LY_EOTHER);
+            LY_CHECK_RET(lyd_new_list(parent, NULL, "deviation", NULL, mod->name,
+                                      (mod->parsed->revs ? mod->parsed->revs[0].date : "")));
         }
     }
 
@@ -600,35 +595,34 @@
 static LY_ERR
 ylib_submodules(struct lyd_node *parent, const struct lys_module *cur_mod, int bis)
 {
+    LY_ERR ret;
     LY_ARRAY_COUNT_TYPE i;
-    struct lyd_node *node, *cont;
+    struct lyd_node *cont;
     struct lysp_submodule *submod;
-    int ret;
+    int r;
     char *str;
 
     LY_ARRAY_FOR(cur_mod->parsed->includes, i) {
         submod = cur_mod->parsed->includes[i].submodule;
 
         if (bis) {
-            cont = lyd_new_list(parent, NULL, "submodule", submod->name);
-            LY_CHECK_RET(!cont, LY_EOTHER);
+            LY_CHECK_RET(lyd_new_list(parent, NULL, "submodule", &cont, submod->name));
 
             if (submod->revs) {
-                node = lyd_new_term(cont, NULL, "revision", submod->revs[0].date);
-                LY_CHECK_RET(!node, LY_EOTHER);
+                LY_CHECK_RET(lyd_new_term(cont, NULL, "revision", submod->revs[0].date, NULL));
             }
         } else {
-            cont = lyd_new_list(parent, NULL, "submodule", submod->name, (submod->revs ? submod->revs[0].date : ""));
-            LY_CHECK_RET(!cont, LY_EOTHER);
+            LY_CHECK_RET(lyd_new_list(parent, NULL, "submodule", &cont, submod->name,
+                                      (submod->revs ? submod->revs[0].date : "")));
         }
 
         if (submod->filepath) {
-            ret = asprintf(&str, "file://%s", submod->filepath);
-            LY_CHECK_ERR_RET(ret == -1, LOGMEM(cur_mod->ctx), LY_EMEM);
+            r = asprintf(&str, "file://%s", submod->filepath);
+            LY_CHECK_ERR_RET(r == -1, LOGMEM(cur_mod->ctx), LY_EMEM);
 
-            node = lyd_new_term(cont, NULL, bis ? "location" : "schema", str);
-            LY_CHECK_RET(!node, LY_EOTHER);
+            ret = lyd_new_term(cont, NULL, bis ? "location" : "schema", str, NULL);
             free(str);
+            LY_CHECK_RET(ret);
         }
     }
 
@@ -641,19 +635,20 @@
     return ctx->module_set_id;
 }
 
-API struct lyd_node *
-ly_ctx_get_yanglib_data(const struct ly_ctx *ctx)
+API LY_ERR
+ly_ctx_get_yanglib_data(const struct ly_ctx *ctx, struct lyd_node **root_p)
 {
+    LY_ERR ret;
     uint32_t i;
-    int bis = 0, ret;
+    int bis = 0, r;
     char id[8], *str;
     const struct lys_module *mod;
-    struct lyd_node *root = NULL, *root_bis = NULL, *cont, *set_bis = NULL, *node;
+    struct lyd_node *root = NULL, *root_bis = NULL, *cont, *set_bis = NULL;
 
-    LY_CHECK_ARG_RET(ctx, ctx, NULL);
+    LY_CHECK_ARG_RET(ctx, ctx, root_p, LY_EINVAL);
 
     mod = ly_ctx_get_module_implemented(ctx, "ietf-yang-library");
-    LY_CHECK_ERR_RET(!mod, LOGERR(ctx, LY_EINVAL, "Module \"ietf-yang-library\" is not implemented."), NULL);
+    LY_CHECK_ERR_RET(!mod, LOGERR(ctx, LY_EINVAL, "Module \"ietf-yang-library\" is not implemented."), LY_EINVAL);
 
     if (mod->parsed->revs && !strcmp(mod->parsed->revs[0].date, "2016-06-21")) {
         bis = 0;
@@ -661,18 +656,14 @@
         bis = 1;
     } else {
         LOGERR(ctx, LY_EINVAL, "Incompatible ietf-yang-library version in context.");
-        return NULL;
+        return LY_EINVAL;
     }
 
-    root = lyd_new_inner(NULL, mod, "modules-state");
-    LY_CHECK_GOTO(!root, error);
+    LY_CHECK_GOTO(ret = lyd_new_inner(NULL, mod, "modules-state", &root), error);
 
     if (bis) {
-        root_bis = lyd_new_inner(NULL, mod, "yang-library");
-        LY_CHECK_GOTO(!root_bis, error);
-
-        set_bis = lyd_new_list(root_bis, NULL, "module-set", "complete");
-        LY_CHECK_GOTO(!set_bis, error);
+        LY_CHECK_GOTO(ret = lyd_new_inner(NULL, mod, "yang-library", &root_bis), error);
+        LY_CHECK_GOTO(ret = lyd_new_list(root_bis, NULL, "module-set", &set_bis, "complete"), error);
     }
 
     for (i = 0; i < ctx->list.count; ++i) {
@@ -681,35 +672,34 @@
         /*
          * deprecated legacy
          */
-        cont = lyd_new_list(root, NULL, "module", mod->name, (mod->parsed->revs ? mod->parsed->revs[0].date : ""));
-        LY_CHECK_GOTO(!cont, error);
+        LY_CHECK_GOTO(ret = lyd_new_list(root, NULL, "module", &cont, mod->name,
+                                         (mod->parsed->revs ? mod->parsed->revs[0].date : "")), error);
 
         /* schema */
         if (mod->filepath) {
-            ret = asprintf(&str, "file://%s", mod->filepath);
-            LY_CHECK_ERR_GOTO(ret == -1, LOGMEM(ctx), error);
+            r = asprintf(&str, "file://%s", mod->filepath);
+            LY_CHECK_ERR_GOTO(r == -1, LOGMEM(ctx); ret = LY_EMEM, error);
 
-            node = lyd_new_term(cont, NULL, "schema", str);
+            ret = lyd_new_term(cont, NULL, "schema", str, NULL);
             free(str);
-            LY_CHECK_GOTO(!node, error);
+            LY_CHECK_GOTO(ret, error);
         }
 
         /* namespace */
-        node = lyd_new_term(cont, NULL, "namespace", mod->ns);
-        LY_CHECK_GOTO(!node, error);
+        LY_CHECK_GOTO(ret = lyd_new_term(cont, NULL, "namespace", mod->ns, NULL), error);
 
         /* feature leaf-list */
-        LY_CHECK_GOTO(ylib_feature(cont, mod), error);
+        LY_CHECK_GOTO(ret = ylib_feature(cont, mod), error);
 
         /* deviation list */
-        LY_CHECK_GOTO(ylib_deviation(cont, mod, 0), error);
+        LY_CHECK_GOTO(ret = ylib_deviation(cont, mod, 0), error);
 
         /* conformance-type */
-        node = lyd_new_term(cont, NULL, "conformance-type", (mod->implemented ? "implement" : "import"));
-        LY_CHECK_GOTO(!node, error);
+        LY_CHECK_GOTO(ret = lyd_new_term(cont, NULL, "conformance-type", mod->implemented ? "implement" : "import",
+                                         NULL), error);
 
         /* submodule list */
-        LY_CHECK_GOTO(ylib_submodules(cont, mod, 0), error);
+        LY_CHECK_GOTO(ret = ylib_submodules(cont, mod, 0), error);
 
         /*
          * current revision
@@ -717,60 +707,52 @@
         if (bis) {
             /* name and revision */
             if (mod->implemented) {
-                cont = lyd_new_list(set_bis, NULL, "module", mod->name);
-                LY_CHECK_GOTO(!cont, error);
+                LY_CHECK_GOTO(ret = lyd_new_list(set_bis, NULL, "module", &cont, mod->name), error);
 
                 if (mod->parsed->revs) {
-                    node = lyd_new_term(cont, NULL, "revision", mod->parsed->revs[0].date);
-                    LY_CHECK_GOTO(!node, error);
+                    LY_CHECK_GOTO(ret = lyd_new_term(cont, NULL, "revision", mod->parsed->revs[0].date, NULL), error);
                 }
             } else {
-                cont = lyd_new_list(set_bis, NULL, "import-only-module", mod->name,
-                                    (mod->parsed->revs ? mod->parsed->revs[0].date : ""));
-                LY_CHECK_GOTO(!cont, error);
+                LY_CHECK_GOTO(ret = lyd_new_list(set_bis, NULL, "import-only-module", &cont, mod->name,
+                                                 (mod->parsed->revs ? mod->parsed->revs[0].date : "")), error);
             }
 
             /* namespace */
-            node = lyd_new_term(cont, NULL, "namespace", mod->ns);
-            LY_CHECK_GOTO(!node, error);
+            LY_CHECK_GOTO(ret = lyd_new_term(cont, NULL, "namespace", mod->ns, NULL), error);
 
             /* location */
             if (mod->filepath) {
-                ret = asprintf(&str, "file://%s", mod->filepath);
-                LY_CHECK_ERR_GOTO(ret == -1, LOGMEM(ctx), error);
+                r = asprintf(&str, "file://%s", mod->filepath);
+                LY_CHECK_ERR_GOTO(r == -1, LOGMEM(ctx); ret = LY_EMEM, error);
 
-                node = lyd_new_term(cont, NULL, "schema", str);
+                ret = lyd_new_term(cont, NULL, "schema", str, NULL);
                 free(str);
-                LY_CHECK_GOTO(!node, error);
+                LY_CHECK_GOTO(ret, error);
             }
 
             /* submodule list */
-            LY_CHECK_GOTO(ylib_submodules(cont, mod, 1), error);
+            LY_CHECK_GOTO(ret = ylib_submodules(cont, mod, 1), error);
 
             /* feature list */
-            LY_CHECK_GOTO(ylib_feature(cont, mod), error);
+            LY_CHECK_GOTO(ret = ylib_feature(cont, mod), error);
 
             /* deviation */
-            LY_CHECK_GOTO(ylib_deviation(cont, mod, 1), error);
+            LY_CHECK_GOTO(ret = ylib_deviation(cont, mod, 1), error);
         }
     }
 
     /* IDs */
     sprintf(id, "%u", ctx->module_set_id);
-    node = lyd_new_term(root, NULL, "module-set-id", id);
-    LY_CHECK_GOTO(!node, error);
+    LY_CHECK_GOTO(ret = lyd_new_term(root, NULL, "module-set-id", id, NULL), error);
 
     if (bis) {
         /* create one complete schema */
-        cont = lyd_new_list(root_bis, NULL, "schema", "complete");
-        LY_CHECK_GOTO(!cont, error);
+        LY_CHECK_GOTO(ret = lyd_new_list(root_bis, NULL, "schema", &cont, "complete"), error);
 
-        node = lyd_new_term(cont, NULL, "module-set", "complete");
-        LY_CHECK_GOTO(!node, error);
+        LY_CHECK_GOTO(ret = lyd_new_term(cont, NULL, "module-set", "complete", NULL), error);
 
         /* content-id */
-        node = lyd_new_term(root_bis, NULL, "content-id", id);
-        LY_CHECK_GOTO(!node, error);
+        LY_CHECK_GOTO(ret = lyd_new_term(root_bis, NULL, "content-id", id, NULL), error);
     }
 
     if (root_bis) {
@@ -781,16 +763,15 @@
         root_bis = 0;
     }
 
-    if (lyd_validate(&root, NULL, LYD_VALIDATE_PRESENT, NULL)) {
-        goto error;
-    }
+    LY_CHECK_GOTO(ret = lyd_validate_all(&root, NULL, LYD_VALIDATE_PRESENT, NULL), error);
 
-    return root;
+    *root_p = root;
+    return LY_SUCCESS;
 
 error:
     lyd_free_all(root);
     lyd_free_all(root_bis);
-    return NULL;
+    return ret;
 }
 
 API void
diff --git a/src/context.h b/src/context.h
index 9dc3f57..cdd5ced 100644
--- a/src/context.h
+++ b/src/context.h
@@ -24,6 +24,7 @@
 extern "C" {
 #endif
 
+struct lyd_node;
 struct lysc_node;
 
 /**
@@ -446,10 +447,10 @@
  * ietf-yang-library module must be loaded.
  *
  * @param[in] ctx Context with the modules.
- * @return Generated data, must be freed,
- * @return NULL on error.
+ * @param[out] root Generated yang-library data.
+ * @return LY_ERR value
  */
-struct lyd_node *ly_ctx_get_yanglib_data(const struct ly_ctx *ctx);
+LY_ERR ly_ctx_get_yanglib_data(const struct ly_ctx *ctx, struct lyd_node **root);
 
 /**
  * @brief Free all internal structures of the specified context.
diff --git a/src/diff.c b/src/diff.c
index e69f52a..cef0713 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -102,8 +102,8 @@
     }
 
     /* duplicate the subtree (and connect to the diff if possible) */
-    dup = lyd_dup(node, (struct lyd_node_inner *)diff_parent, LYD_DUP_RECURSIVE | LYD_DUP_NO_META | LYD_DUP_WITH_PARENTS);
-    LY_CHECK_RET(!dup, LY_EMEM);
+    LY_CHECK_RET(lyd_dup_single(node, (struct lyd_node_inner *)diff_parent,
+                                LYD_DUP_RECURSIVE | LYD_DUP_NO_META | LYD_DUP_WITH_PARENTS, &dup));
 
     /* find the first duplicated parent */
     if (!diff_parent) {
@@ -139,38 +139,36 @@
     assert(!strcmp(yang_mod->name, "yang"));
 
     /* add parent operation, if any */
-    if (diff_parent && (diff_parent != dup) && !lyd_new_meta(diff_parent, yang_mod, "operation", "none")) {
-        return LY_EMEM;
+    if (diff_parent && (diff_parent != dup)) {
+        LY_CHECK_RET(lyd_new_meta(diff_parent, yang_mod, "operation", "none", NULL));
     }
 
     /* add subtree operation */
-    if (!lyd_new_meta(dup, yang_mod, "operation", lyd_diff_op2str(op))) {
-        return LY_EMEM;
-    }
+    LY_CHECK_RET(lyd_new_meta(dup, yang_mod, "operation", lyd_diff_op2str(op), NULL));
 
     /* orig-default */
-    if (orig_default && !lyd_new_meta(dup, yang_mod, "orig-default", orig_default)) {
-        return LY_EMEM;
+    if (orig_default) {
+        LY_CHECK_RET(lyd_new_meta(dup, yang_mod, "orig-default", orig_default, NULL));
     }
 
     /* orig-value */
-    if (orig_value && !lyd_new_meta(dup, yang_mod, "orig-value", orig_value)) {
-        return LY_EMEM;
+    if (orig_value) {
+        LY_CHECK_RET(lyd_new_meta(dup, yang_mod, "orig-value", orig_value, NULL));
     }
 
     /* key */
-    if (key && !lyd_new_meta(dup, yang_mod, "key", key)) {
-        return LY_EMEM;
+    if (key) {
+        LY_CHECK_RET(lyd_new_meta(dup, yang_mod, "key", key, NULL));
     }
 
     /* value */
-    if (value && !lyd_new_meta(dup, yang_mod, "value", value)) {
-        return LY_EMEM;
+    if (value) {
+        LY_CHECK_RET(lyd_new_meta(dup, yang_mod, "value", value, NULL));
     }
 
     /* orig-key */
-    if (orig_key && !lyd_new_meta(dup, yang_mod, "orig-key", orig_key)) {
-        return LY_EMEM;
+    if (orig_key) {
+        LY_CHECK_RET(lyd_new_meta(dup, yang_mod, "orig-key", orig_key, NULL));
     }
 
     return LY_SUCCESS;
@@ -290,7 +288,7 @@
         if (lyd_compare(second, userord_item->inst[second_pos], 0)) {
             /* in first, there is a different instance on the second position, we are going to move 'first' node */
             *op = LYD_DIFF_OP_REPLACE;
-        } else if ((options & LYD_DIFF_WITHDEFAULTS) && ((first->flags & LYD_DEFAULT) != (second->flags & LYD_DEFAULT))) {
+        } else if ((options & LYD_DIFF_DEFAULTS) && ((first->flags & LYD_DEFAULT) != (second->flags & LYD_DEFAULT))) {
             /* default flag change */
             *op = LYD_DIFF_OP_NONE;
         } else {
@@ -304,7 +302,7 @@
      */
 
     /* orig-default */
-    if ((options & LYD_DIFF_WITHDEFAULTS) && (schema->nodetype == LYS_LEAFLIST)
+    if ((options & LYD_DIFF_DEFAULTS) && (schema->nodetype == LYS_LEAFLIST)
             && ((*op == LYD_DIFF_OP_REPLACE) || (*op == LYD_DIFF_OP_NONE))
             && ((first->flags & LYD_DEFAULT) != (second->flags & LYD_DEFAULT))) {
         if (first->flags & LYD_DEFAULT) {
@@ -440,7 +438,7 @@
             return LY_ENOT;
         case LYS_LIST:
         case LYS_LEAFLIST:
-            if ((options & LYD_DIFF_WITHDEFAULTS) && ((first->flags & LYD_DEFAULT) != (second->flags & LYD_DEFAULT))) {
+            if ((options & LYD_DIFF_DEFAULTS) && ((first->flags & LYD_DEFAULT) != (second->flags & LYD_DEFAULT))) {
                 /* default flag change */
                 *op = LYD_DIFF_OP_NONE;
             } else {
@@ -454,7 +452,7 @@
             if (lyd_compare(first, second, 0)) {
                 /* different values */
                 *op = LYD_DIFF_OP_REPLACE;
-            } else if ((options & LYD_DIFF_WITHDEFAULTS) && ((first->flags & LYD_DEFAULT) != (second->flags & LYD_DEFAULT))) {
+            } else if ((options & LYD_DIFF_DEFAULTS) && ((first->flags & LYD_DEFAULT) != (second->flags & LYD_DEFAULT))) {
                 /* default flag change */
                 *op = LYD_DIFF_OP_NONE;
             } else {
@@ -472,7 +470,7 @@
      */
 
     /* orig-default */
-    if ((options & LYD_DIFF_WITHDEFAULTS) && (schema->nodetype & LYD_NODE_TERM)
+    if ((options & LYD_DIFF_DEFAULTS) && (schema->nodetype & LYD_NODE_TERM)
             && ((*op == LYD_DIFF_OP_REPLACE) || (*op == LYD_DIFF_OP_NONE))
             && ((first->flags & LYD_DEFAULT) != (second->flags & LYD_DEFAULT))) {
         if (first->flags & LYD_DEFAULT) {
@@ -532,32 +530,27 @@
  * @param[in] first First tree first sibling.
  * @param[in] second Second tree first sibling.
  * @param[in] options Diff options.
+ * @param[in] nosiblings Whether to skip following siblings.
  * @param[in,out] diff Diff to append to.
  * @return LY_ERR value.
  */
 static LY_ERR
-lyd_diff_siblings_r(const struct lyd_node *first, const struct lyd_node *second, int options, struct lyd_node **diff)
+lyd_diff_siblings_r(const struct lyd_node *first, const struct lyd_node *second, int options, int nosiblings,
+                    struct lyd_node **diff)
 {
     LY_ERR ret = LY_SUCCESS;
     const struct lyd_node *iter_first, *iter_second;
     struct lyd_node *match_second, *match_first;
-    int nosiblings = 0;
     struct lyd_diff_userord *userord = NULL;
     LY_ARRAY_COUNT_TYPE u;
     enum lyd_diff_op op;
     const char *orig_default;
     char *orig_value, *key, *value, *orig_key;
 
-    if (options & LYD_DIFF_NOSIBLINGS) {
-        /* remember it for this function call only, should not be passed recursively */
-        nosiblings = 1;
-        options &= ~LYD_DIFF_NOSIBLINGS;
-    }
-
     /* compare first tree to the second tree - delete, replace, none */
     LY_LIST_FOR(first, iter_first) {
         assert(!(iter_first->schema->flags & LYS_KEY));
-        if ((iter_first->flags & LYD_DEFAULT) && !(options & LYD_DIFF_WITHDEFAULTS)) {
+        if ((iter_first->flags & LYD_DEFAULT) && !(options & LYD_DIFF_DEFAULTS)) {
             /* skip default nodes */
             continue;
         }
@@ -570,7 +563,7 @@
             lyd_find_sibling_val(second, iter_first->schema, NULL, 0, &match_second);
         }
 
-        if (match_second && (match_second->flags & LYD_DEFAULT) && !(options & LYD_DIFF_WITHDEFAULTS)) {
+        if (match_second && (match_second->flags & LYD_DEFAULT) && !(options & LYD_DIFF_DEFAULTS)) {
             /* ignore default nodes */
             match_second = NULL;
         }
@@ -617,7 +610,7 @@
 
         /* check descendants, if any, recursively */
         if (match_second) {
-            LY_CHECK_GOTO(lyd_diff_siblings_r(LYD_CHILD(iter_first), LYD_CHILD(match_second), options, diff), cleanup);
+            LY_CHECK_GOTO(lyd_diff_siblings_r(LYD_CHILD(iter_first), LYD_CHILD(match_second), options, 0, diff), cleanup);
         }
 
         if (nosiblings) {
@@ -633,7 +626,7 @@
     /* compare second tree to the first tree - create, user-ordered move */
     LY_LIST_FOR(second, iter_second) {
         assert(!(iter_second->schema->flags & LYS_KEY));
-        if ((iter_second->flags & LYD_DEFAULT) && !(options & LYD_DIFF_WITHDEFAULTS)) {
+        if ((iter_second->flags & LYD_DEFAULT) && !(options & LYD_DIFF_DEFAULTS)) {
             /* skip default nodes */
             continue;
         }
@@ -644,7 +637,7 @@
             lyd_find_sibling_val(first, iter_second->schema, NULL, 0, &match_first);
         }
 
-        if (match_first && (match_first->flags & LYD_DEFAULT) && !(options & LYD_DIFF_WITHDEFAULTS)) {
+        if (match_first && (match_first->flags & LYD_DEFAULT) && !(options & LYD_DIFF_DEFAULTS)) {
             /* ignore default nodes */
             match_first = NULL;
         }
@@ -693,8 +686,8 @@
     return ret;
 }
 
-API LY_ERR
-lyd_diff(const struct lyd_node *first, const struct lyd_node *second, int options, struct lyd_node **diff)
+static LY_ERR
+lyd_diff(const struct lyd_node *first, const struct lyd_node *second, int options, int nosiblings, struct lyd_node **diff)
 {
     const struct ly_ctx *ctx;
 
@@ -715,7 +708,19 @@
 
     *diff = NULL;
 
-    return lyd_diff_siblings_r(first, second, options, diff);
+    return lyd_diff_siblings_r(first, second, options, nosiblings, diff);
+}
+
+API LY_ERR
+lyd_diff_tree(const struct lyd_node *first, const struct lyd_node *second, int options, struct lyd_node **diff)
+{
+    return lyd_diff(first, second, options, 1, diff);
+}
+
+API LY_ERR
+lyd_diff_siblings(const struct lyd_node *first, const struct lyd_node *second, int options, struct lyd_node **diff)
+{
+    return lyd_diff(first, second, options, 0, diff);
 }
 
 /**
@@ -886,9 +891,8 @@
             /* find the node (we must have some siblings because the node was only moved) */
             lyd_diff_find_node(*first_node, diff_node, &match);
         } else {
-            /* duplicate the node(s) */
-            match = lyd_dup(diff_node, NULL, LYD_DUP_NO_META);
-            LY_CHECK_RET(!match, LY_EMEM);
+            /* duplicate the node */
+            LY_CHECK_RET(lyd_dup_single(diff_node, NULL, LYD_DUP_NO_META, &match));
         }
 
         /* get "key" or "value" metadata string value */
@@ -937,8 +941,7 @@
         break;
     case LYD_DIFF_OP_CREATE:
         /* duplicate the node */
-        match = lyd_dup(diff_node, NULL, LYD_DUP_NO_META);
-        LY_CHECK_RET(!match, LY_EMEM);
+        LY_CHECK_RET(lyd_dup_single(diff_node, NULL, LYD_DUP_NO_META, &match));
 
         /* insert it at the end */
         ret = 0;
@@ -1026,7 +1029,7 @@
 }
 
 API LY_ERR
-lyd_diff_apply(struct lyd_node **data, const struct lyd_node *diff)
+lyd_diff_apply_all(struct lyd_node **data, const struct lyd_node *diff)
 {
     return lyd_diff_apply_module(data, diff, NULL, NULL, NULL);
 }
@@ -1073,7 +1076,7 @@
 
     LY_LIST_FOR(node->meta, meta) {
         if (!strcmp(meta->name, name) && !strcmp(meta->annotation->module->name, "yang")) {
-            lyd_free_meta(LYD_NODE_CTX(node), meta, 0);
+            lyd_free_meta_single(meta);
             return;
         }
     }
@@ -1095,15 +1098,12 @@
 
     LY_LIST_FOR(node->meta, meta) {
         if (!strcmp(meta->name, "operation") && !strcmp(meta->annotation->module->name, "yang")) {
-            lyd_free_meta(LYD_NODE_CTX(node), meta, 0);
+            lyd_free_meta_single(meta);
             break;
         }
     }
 
-    if (!lyd_new_meta(node, NULL, "yang:operation", lyd_diff_op2str(op))) {
-        return LY_EINT;
-    }
-    return LY_SUCCESS;
+    return lyd_new_meta(node, NULL, "yang:operation", lyd_diff_op2str(op), NULL);
 }
 
 /**
@@ -1142,9 +1142,7 @@
             lyd_diff_del_meta(diff_match, meta_name);
             meta = lyd_find_meta(src_diff->meta, mod, meta_name);
             LY_CHECK_ERR_RET(!meta, LOGINT(LYD_NODE_CTX(src_diff)), LY_EINT);
-            if (!lyd_dup_meta(meta, diff_match)) {
-                return LY_EINT;
-            }
+            LY_CHECK_RET(lyd_dup_meta_single(meta, diff_match, NULL));
             break;
         case LYS_LEAF:
             /* replaced with the exact same value, impossible */
@@ -1175,7 +1173,7 @@
             }
             if (!ret) {
                 /* values are the same, remove orig-value meta and set oper to NONE */
-                lyd_free_meta(LYD_NODE_CTX(diff_match), meta, 0);
+                lyd_free_meta_single(meta);
                 LY_CHECK_RET(lyd_diff_change_op(diff_match, LYD_DIFF_OP_NONE));
             }
 
@@ -1208,15 +1206,11 @@
         /* set orig-key and key metadata */
         meta = lyd_find_meta(src_diff->meta, mod, "orig-key");
         LY_CHECK_ERR_RET(!meta, LOGINT(LYD_NODE_CTX(src_diff)), LY_EINT);
-        if (!lyd_dup_meta(meta, diff_match)) {
-            return LY_EINT;
-        }
+        LY_CHECK_RET(lyd_dup_meta_single(meta, diff_match, NULL));
 
         meta = lyd_find_meta(src_diff->meta, mod, "key");
         LY_CHECK_ERR_RET(!meta, LOGINT(LYD_NODE_CTX(src_diff)), LY_EINT);
-        if (!lyd_dup_meta(meta, diff_match)) {
-            return LY_EINT;
-        }
+        LY_CHECK_RET(lyd_dup_meta_single(meta, diff_match, NULL));
         break;
     default:
         /* delete operation is not valid */
@@ -1238,7 +1232,6 @@
 lyd_diff_merge_create(struct lyd_node *diff_match, enum lyd_diff_op cur_op, const struct lyd_node *src_diff)
 {
     struct lyd_node *child;
-    struct lyd_meta *meta;
     const char *str_val;
     int dynamic;
     LY_ERR ret;
@@ -1252,9 +1245,8 @@
 
             if (diff_match->schema->nodetype & LYD_NODE_TERM) {
                 /* add orig-dflt metadata */
-                if (!lyd_new_meta(diff_match, NULL, "yang:orig-default", diff_match->flags & LYD_DEFAULT ? "true" : "false")) {
-                    return LY_EINT;
-                }
+                LY_CHECK_RET(lyd_new_meta(diff_match, NULL, "yang:orig-default",
+                                          diff_match->flags & LYD_DEFAULT ? "true" : "false", NULL));
             }
         } else {
             assert(diff_match->schema->nodetype == LYS_LEAF);
@@ -1263,11 +1255,11 @@
 
             /* current value is the previous one (meta) */
             str_val = lyd_value2str((struct lyd_node_term *)diff_match, &dynamic);
-            meta = lyd_new_meta(diff_match, NULL, "yang:orig-value", str_val);
+            ret = lyd_new_meta(diff_match, NULL, "yang:orig-value", str_val, NULL);
             if (dynamic) {
                 free((char *)str_val);
             }
-            LY_CHECK_RET(!meta, LY_EINT);
+            LY_CHECK_RET(ret);
 
             /* update the value itself */
             str_val = lyd_value2str((struct lyd_node_term *)src_diff, &dynamic);
@@ -1320,9 +1312,8 @@
 
         if (diff_match->schema->nodetype & LYD_NODE_TERM) {
             /* add orig-default meta because it is expected */
-            if (!lyd_new_meta(diff_match, NULL, "yang:orig-default", diff_match->flags & LYD_DEFAULT ? "true" : "false")) {
-                return LY_EINT;
-            }
+            LY_CHECK_RET(lyd_new_meta(diff_match, NULL, "yang:orig-default",
+                                      diff_match->flags & LYD_DEFAULT ? "true" : "false", NULL));
         } else {
             /* keep operation for all descendants (for now) */
             LY_LIST_FOR(LYD_CHILD(diff_match), child) {
@@ -1384,8 +1375,8 @@
 
         if (!lyd_compare_meta(orig_val_meta, val_meta)) {
             /* there is actually no move */
-            lyd_free_meta(LYD_NODE_CTX(diff), orig_val_meta, 0);
-            lyd_free_meta(LYD_NODE_CTX(diff), val_meta, 0);
+            lyd_free_meta_single(orig_val_meta);
+            lyd_free_meta_single(val_meta);
             if (child) {
                 /* change operation to NONE, we have siblings */
                 lyd_diff_change_op(diff, LYD_DIFF_OP_NONE);
@@ -1486,8 +1477,7 @@
         }
     } else {
         /* add new diff node with all descendants */
-        diff_node = lyd_dup(src_diff, (struct lyd_node_inner *)diff_parent, LYD_DUP_RECURSIVE);
-        LY_CHECK_RET(!diff_node, LY_EINT);
+        LY_CHECK_RET(lyd_dup_single(src_diff, (struct lyd_node_inner *)diff_parent, LYD_DUP_RECURSIVE, &diff_node));
 
         /* insert node into diff if not already */
         if (!diff_parent) {
@@ -1541,7 +1531,7 @@
 }
 
 API LY_ERR
-lyd_diff_merge(const struct lyd_node *src_diff, struct lyd_node **diff)
+lyd_diff_merge_all(const struct lyd_node *src_diff, struct lyd_node **diff)
 {
     return lyd_diff_merge_module(src_diff, NULL, NULL, NULL, diff);
 }
@@ -1662,8 +1652,7 @@
     }
 
     /* duplicate diff */
-    *diff = lyd_dup(src_diff, NULL, LYD_DUP_WITH_SIBLINGS | LYD_DUP_RECURSIVE);
-    LY_CHECK_RET(!*diff, LY_EMEM);
+    LY_CHECK_RET(lyd_dup_siblings(src_diff, NULL, LYD_DUP_RECURSIVE, diff));
 
     /* find module with metadata needed for later */
     mod = ly_ctx_get_module_latest(LYD_NODE_CTX(src_diff), "yang");
diff --git a/src/parser_data.h b/src/parser_data.h
index 7bf68b2..a8ec4d5 100644
--- a/src/parser_data.h
+++ b/src/parser_data.h
@@ -131,7 +131,8 @@
  * @return LY_SUCCESS in case of successful parsing (and validation).
  * @return LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
  */
-LY_ERR lyd_parse_data(const struct ly_ctx *ctx, struct ly_in *in, LYD_FORMAT format, int parse_options, int validate_options, struct lyd_node **tree);
+LY_ERR lyd_parse_data(const struct ly_ctx *ctx, struct ly_in *in, LYD_FORMAT format, int parse_options,
+                      int validate_options, struct lyd_node **tree);
 
 /**
  * @brief Parse (and validate) input data as a YANG data tree.
@@ -148,7 +149,8 @@
  * @return LY_SUCCESS in case of successful parsing (and validation).
  * @return LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
  */
-LY_ERR lyd_parse_data_mem(const struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int parse_options, int validate_options, struct lyd_node **tree);
+LY_ERR lyd_parse_data_mem(const struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int parse_options,
+                          int validate_options, struct lyd_node **tree);
 
 /**
  * @brief Parse (and validate) input data as a YANG data tree.
@@ -165,7 +167,8 @@
  * @return LY_SUCCESS in case of successful parsing (and validation).
  * @return LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
  */
-LY_ERR lyd_parse_data_fd(const struct ly_ctx *ctx, int fd, LYD_FORMAT format, int parse_options, int validate_options, struct lyd_node **tree);
+LY_ERR lyd_parse_data_fd(const struct ly_ctx *ctx, int fd, LYD_FORMAT format, int parse_options, int validate_options,
+                         struct lyd_node **tree);
 
 /**
  * @brief Parse (and validate) input data as a YANG data tree.
@@ -182,7 +185,8 @@
  * @return LY_SUCCESS in case of successful parsing (and validation).
  * @return LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
  */
-LY_ERR lyd_parse_data_path(const struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int parse_options, int validate_options, struct lyd_node **tree);
+LY_ERR lyd_parse_data_path(const struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int parse_options,
+                           int validate_options, struct lyd_node **tree);
 
 /**
  * @brief Parse (and validate) data from the input handler as a YANG RPC/action invocation.
@@ -201,7 +205,8 @@
  * @return LY_SUCCESS in case of successful parsing (and validation).
  * @return LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
  */
-LY_ERR lyd_parse_rpc(const struct ly_ctx *ctx, struct ly_in *in, LYD_FORMAT format, struct lyd_node **tree, struct lyd_node **op);
+LY_ERR lyd_parse_rpc(const struct ly_ctx *ctx, struct ly_in *in, LYD_FORMAT format, struct lyd_node **tree,
+                     struct lyd_node **op);
 
 /**
  * @brief Parse (and validate) data from the input handler as a YANG RPC/action reply.
@@ -221,7 +226,8 @@
  * @return LY_SUCCESS in case of successful parsing (and validation).
  * @return LY_ERR value in case of error. Additional error information can be obtained from the request's context using ly_err* functions.
  */
-LY_ERR lyd_parse_reply(const struct lyd_node *request, struct ly_in *in, LYD_FORMAT format, struct lyd_node **tree, struct lyd_node **op);
+LY_ERR lyd_parse_reply(const struct lyd_node *request, struct ly_in *in, LYD_FORMAT format, struct lyd_node **tree,
+                       struct lyd_node **op);
 
 /**
  * @brief Parse XML string as YANG notification.
@@ -238,7 +244,8 @@
  * @return LY_SUCCESS in case of successful parsing (and validation).
  * @return LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
  */
-LY_ERR lyd_parse_notif(const struct ly_ctx *ctx, struct ly_in *in, LYD_FORMAT format, struct lyd_node **tree, struct lyd_node **ntf);
+LY_ERR lyd_parse_notif(const struct ly_ctx *ctx, struct ly_in *in, LYD_FORMAT format, struct lyd_node **tree,
+                       struct lyd_node **ntf);
 
 /**
  * @brief Fully validate a data tree.
@@ -250,7 +257,7 @@
  * @return LY_SUCCESS on success.
  * @return LY_ERR error on error.
  */
-LY_ERR lyd_validate(struct lyd_node **tree, const struct ly_ctx *ctx, int val_opts, struct lyd_node **diff);
+LY_ERR lyd_validate_all(struct lyd_node **tree, const struct ly_ctx *ctx, int val_opts, struct lyd_node **diff);
 
 /**
  * @brief Fully validate a data tree of a module.
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index 1965afb..95ff05a 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -379,7 +379,7 @@
 cleanup:
     free(meta_name);
     if (ret) {
-        lyd_free_meta(lybctx->ctx, *meta, 1);
+        lyd_free_meta_siblings(*meta);
         *meta = NULL;
     }
     return ret;
@@ -518,7 +518,7 @@
     }
     ly_free_val_prefs(lybctx->ctx, val_prefs);
     if (ret) {
-        ly_free_attr(lybctx->ctx, *attr, 1);
+        ly_free_attr_siblings(lybctx->ctx, *attr);
         *attr = NULL;
     }
     return ret;
@@ -910,8 +910,8 @@
     }
     ly_free_val_prefs(lybctx->ctx, val_prefs);
 
-    lyd_free_meta(lybctx->ctx, meta, 1);
-    ly_free_attr(lybctx->ctx, attr, 1);
+    lyd_free_meta_siblings(meta);
+    ly_free_attr_siblings(lybctx->ctx, attr);
     lyd_free_tree(node);
     return ret;
 }
@@ -1208,8 +1208,8 @@
     }
 
     /* duplicate request OP with parents */
-    rep_op = lyd_dup(req_op, NULL, LYD_DUP_WITH_PARENTS);
-    LY_CHECK_ERR_GOTO(!rep_op, ret = LY_EMEM, cleanup);
+    ret = lyd_dup_single(req_op, NULL, LYD_DUP_WITH_PARENTS, &rep_op);
+    LY_CHECK_GOTO(ret, cleanup);
 
     /* read magic number */
     ret = lyb_parse_magic_number(&lybctx);
diff --git a/src/parser_schema.h b/src/parser_schema.h
index 82bdd9b..9e3985a 100644
--- a/src/parser_schema.h
+++ b/src/parser_schema.h
@@ -20,6 +20,7 @@
 #endif
 
 struct ly_in;
+struct lys_module;
 
 /**
  * @addtogroup schematree
@@ -41,9 +42,10 @@
  * @param[in] ctx libyang context where to process the data model.
  * @param[in] in The input handle to provide the dumped data model in the specified format.
  * @param[in] format Format of the schema to parse.
- * @return Pointer to the data model structure or NULL on error.
+ * @param[out] module Optional parsed module.
+ * @return LY_ERR value.
  */
-struct lys_module *lys_parse(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format);
+LY_ERR lys_parse(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, const struct lys_module **module);
 
 /**
  * @brief Load a schema into the specified context.
@@ -52,12 +54,12 @@
  * consider use of lys_parse() with a standalone input handler.
  *
  * @param[in] ctx libyang context where to process the data model.
- * @param[in] data The string containing the dumped data model in the specified
- * format.
+ * @param[in] data The string containing the dumped data model in the specified format.
  * @param[in] format Format of the input data (YANG or YIN).
- * @return Pointer to the data model structure or NULL on error.
+ * @param[out] module Optional parsed module.
+ * @return LY_ERR value.
  */
-struct lys_module *lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format);
+LY_ERR lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, const struct lys_module **module);
 
 /**
  * @brief Read a schema from file descriptor into the specified context.
@@ -71,9 +73,10 @@
  * @param[in] fd File descriptor of a regular file (e.g. sockets are not supported) containing the schema
  *            in the specified format.
  * @param[in] format Format of the input data (YANG or YIN).
- * @return Pointer to the data model structure or NULL on error.
+ * @param[out] module Optional parsed module.
+ * @return LY_ERR value.
  */
-struct lys_module *lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format);
+LY_ERR lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, const struct lys_module **module);
 
 /**
  * @brief Load a schema into the specified context from a file.
@@ -84,9 +87,10 @@
  * @param[in] ctx libyang context where to process the data model.
  * @param[in] path Path to the file with the model in the specified format.
  * @param[in] format Format of the input data (YANG or YIN).
- * @return Pointer to the data model structure or NULL on error.
+ * @param[out] module Optional parsed module.
+ * @return LY_ERR value.
  */
-struct lys_module *lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format);
+LY_ERR lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, const struct lys_module **module);
 
 /**
  * @brief Search for the schema file in the specified searchpaths.
@@ -103,7 +107,8 @@
  * file suffix.
  * @return LY_ERR value (LY_SUCCESS is returned even if the file is not found, then the *localfile is NULL).
  */
-LY_ERR lys_search_localfile(const char * const *searchpaths, int cwd, const char *name, const char *revision, char **localfile, LYS_INFORMAT *format);
+LY_ERR lys_search_localfile(const char * const *searchpaths, int cwd, const char *name, const char *revision,
+                            char **localfile, LYS_INFORMAT *format);
 
 /** @} schematree */
 
diff --git a/src/parser_xml.c b/src/parser_xml.c
index c382a78..eb73a8f 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -139,7 +139,7 @@
 
 cleanup:
     if (ret) {
-        lyd_free_meta(xmlctx->ctx, *meta, 1);
+        lyd_free_meta_siblings(*meta);
         *meta = NULL;
     }
     return ret;
@@ -203,7 +203,7 @@
 
 cleanup:
     if (ret) {
-        ly_free_attr(xmlctx->ctx, *attr, 1);
+        ly_free_attr_siblings(xmlctx->ctx, *attr);
         *attr = NULL;
     }
     return ret;
@@ -662,8 +662,8 @@
     ret = LY_SUCCESS;
 
 cleanup:
-    lyd_free_meta(ctx, meta, 1);
-    ly_free_attr(ctx, attr, 1);
+    lyd_free_meta_siblings(meta);
+    ly_free_attr_siblings(ctx, attr);
     lyd_free_tree(cur);
     if (ret && *first) {
         lyd_free_siblings(*first);
@@ -799,7 +799,7 @@
     attr = NULL;
 
 cleanup:
-    ly_free_attr(xmlctx->ctx, attr, 1);
+    ly_free_attr_siblings(xmlctx->ctx, attr);
     return ret;
 }
 
@@ -982,7 +982,7 @@
 cleanup:
     if (ret) {
         lyd_free_tree(*envp);
-        ly_free_attr(xmlctx->ctx, attr, 1);
+        ly_free_attr_siblings(xmlctx->ctx, attr);
     }
     return ret;
 }
@@ -1080,11 +1080,11 @@
     }
 
     /* duplicate request OP with parents */
-    rep_op = lyd_dup(req_op, NULL, LYD_DUP_WITH_PARENTS);
-    LY_CHECK_ERR_GOTO(!rep_op, ret = LY_EMEM, cleanup);
+    LY_CHECK_GOTO(ret = lyd_dup_single(req_op, NULL, LYD_DUP_WITH_PARENTS, &rep_op), cleanup);
 
     /* parse "rpc-reply", if any */
-    LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpcr_e), cleanup);
+    LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpcr_e),
+                  cleanup);
 
     /* parse the rest of data normally but connect them to the duplicated operation */
     LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, (struct lyd_node_inner *)rep_op, lyd_node_children_p(rep_op)), cleanup);
diff --git a/src/path.c b/src/path.c
index f4829e3..eb72c2f 100644
--- a/src/path.c
+++ b/src/path.c
@@ -424,7 +424,7 @@
             key = lys_find_child(ctx_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
             if (!key) {
                 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
-                return LY_EVALID;
+                return LY_ENOTFOUND;
             } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
                 LOGVAL(ctx, LY_VLOG_LYSC, key, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
                        lys_nodetype2str(key->nodetype), key->name);
diff --git a/src/printer_data.c b/src/printer_data.c
index bbb2eda..3d78d3b 100644
--- a/src/printer_data.c
+++ b/src/printer_data.c
@@ -23,15 +23,10 @@
 #include "printer_internal.h"
 #include "tree_data.h"
 
-API LY_ERR
-lyd_print(struct ly_out *out, const struct lyd_node *root, LYD_FORMAT format, int options)
+static LY_ERR
+lyd_print_(struct ly_out *out, const struct lyd_node *root, LYD_FORMAT format, int options)
 {
-    LY_ERR ret = LY_EINVAL;
-
-    LY_CHECK_ARG_RET(NULL, out, root, LY_EINVAL);
-
-    /* reset number of printed bytes */
-    out->func_printed = 0;
+    LY_ERR ret = LY_SUCCESS;
 
     switch (format) {
     case LYD_XML:
@@ -54,22 +49,46 @@
     return ret;
 }
 
-static LY_ERR
-lyd_print_(struct ly_out *out, const struct lyd_node *root, LYD_FORMAT format, int options)
+API LY_ERR
+lyd_print_all(struct ly_out *out, const struct lyd_node *root, LYD_FORMAT format, int options)
 {
-    LY_ERR ret;
+    LY_CHECK_ARG_RET(NULL, out, root, !(options & LYD_PRINT_WITHSIBLINGS), LY_EINVAL);
 
-    LY_CHECK_ARG_RET(NULL, out, LY_EINVAL);
+    /* reset the number of printed bytes */
+    out->func_printed = 0;
 
-    ret = lyd_print(out, root, format, options);
+    /* get first top-level sibling */
+    while (root->parent) {
+        root = (struct lyd_node *)root->parent;
+    }
+    while (root->prev->next) {
+        root = root->prev;
+    }
 
-    ly_out_free(out, NULL, 0);
-    return ret;
+    /* print each top-level sibling */
+    LY_CHECK_RET(lyd_print_(out, root, format, options | LYD_PRINT_WITHSIBLINGS));
+
+    return LY_SUCCESS;
+}
+
+API LY_ERR
+lyd_print_tree(struct ly_out *out, const struct lyd_node *root, LYD_FORMAT format, int options)
+{
+    LY_CHECK_ARG_RET(NULL, out, root, !(options & LYD_PRINT_WITHSIBLINGS), LY_EINVAL);
+
+    /* reset the number of printed bytes */
+    out->func_printed = 0;
+
+    /* print the subtree */
+    LY_CHECK_RET(lyd_print_(out, root, format, options));
+
+    return LY_SUCCESS;
 }
 
 API LY_ERR
 lyd_print_mem(char **strp, const struct lyd_node *root, LYD_FORMAT format, int options)
 {
+    LY_ERR ret;
     struct ly_out *out;
 
     LY_CHECK_ARG_RET(NULL, strp, root, LY_EINVAL);
@@ -78,50 +97,64 @@
     *strp = NULL;
 
     LY_CHECK_RET(ly_out_new_memory(strp, 0, &out));
-    return lyd_print_(out, root, format, options);
+    ret = lyd_print_(out, root, format, options);
+    ly_out_free(out, NULL, 0);
+    return ret;
 }
 
 API LY_ERR
 lyd_print_fd(int fd, const struct lyd_node *root, LYD_FORMAT format, int options)
 {
+    LY_ERR ret;
     struct ly_out *out;
 
     LY_CHECK_ARG_RET(NULL, fd != -1, root, LY_EINVAL);
 
     LY_CHECK_RET(ly_out_new_fd(fd, &out));
-    return lyd_print_(out, root, format, options);
+    ret = lyd_print_(out, root, format, options);
+    ly_out_free(out, NULL, 0);
+    return ret;
 }
 
 API LY_ERR
 lyd_print_file(FILE *f, const struct lyd_node *root, LYD_FORMAT format, int options)
 {
+    LY_ERR ret;
     struct ly_out *out;
 
     LY_CHECK_ARG_RET(NULL, f, root, LY_EINVAL);
 
     LY_CHECK_RET(ly_out_new_file(f, &out));
-    return lyd_print_(out, root, format, options);
+    ret = lyd_print_(out, root, format, options);
+    ly_out_free(out, NULL, 0);
+    return ret;
 }
 
 API LY_ERR
 lyd_print_path(const char *path, const struct lyd_node *root, LYD_FORMAT format, int options)
 {
+    LY_ERR ret;
     struct ly_out *out;
 
     LY_CHECK_ARG_RET(NULL, path, root, LY_EINVAL);
 
     LY_CHECK_RET(ly_out_new_filepath(path, &out));
-    return lyd_print_(out, root, format, options);
+    ret = lyd_print_(out, root, format, options);
+    ly_out_free(out, NULL, 0);
+    return ret;
 }
 
 API LY_ERR
 lyd_print_clb(ssize_t (*writeclb)(void *arg, const void *buf, size_t count), void *arg,
               const struct lyd_node *root, LYD_FORMAT format, int options)
 {
+    LY_ERR ret;
     struct ly_out *out;
 
     LY_CHECK_ARG_RET(NULL, writeclb, root, LY_EINVAL);
 
     LY_CHECK_RET(ly_out_new_clb(writeclb, arg, &out));
-    return lyd_print_(out, root, format, options);
+    ret = lyd_print_(out, root, format, options);
+    ly_out_free(out, NULL, 0);
+    return ret;
 }
diff --git a/src/printer_data.h b/src/printer_data.h
index afe0418..09fe8f5 100644
--- a/src/printer_data.h
+++ b/src/printer_data.h
@@ -57,15 +57,26 @@
  */
 
 /**
- * @brief Common YANG data printer.
+ * @brief Print the whole data tree of the root, including all the siblings.
  *
  * @param[in] out Printer handler for a specific output. Use ly_out_*() functions to create and free the handler.
- * @param[in] root The root element of the (sub)tree to print.
+ * @param[in] root The root element of the tree to print, can be any sibling.
  * @param[in] format Output format.
- * @param[in] options [Data printer flags](@ref dataprinterflags).
+ * @param[in] options [Data printer flags](@ref dataprinterflags) except ::LYD_PRINT_WITHSIBLINGS.
  * @return LY_ERR value.
  */
-LY_ERR lyd_print(struct ly_out *out, const struct lyd_node *root, LYD_FORMAT format, int options);
+LY_ERR lyd_print_all(struct ly_out *out, const struct lyd_node *root, LYD_FORMAT format, int options);
+
+/**
+ * @brief Print the selected data subtree.
+ *
+ * @param[in] out Printer handler for a specific output. Use ly_out_*() functions to create and free the handler.
+ * @param[in] root The root element of the subtree to print.
+ * @param[in] format Output format.
+ * @param[in] options [Data printer flags](@ref dataprinterflags) except ::LYD_PRINT_WITHSIBLINGS.
+ * @return LY_ERR value.
+ */
+LY_ERR lyd_print_tree(struct ly_out *out, const struct lyd_node *root, LYD_FORMAT format, int options);
 
 /**
  * @brief Print data tree in the specified format.
diff --git a/src/tree_data.c b/src/tree_data.c
index 3b7e1a3..7780c97 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -657,30 +657,36 @@
     return LY_SUCCESS;
 }
 
-API struct lyd_node *
-lyd_new_inner(struct lyd_node *parent, const struct lys_module *module, const char *name)
+API LY_ERR
+lyd_new_inner(struct lyd_node *parent, const struct lys_module *module, const char *name, struct lyd_node **node)
 {
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
 
-    LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
+    LY_CHECK_ARG_RET(ctx, parent || module, name, LY_EINVAL);
 
     if (!module) {
         module = parent->schema->module;
     }
 
-    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_CONTAINER | LYS_NOTIF | LYS_RPC | LYS_ACTION, 0);
-    LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Inner node (and not a list) \"%s\" not found.", name), NULL);
+    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0,
+                            LYS_CONTAINER | LYS_NOTIF | LYS_RPC | LYS_ACTION, 0);
+    LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Inner node (and not a list) \"%s\" not found.", name), LY_ENOTFOUND);
 
-    if (!lyd_create_inner(schema, &ret) && parent) {
+    LY_CHECK_RET(lyd_create_inner(schema, &ret));
+    if (parent) {
         lyd_insert_node(parent, NULL, ret);
     }
-    return ret;
+
+    if (node) {
+        *node = ret;
+    }
+    return LY_SUCCESS;
 }
 
-API struct lyd_node *
-lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, ...)
+API LY_ERR
+lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, struct lyd_node **node, ...)
 {
     struct lyd_node *ret = NULL, *key;
     const struct lysc_node *schema, *key_s;
@@ -689,19 +695,19 @@
     const char *key_val;
     LY_ERR rc = LY_SUCCESS;
 
-    LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
+    LY_CHECK_ARG_RET(ctx, parent || module, name, LY_EINVAL);
 
     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);
+    LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), LY_ENOTFOUND);
 
     /* create list inner node */
-    LY_CHECK_RET(lyd_create_inner(schema, &ret), NULL);
+    LY_CHECK_RET(lyd_create_inner(schema, &ret));
 
-    va_start(ap, name);
+    va_start(ap, node);
 
     /* create and insert all the keys */
     for (key_s = lysc_node_children(schema, 0); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
@@ -713,30 +719,30 @@
         lyd_insert_node(ret, NULL, key);
     }
 
-    /* hash having all the keys */
-    lyd_hash(ret);
-
     if (parent) {
         lyd_insert_node(parent, NULL, ret);
     }
 
 cleanup:
+    va_end(ap);
     if (rc) {
         lyd_free_tree(ret);
         ret = NULL;
+    } else if (node) {
+        *node = ret;
     }
-    va_end(ap);
-    return ret;
+    return rc;
 }
 
-API struct lyd_node *
-lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *keys)
+API LY_ERR
+lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *keys,
+              struct lyd_node **node)
 {
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
 
-    LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
+    LY_CHECK_ARG_RET(ctx, parent || module, name, LY_EINVAL);
 
     if (!module) {
         module = parent->schema->module;
@@ -747,69 +753,81 @@
 
     /* find schema node */
     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);
+    LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), LY_ENOTFOUND);
 
     if ((schema->flags & LYS_KEYLESS) && !keys[0]) {
         /* key-less list */
-        LY_CHECK_RET(lyd_create_inner(schema, &ret), NULL);
+        LY_CHECK_RET(lyd_create_inner(schema, &ret));
     } else {
         /* create the list node */
-        LY_CHECK_RET(lyd_create_list2(schema, keys, strlen(keys), &ret), NULL);
+        LY_CHECK_RET(lyd_create_list2(schema, keys, strlen(keys), &ret));
     }
-
     if (parent) {
         lyd_insert_node(parent, NULL, ret);
     }
-    return ret;
+
+    if (node) {
+        *node = ret;
+    }
+    return LY_SUCCESS;
 }
 
-API struct lyd_node *
-lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str)
+API LY_ERR
+lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str,
+             struct lyd_node **node)
 {
     LY_ERR rc;
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
 
-    LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
+    LY_CHECK_ARG_RET(ctx, parent || module, name, LY_EINVAL);
 
     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);
+    LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Term node \"%s\" not found.", name), LY_ENOTFOUND);
 
     rc = lyd_create_term(schema, val_str, val_str ? strlen(val_str) : 0, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &ret);
-    LY_CHECK_RET(rc && (rc != LY_EINCOMPLETE), NULL);
-
+    LY_CHECK_RET(rc && (rc != LY_EINCOMPLETE), rc);
     if (parent) {
         lyd_insert_node(parent, NULL, ret);
     }
-    return ret;
+
+    if (node) {
+        *node = ret;
+    }
+    return LY_SUCCESS;
 }
 
-API struct lyd_node *
+API LY_ERR
 lyd_new_any(struct lyd_node *parent, const struct lys_module *module, const char *name, const void *value,
-            LYD_ANYDATA_VALUETYPE value_type)
+            LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node)
 {
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
 
-    LY_CHECK_ARG_RET(ctx, parent || module, name, NULL);
+    LY_CHECK_ARG_RET(ctx, parent || module, name, LY_EINVAL);
 
     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);
+    LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Any node \"%s\" not found.", name), LY_ENOTFOUND);
 
-    if (!lyd_create_any(schema, value, value_type, &ret) && parent) {
+    LY_CHECK_RET(lyd_create_any(schema, value, value_type, &ret));
+    if (parent) {
         lyd_insert_node(parent, NULL, ret);
     }
-    return ret;
+
+    if (node) {
+        *node = ret;
+    }
+    return LY_SUCCESS;
 }
 
 /**
@@ -885,8 +903,9 @@
     return ret;
 }
 
-API struct lyd_meta *
-lyd_new_meta(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str)
+API LY_ERR
+lyd_new_meta(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str,
+             struct lyd_meta **meta)
 {
     struct lyd_meta *ret = NULL;
     const struct ly_ctx *ctx;
@@ -894,7 +913,7 @@
     char *str;
     size_t pref_len, name_len;
 
-    LY_CHECK_ARG_RET(NULL, parent, name, module || strchr(name, ':'), NULL);
+    LY_CHECK_ARG_RET(NULL, parent, name, module || strchr(name, ':'), LY_EINVAL);
 
     ctx = LYD_NODE_CTX(parent);
 
@@ -902,7 +921,7 @@
     tmp = name;
     if (ly_parse_nodeid(&tmp, &prefix, &pref_len, &name, &name_len) || tmp[0]) {
         LOGERR(ctx, LY_EINVAL, "Metadata name \"%s\" is not valid.", name);
-        return NULL;
+        return LY_EVALID;
     }
 
     /* find the module */
@@ -910,7 +929,7 @@
         str = strndup(prefix, pref_len);
         module = ly_ctx_get_module_implemented(ctx, str);
         free(str);
-        LY_CHECK_ERR_RET(!module, LOGERR(ctx, LY_EINVAL, "Module \"%.*s\" not found.", pref_len, prefix), NULL);
+        LY_CHECK_ERR_RET(!module, LOGERR(ctx, LY_EINVAL, "Module \"%.*s\" not found.", pref_len, prefix), LY_ENOTFOUND);
     }
 
     /* set value if none */
@@ -918,18 +937,22 @@
         val_str = "";
     }
 
-    lyd_create_meta(parent, &ret, module, name, name_len, val_str, strlen(val_str), NULL, lydjson_resolve_prefix, NULL,
-                    LYD_JSON, parent->schema);
-    return ret;
+    LY_CHECK_RET(lyd_create_meta(parent, &ret, module, name, name_len, val_str, strlen(val_str), NULL,
+                                 lydjson_resolve_prefix, NULL, LYD_JSON, parent->schema));
+
+    if (meta) {
+        *meta = ret;
+    }
+    return LY_SUCCESS;
 }
 
-API struct lyd_node *
+API LY_ERR
 lyd_new_opaq(struct lyd_node *parent, const struct ly_ctx *ctx, const char *name, const char *value,
-             const char *module_name)
+             const char *module_name, struct lyd_node **node)
 {
     struct lyd_node *ret = NULL;
 
-    LY_CHECK_ARG_RET(ctx, parent || ctx, name, module_name, NULL);
+    LY_CHECK_ARG_RET(ctx, parent || ctx, name, module_name, LY_EINVAL);
 
     if (!ctx) {
         ctx = LYD_NODE_CTX(parent);
@@ -938,22 +961,28 @@
         value = "";
     }
 
-    if (!lyd_create_opaq(ctx, name, strlen(name), value, strlen(value), NULL, LYD_JSON, NULL, NULL, 0, module_name, &ret)
-            && parent) {
+    LY_CHECK_RET(lyd_create_opaq(ctx, name, strlen(name), value, strlen(value), NULL, LYD_JSON, NULL, NULL, 0,
+                                 module_name, &ret));
+    if (parent) {
         lyd_insert_node(parent, NULL, ret);
     }
-    return ret;
+
+    if (node) {
+        *node = ret;
+    }
+    return LY_SUCCESS;
 }
 
-API struct ly_attr *
-lyd_new_attr(struct lyd_node *parent, const char *module_name, const char *name, const char *val_str)
+API LY_ERR
+lyd_new_attr(struct lyd_node *parent, const char *module_name, const char *name, const char *val_str,
+             struct ly_attr **attr)
 {
     struct ly_attr *ret = NULL;
     const struct ly_ctx *ctx;
     const char *prefix, *tmp;
     size_t pref_len, name_len;
 
-    LY_CHECK_ARG_RET(NULL, parent, !parent->schema, name, NULL);
+    LY_CHECK_ARG_RET(NULL, parent, !parent->schema, name, LY_EINVAL);
 
     ctx = LYD_NODE_CTX(parent);
 
@@ -961,7 +990,7 @@
     tmp = name;
     if (ly_parse_nodeid(&tmp, &prefix, &pref_len, &name, &name_len) || tmp[0]) {
         LOGERR(ctx, LY_EINVAL, "Metadata name \"%s\" is not valid.", name);
-        return NULL;
+        return LY_EVALID;
     }
 
     /* set value if none */
@@ -969,9 +998,13 @@
         val_str = "";
     }
 
-    ly_create_attr(parent, &ret, ctx, name, name_len, val_str, strlen(val_str), NULL, LYD_JSON, NULL, prefix,
-                   pref_len, module_name);
-    return ret;
+    LY_CHECK_RET(ly_create_attr(parent, &ret, ctx, name, name_len, val_str, strlen(val_str), NULL, LYD_JSON, NULL,
+                                prefix, pref_len, module_name));
+
+    if (attr) {
+        *attr = ret;
+    }
+    return LY_SUCCESS;
 }
 
 API LY_ERR
@@ -1092,23 +1125,11 @@
     return ret;
 }
 
-API struct lyd_node *
-lyd_new_path(struct lyd_node *parent, const struct ly_ctx *ctx, const char *path, const char *value, int options)
+API LY_ERR
+lyd_new_path(struct lyd_node *parent, const struct ly_ctx *ctx, const char *path, const char *value, int options,
+             struct lyd_node **node)
 {
-    struct lyd_node *new_parent = NULL;
-
-    lyd_new_path2(parent, ctx, path, value, 0, options, &new_parent, NULL);
-    return new_parent;
-}
-
-API struct lyd_node *
-lyd_new_path_any(struct lyd_node *parent, const struct ly_ctx *ctx, const char *path, const void *value,
-                 LYD_ANYDATA_VALUETYPE value_type, int options)
-{
-    struct lyd_node *new_parent = NULL;
-
-    lyd_new_path2(parent, ctx, path, value, value_type, options, &new_parent, NULL);
-    return new_parent;
+    return lyd_new_path2(parent, ctx, path, value, 0, options, node, NULL);
 }
 
 API LY_ERR
@@ -2106,8 +2127,8 @@
  * @return LY_ERR value
  */
 static LY_ERR
-lyd_dup_recursive(const struct lyd_node *node, struct lyd_node *parent, struct lyd_node **first, int options,
-                  struct lyd_node **dup_p)
+lyd_dup_r(const struct lyd_node *node, struct lyd_node *parent, struct lyd_node **first, int options,
+          struct lyd_node **dup_p)
 {
     LY_ERR ret;
     struct lyd_node *dup = NULL;
@@ -2155,10 +2176,7 @@
     /* duplicate metadata */
     if (!(options & LYD_DUP_NO_META)) {
         LY_LIST_FOR(node->meta, meta) {
-            if (!lyd_dup_meta(meta, dup)) {
-                ret = LY_EINT;
-                goto error;
-            }
+            LY_CHECK_GOTO(ret = lyd_dup_meta_single(meta, dup, NULL), error);
         }
     }
 
@@ -2171,7 +2189,7 @@
         if (options & LYD_DUP_RECURSIVE) {
             /* duplicate all the children */
             LY_LIST_FOR(orig->child, child) {
-                LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
+                LY_CHECK_GOTO(ret = lyd_dup_r(child, dup, NULL, options, NULL), error);
             }
         }
         opaq->name = lydict_insert(LYD_NODE_CTX(node), orig->name, 0);
@@ -2207,7 +2225,7 @@
         if (options & LYD_DUP_RECURSIVE) {
             /* duplicate all the children */
             LY_LIST_FOR(orig->child, child) {
-                LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
+                LY_CHECK_GOTO(ret = lyd_dup_r(child, dup, NULL, options, NULL), error);
             }
         } else if (dup->schema->nodetype == LYS_LIST && !(dup->schema->flags & LYS_KEYLESS)) {
             /* always duplicate keys of a list */
@@ -2223,7 +2241,7 @@
                      * but there can be also some non-key nodes */
                     continue;
                 }
-                LY_CHECK_GOTO(ret = lyd_dup_recursive(child, dup, NULL, options, NULL), error);
+                LY_CHECK_GOTO(ret = lyd_dup_r(child, dup, NULL, options, NULL), error);
                 child = child->next;
             }
         }
@@ -2247,86 +2265,92 @@
     return ret;
 }
 
-API struct lyd_node *
-lyd_dup(const struct lyd_node *node, struct lyd_node_inner *parent, int options)
+static LY_ERR
+lyd_dup_get_local_parent(const struct lyd_node *node, const struct lyd_node_inner *parent, struct lyd_node **dup_parent,
+                         struct lyd_node_inner **local_parent)
 {
+    const struct lyd_node_inner *orig_parent, *iter;
+    int repeat = 1;
+
+    *dup_parent = NULL;
+    *local_parent = NULL;
+
+    for (orig_parent = node->parent; repeat && orig_parent; orig_parent = orig_parent->parent) {
+        if (parent && (parent->schema == orig_parent->schema)) {
+            /* stop creating parents, connect what we have into the provided parent */
+            iter = parent;
+            repeat = 0;
+        } else {
+            iter = NULL;
+            LY_CHECK_RET(lyd_dup_r((struct lyd_node *)orig_parent, NULL, (struct lyd_node **)&iter, 0,
+                                   (struct lyd_node **)&iter));
+        }
+        if (!*local_parent) {
+            *local_parent = (struct lyd_node_inner *)iter;
+        }
+        if (iter->child) {
+            /* 1) list - add after keys
+             * 2) provided parent with some children */
+            iter->child->prev->next = *dup_parent;
+            if (*dup_parent) {
+                (*dup_parent)->prev = iter->child->prev;
+                iter->child->prev = *dup_parent;
+            }
+        } else {
+            ((struct lyd_node_inner *)iter)->child = *dup_parent;
+        }
+        if (*dup_parent) {
+            (*dup_parent)->parent = (struct lyd_node_inner *)iter;
+        }
+        *dup_parent = (struct lyd_node *)iter;
+    }
+
+    if (repeat && parent) {
+        /* given parent and created parents chain actually do not interconnect */
+        LOGERR(LYD_NODE_CTX(node), LY_EINVAL,
+               "Invalid argument parent (%s()) - does not interconnect with the created node's parents chain.", __func__);
+        return LY_EINVAL;
+    }
+
+    return LY_SUCCESS;
+}
+
+static LY_ERR
+lyd_dup(const struct lyd_node *node, struct lyd_node_inner *parent, int options, int nosiblings, struct lyd_node **dup)
+{
+    LY_ERR rc;
     const struct lyd_node *orig;          /* original node to be duplicated */
     struct lyd_node *first = NULL;        /* the first duplicated node, this is returned */
     struct lyd_node *top = NULL;          /* the most higher created node */
     struct lyd_node_inner *local_parent = NULL; /* the direct parent node for the duplicated node(s) */
-    int keyless_parent_list = 0;
 
-    LY_CHECK_ARG_RET(NULL, node, NULL);
+    LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
 
     if (options & LYD_DUP_WITH_PARENTS) {
-        struct lyd_node_inner *orig_parent, *iter;
-        int repeat = 1;
-        for (top = NULL, orig_parent = node->parent; repeat && orig_parent; orig_parent = orig_parent->parent) {
-            if (parent && parent->schema == orig_parent->schema) {
-                /* stop creating parents, connect what we have into the provided parent */
-                iter = parent;
-                repeat = 0;
-                /* get know if there is a keyless list which we will have to rehash */
-                for (struct lyd_node_inner *piter = parent; piter; piter = piter->parent) {
-                    if (piter->schema->nodetype == LYS_LIST && (piter->schema->flags & LYS_KEYLESS)) {
-                        keyless_parent_list = 1;
-                        break;
-                    }
-                }
-            } else {
-                iter = NULL;
-                LY_CHECK_GOTO(lyd_dup_recursive((struct lyd_node *)orig_parent, NULL, (struct lyd_node **)&iter, 0,
-                                                (struct lyd_node **)&iter), error);
-            }
-            if (!local_parent) {
-                local_parent = iter;
-            }
-            if (iter->child) {
-                /* 1) list - add after keys
-                 * 2) provided parent with some children */
-                iter->child->prev->next = top;
-                if (top) {
-                    top->prev = iter->child->prev;
-                    iter->child->prev = top;
-                }
-            } else {
-                iter->child = top;
-                if (iter->schema->nodetype == LYS_LIST) {
-                    /* keyless list - we will need to rehash it since we are going to add nodes into it */
-                    keyless_parent_list = 1;
-                }
-            }
-            if (top) {
-                top->parent = iter;
-            }
-            top = (struct lyd_node*)iter;
-        }
-        if (repeat && parent) {
-            /* given parent and created parents chain actually do not interconnect */
-            LOGERR(LYD_NODE_CTX(node), LY_EINVAL,
-                   "Invalid argument parent (%s()) - does not interconnect with the created node's parents chain.", __func__);
-            goto error;
-        }
+        LY_CHECK_GOTO(rc = lyd_dup_get_local_parent(node, parent, &top, &local_parent), error);
     } else {
         local_parent = parent;
     }
 
     LY_LIST_FOR(node, orig) {
         /* if there is no local parent, it will be inserted into first */
-        LY_CHECK_GOTO(lyd_dup_recursive(orig, (struct lyd_node *)local_parent, &first, options, first ? NULL : &first), error);
-        if (!(options & LYD_DUP_WITH_SIBLINGS)) {
+        LY_CHECK_GOTO(rc = lyd_dup_r(orig, (struct lyd_node *)local_parent, &first, options, first ? NULL : &first), error);
+        if (nosiblings) {
             break;
         }
     }
-    if (keyless_parent_list) {
-        /* rehash */
-        for (; local_parent; local_parent = local_parent->parent) {
-            if (local_parent->schema->nodetype == LYS_LIST && (local_parent->schema->flags & LYS_KEYLESS)) {
-                lyd_hash((struct lyd_node*)local_parent);
-            }
+
+    /* rehash if needed */
+    for (; local_parent; local_parent = local_parent->parent) {
+        if (local_parent->schema->nodetype == LYS_LIST && (local_parent->schema->flags & LYS_KEYLESS)) {
+            lyd_hash((struct lyd_node *)local_parent);
         }
     }
-    return first;
+
+    if (dup) {
+        *dup = first;
+    }
+    return LY_SUCCESS;
 
 error:
     if (top) {
@@ -2334,25 +2358,37 @@
     } else {
         lyd_free_siblings(first);
     }
-    return NULL;
+    return rc;
 }
 
-API struct lyd_meta *
-lyd_dup_meta(const struct lyd_meta *meta, struct lyd_node *node)
+API LY_ERR
+lyd_dup_single(const struct lyd_node *node, struct lyd_node_inner *parent, int options, struct lyd_node **dup)
+{
+    return lyd_dup(node, parent, options, 1, dup);
+}
+
+API LY_ERR
+lyd_dup_siblings(const struct lyd_node *node, struct lyd_node_inner *parent, int options, struct lyd_node **dup)
+{
+    return lyd_dup(node, parent, options, 0, dup);
+}
+
+API LY_ERR
+lyd_dup_meta_single(const struct lyd_meta *meta, struct lyd_node *node, struct lyd_meta **dup)
 {
     LY_ERR ret;
     struct lyd_meta *mt, *last;
 
-    LY_CHECK_ARG_RET(NULL, meta, node, NULL);
+    LY_CHECK_ARG_RET(NULL, meta, node, LY_EINVAL);
 
     /* create a copy */
     mt = calloc(1, sizeof *mt);
-    LY_CHECK_ERR_RET(!mt, LOGMEM(LYD_NODE_CTX(node)), NULL);
+    LY_CHECK_ERR_RET(!mt, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
     mt->parent = node;
     mt->annotation = meta->annotation;
     mt->value.realtype = meta->value.realtype;
     ret = mt->value.realtype->plugin->duplicate(LYD_NODE_CTX(node), &meta->value, &mt->value);
-    LY_CHECK_ERR_RET(ret, LOGERR(LYD_NODE_CTX(node), LY_EINT, "Value duplication failed."), NULL);
+    LY_CHECK_ERR_RET(ret, LOGERR(LYD_NODE_CTX(node), LY_EINT, "Value duplication failed."), ret);
     mt->name = lydict_insert(LYD_NODE_CTX(node), meta->name, 0);
 
     /* insert as the last attribute */
@@ -2363,7 +2399,10 @@
         node->meta = mt;
     }
 
-    return mt;
+    if (dup) {
+        *dup = mt;
+    }
+    return LY_SUCCESS;
 }
 
 /**
@@ -2401,8 +2440,8 @@
             /* since they are different, they cannot both be default */
             assert(!(sibling_src->flags & LYD_DEFAULT) || !(match_trg->flags & LYD_DEFAULT));
 
-            /* update value (or only LYD_DEFAULT flag) only if no flag set or the source node is not default */
-            if (!(options & LYD_MERGE_EXPLICIT) || !(sibling_src->flags & LYD_DEFAULT)) {
+            /* update value (or only LYD_DEFAULT flag) only if flag set or the source node is not default */
+            if ((options & LYD_MERGE_DEFAULTS) || !(sibling_src->flags & LYD_DEFAULT)) {
                 type = ((struct lysc_node_leaf *)match_trg->schema)->type;
                 type->plugin->free(LYD_NODE_CTX(match_trg), &((struct lyd_node_term *)match_trg)->value);
                 LY_CHECK_RET(type->plugin->duplicate(LYD_NODE_CTX(match_trg), &((struct lyd_node_term *)sibling_src)->value,
@@ -2418,8 +2457,7 @@
                 /* spend it */
                 *sibling_src_p = NULL;
             } else {
-                dup_src = lyd_dup(sibling_src, NULL, 0);
-                LY_CHECK_RET(!dup_src, LY_EMEM);
+                LY_CHECK_RET(lyd_dup_single(sibling_src, NULL, 0, &dup_src));
             }
             /* just switch values */
             tmp_val_type = ((struct lyd_node_any *)match_trg)->value_type;
@@ -2448,8 +2486,7 @@
             /* spend it */
             *sibling_src_p = NULL;
         } else {
-            dup_src = lyd_dup(sibling_src, NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_FLAGS);
-            LY_CHECK_RET(!dup_src, LY_EMEM);
+            LY_CHECK_RET(lyd_dup_single(sibling_src, NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_FLAGS, &dup_src));
         }
 
         /* set LYD_NEW for all the new nodes, required for validation */
@@ -2464,8 +2501,8 @@
     return LY_SUCCESS;
 }
 
-API LY_ERR
-lyd_merge(struct lyd_node **target, const struct lyd_node *source, int options)
+static LY_ERR
+lyd_merge(struct lyd_node **target, const struct lyd_node *source, int options, int nosiblings)
 {
     const struct lyd_node *sibling_src, *tmp;
     int first;
@@ -2490,7 +2527,7 @@
             source = tmp;
         }
 
-        if (options & LYD_MERGE_NOSIBLINGS) {
+        if (nosiblings) {
             break;
         }
     }
@@ -2503,6 +2540,18 @@
     return LY_SUCCESS;
 }
 
+API LY_ERR
+lyd_merge_tree(struct lyd_node **target, const struct lyd_node *source, int options)
+{
+    return lyd_merge(target, source, options, 1);
+}
+
+API LY_ERR
+lyd_merge_siblings(struct lyd_node **target, const struct lyd_node *source, int options)
+{
+    return lyd_merge(target, source, options, 0);
+}
+
 static LY_ERR
 lyd_path_str_enlarge(char **buffer, size_t *buflen, size_t reqlen, int is_static)
 {
diff --git a/src/tree_data.h b/src/tree_data.h
index 9991eec..ea44fe7 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -475,10 +475,10 @@
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
  * @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.
+ * @param[out] node Optional created node.
+ * @return LY_ERR value.
  */
-struct lyd_node *lyd_new_inner(struct lyd_node *parent, const struct lys_module *module, const char *name);
+LY_ERR lyd_new_inner(struct lyd_node *parent, const struct lys_module *module, const char *name, struct lyd_node **node);
 
 /**
  * @brief Create a new list node in the data tree.
@@ -486,13 +486,13 @@
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
  * @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[out] node Optional created node.
  * @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). No keys are expected for
  * key-less lists.
- * @return New created node.
- * @return NULL on error.
+ * @return LY_ERR value.
  */
-struct lyd_node *lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, ...);
+LY_ERR lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, struct lyd_node **node, ...);
 
 /**
  * @brief Create a new list node in the data tree.
@@ -503,10 +503,11 @@
  * @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).
  * Use NULL or string of length 0 in case of key-less list.
- * @return New created node.
- * @return NULL on error.
+ * @param[out] node Optional created node.
+ * @return LY_ERR value.
  */
-struct lyd_node *lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *keys);
+LY_ERR lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *keys,
+                     struct lyd_node **node);
 
 /**
  * @brief Create a new term node in the data tree.
@@ -516,10 +517,11 @@
  * @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).
- * @return New created node.
- * @return NULL on error.
+ * @param[out] node Optional created node.
+ * @return LY_ERR value.
  */
-struct lyd_node *lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str);
+LY_ERR lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str,
+                    struct lyd_node **node);
 
 /**
  * @brief Create a new any node in the data tree.
@@ -529,11 +531,11 @@
  * @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.
- * @return New created node.
- * @return NULL on error.
+ * @param[out] node Optional created node.
+ * @return LY_ERR value.
  */
-struct lyd_node *lyd_new_any(struct lyd_node *parent, const struct lys_module *module, const char *name,
-                             const void *value, LYD_ANYDATA_VALUETYPE value_type);
+LY_ERR lyd_new_any(struct lyd_node *parent, const struct lys_module *module, const char *name, const void *value,
+                   LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node);
 
 /**
  * @brief Create new metadata for a data node.
@@ -544,11 +546,11 @@
  *            If the prefix is specified it is always used but if not specified, @p module must be set.
  * @param[in] val_str String form of the value of the metadata. In case of an instance-identifier or identityref
  * value, the JSON format is expected (module names instead of prefixes).
- * @return New created metadata of @p parent.
- * @return NULL on error.
+ * @param[out] meta Optional created metadata.
+ * @return LY_ERR value.
  */
-struct lyd_meta *lyd_new_meta(struct lyd_node *parent, const struct lys_module *module, const char *name,
-                              const char *val_str);
+LY_ERR lyd_new_meta(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str,
+                    struct lyd_meta **meta);
 
 /**
  * @brief Create a new opaque node in the data tree.
@@ -558,11 +560,11 @@
  * @param[in] name Node name.
  * @param[in] value Node value, may be NULL.
  * @param[in] module_name Node module name.
- * @return New created node.
- * @return NULL on error.
+ * @param[out] node Optional created node.
+ * @return LY_ERR value.
  */
-struct lyd_node *lyd_new_opaq(struct lyd_node *parent, const struct ly_ctx *ctx, const char *name, const char *value,
-                              const char *module_name);
+LY_ERR lyd_new_opaq(struct lyd_node *parent, const struct ly_ctx *ctx, const char *name, const char *value,
+                    const char *module_name, struct lyd_node **node);
 
 /**
  * @brief Create new attribute for an opaque data node.
@@ -571,10 +573,11 @@
  * @param[in] module Module name of the attribute being created. There may be none.
  * @param[in] name Attribute name. It can include the module name as the prefix.
  * @param[in] val_str String value of the attribute. Is stored directly.
- * @return New created attribute of @p parent.
- * @return NULL on error.
+ * @param[out] attr Optional created attribute.
+ * @return LY_ERR value.
  */
-struct ly_attr *lyd_new_attr(struct lyd_node *parent, const char *module_name, const char *name, const char *val_str);
+LY_ERR lyd_new_attr(struct lyd_node *parent, const char *module_name, const char *name, const char *val_str,
+                    struct ly_attr **attr);
 
 /**
  * @defgroup pathoptions Data path creation options
@@ -614,11 +617,11 @@
  * @param[in] path Path to create (TODO ref path).
  * @param[in] value Value of the new leaf/leaf-list. For other node types, it is ignored.
  * @param[in] options Bitmask of options, see @ref pathoptions.
- * @return First created node.
- * @return NULL on error.
+ * @param[out] node Optional first created node.
+ * @return LY_ERR value.
  */
-struct lyd_node *lyd_new_path(struct lyd_node *parent, const struct ly_ctx *ctx, const char *path, const char *value,
-                              int options);
+LY_ERR lyd_new_path(struct lyd_node *parent, const struct ly_ctx *ctx, const char *path, const char *value,
+                    int options, struct lyd_node **node);
 
 /**
  * @brief Create a new node in the data tree based on a path. All node types can be created.
@@ -633,11 +636,11 @@
  * @param[in] value Value of the new leaf/leaf-list/anyxml/anydata. For other node types, it is ignored.
  * @param[in] value_type Anyxml/anydata node @p value type.
  * @param[in] options Bitmask of options, see @ref pathoptions.
- * @return First created node.
- * @return NULL on error.
+ * @param[out] node Optional first created node.
+ * @return LY_ERR value.
  */
-struct lyd_node *lyd_new_path_any(struct lyd_node *parent, const struct ly_ctx *ctx, const char *path, const void *value,
-                                  LYD_ANYDATA_VALUETYPE value_type, int options);
+LY_ERR lyd_new_path_any(struct lyd_node *parent, const struct ly_ctx *ctx, const char *path, const void *value,
+                        LYD_ANYDATA_VALUETYPE value_type, int options, struct lyd_node **node);
 
 /**
  * @brief Create a new node in the data tree based on a path. All node types can be created.
@@ -652,8 +655,8 @@
  * @param[in] value Value of the new leaf/leaf-list/anyxml/anydata. For other node types, it is ignored.
  * @param[in] value_type Anyxml/anydata node @p value type.
  * @param[in] options Bitmask of options, see @ref pathoptions.
- * @param[out] new_parent First parent node created, can be NULL. If only one node was created, equals to @p new_node.
- * @param[out] new_node Last node created, can be NULL.
+ * @param[out] new_parent Optional first parent node created. If only one node was created, equals to @p new_node.
+ * @param[out] new_node Optional last node created.
  * @return LY_ERR value.
  */
 LY_ERR lyd_new_path2(struct lyd_node *parent, const struct ly_ctx *ctx, const char *path, const void *value,
@@ -753,7 +756,7 @@
 void lyd_free_all(struct lyd_node *node);
 
 /**
- * @brief Free all the sibling nodes.
+ * @brief Free all the sibling nodes (preceding as well as succeeding).
  *
  * @param[in] node Any of the sibling nodes to free.
  */
@@ -767,24 +770,34 @@
 void lyd_free_tree(struct lyd_node *node);
 
 /**
- * @brief Destroy metadata.
+ * @brief Free a single metadata instance.
  *
- * @param[in] ctx Context where the metadata was created.
- * @param[in] meta Metadata to destroy
- * @param[in] recursive Zero to destroy only the single metadata (the metadata list is corrected),
- * non-zero to destroy also all the subsequent metadata in the list.
+ * @param[in] meta Metadata to free.
  */
-void lyd_free_meta(const struct ly_ctx *ctx, struct lyd_meta *meta, int recursive);
+void lyd_free_meta_single(struct lyd_meta *meta);
 
 /**
- * @brief Destroy attributes.
+ * @brief Free the metadata instance with any following instances.
+ *
+ * @param[in] meta Metadata to free.
+ */
+void lyd_free_meta_siblings(struct lyd_meta *meta);
+
+/**
+ * @brief Free a single attribute.
  *
  * @param[in] ctx Context where the attributes were created.
- * @param[in] attr Attributes to destroy.
- * @param[in] recursive Zero to destroy only the single attribute (the attribute list is corrected),
- * non-zero to destroy also all the subsequent attributes in the list.
+ * @param[in] attr Attribute to free.
  */
-void ly_free_attr(const struct ly_ctx *ctx, struct ly_attr *attr, int recursive);
+void ly_free_attr_single(const struct ly_ctx *ctx, struct ly_attr *attr);
+
+/**
+ * @brief Free the attribute with any following attributes.
+ *
+ * @param[in] ctx Context where the attributes were created.
+ * @param[in] attr First attribute to free.
+ */
+void ly_free_attr_siblings(const struct ly_ctx *ctx, struct ly_attr *attr);
 
 /**
  * @brief Check type restrictions applicable to the particular leaf/leaf-list with the given string @p value.
@@ -877,7 +890,7 @@
  *
  * Default behavior:
  * - only the specified node is duplicated without siblings, parents, or children.
- * - all the attributes of the duplicated nodes are also duplicated.
+ * - all the metadata of the duplicated nodes are also duplicated.
  * @{
  */
 
@@ -886,8 +899,7 @@
 #define LYD_DUP_NO_META      0x02  /**< Do not duplicate metadata of any node. */
 #define LYD_DUP_WITH_PARENTS 0x04  /**< If a nested node is being duplicated, duplicate also all the parents.
                                         Keys are also duplicated for lists. Return value does not change! */
-#define LYD_DUP_WITH_SIBLINGS 0x08 /**< Duplicate also all the sibling of the given node. */
-#define LYD_DUP_WITH_FLAGS    0x10 /**< Also copy any data node flags. That will cause the duplicated data to preserve
+#define LYD_DUP_WITH_FLAGS   0x08  /**< Also copy any data node flags. That will cause the duplicated data to preserve
                                         its validation/default node state. */
 
 /** @} dupoptions */
@@ -897,24 +909,38 @@
  *
  * @param[in] node Data tree node to be duplicated.
  * @param[in] parent Optional parent node where to connect the duplicated node(s).
- * If set in combination with LYD_DUP_WITH_PARENTS, the parents chain is duplicated until it comes to and connect with the @p parent
- * (if the parents chain does not match at some node the schema node of the provided @p parent, duplication fails).
+ * If set in combination with LYD_DUP_WITH_PARENTS, the parents chain is duplicated until it comes to and connects with
+ * the @p parent.
  * @param[in] options Bitmask of options flags, see @ref dupoptions.
- * @return Created copy of the provided data \p node (the first of the duplicated siblings when LYD_DUP_WITH_SIBLINGS used).
- * Note that in case the parents chain is duplicated for the duplicated node(s) (when LYD_DUP_WITH_PARENTS used), the first duplicated node
- * is still returned, not a pointer to the duplicated parents.
+ * @param[out] dup Optional created copy of the node. Note that in case the parents chain is duplicated for the duplicated
+ * node(s) (when LYD_DUP_WITH_PARENTS used), the first duplicated node is still returned.
+ * @return LY_ERR value.
  */
-struct lyd_node *lyd_dup(const struct lyd_node *node, struct lyd_node_inner *parent, int options);
+LY_ERR lyd_dup_single(const struct lyd_node *node, struct lyd_node_inner *parent, int options, struct lyd_node **dup);
+
+/**
+ * @brief Create a copy of the specified data tree \p node with any following siblings. Schema references are kept the same.
+ *
+ * @param[in] node Data tree node to be duplicated.
+ * @param[in] parent Optional parent node where to connect the duplicated node(s).
+ * If set in combination with LYD_DUP_WITH_PARENTS, the parents chain is duplicated until it comes to and connects with
+ * the @p parent.
+ * @param[in] options Bitmask of options flags, see @ref dupoptions.
+ * @param[out] dup Optional created copy of the node. Note that in case the parents chain is duplicated for the duplicated
+ * node(s) (when LYD_DUP_WITH_PARENTS used), the first duplicated node is still returned.
+ * @return LY_ERR value.
+ */
+LY_ERR lyd_dup_siblings(const struct lyd_node *node, struct lyd_node_inner *parent, int options, struct lyd_node **dup);
 
 /**
  * @brief Create a copy of the metadata.
  *
  * @param[in] meta Metadata to copy.
- * @param[in] node Node where to append the new metadata.
- * @return Created metadata copy,
- * @return NULL on error.
+ * @param[in] parent Node where to append the new metadata.
+ * @param[out] dup Optional created metadata copy.
+ * @return LY_ERR value.
  */
-struct lyd_meta *lyd_dup_meta(const struct lyd_meta *meta, struct lyd_node *node);
+LY_ERR lyd_dup_meta_single(const struct lyd_meta *meta, struct lyd_node *parent, struct lyd_meta **dup);
 
 /**
  * @defgroup mergeoptions Data merge options.
@@ -924,20 +950,17 @@
  *
  * Default behavior:
  * - source data tree is not modified in any way,
- * - source data tree is merged with any succeeding siblings,
- * - any default nodes from source replace explicit nodes in the target.
+ * - any default nodes in the source are ignored if there are explicit nodes in the target.
  * @{
  */
 
 #define LYD_MERGE_DESTRUCT      0x01 /**< Spend source data tree in the function, it cannot be used afterwards! */
-#define LYD_MERGE_NOSIBLINGS    0x02 /**< Merge only the single source data tree, no siblings. */
-#define LYD_MERGE_EXPLICIT      0x04 /**< Default nodes in the source tree are ignored if there are explicit nodes
-                                          in the target tree. */
+#define LYD_MERGE_DEFAULTS      0x02 /**< Default nodes in the source tree replace even explicit nodes in the target. */
 
 /** @} mergeoptions */
 
 /**
- * @brief Merge the source data tree into the target data tree. Merge may not be complete until validation
+ * @brief Merge the source data subtree into the target data tree. Merge may not be complete until validation
  * is called on the resulting data tree (data from more cases may be present, default and non-default values).
  *
  * @param[in,out] target Target data tree to merge into, must be a top-level tree.
@@ -946,7 +969,20 @@
  * @return LY_SUCCESS on success,
  * @return LY_ERR value on error.
  */
-LY_ERR lyd_merge(struct lyd_node **target, const struct lyd_node *source, int options);
+LY_ERR lyd_merge_tree(struct lyd_node **target, const struct lyd_node *source, int options);
+
+/**
+ * @brief Merge the source data tree with any following siblings into the target data tree. Merge may not be
+ * complete until validation called on the resulting data tree (data from more cases may be present, default
+ * and non-default values).
+ *
+ * @param[in,out] target Target data tree to merge into, must be a top-level tree.
+ * @param[in] source Source data tree to merge, must be a top-level tree.
+ * @param[in] options Bitmask of option flags, see @ref mergeoptions.
+ * @return LY_SUCCESS on success,
+ * @return LY_ERR value on error.
+ */
+LY_ERR lyd_merge_siblings(struct lyd_node **target, const struct lyd_node *source, int options);
 
 /**
  * @defgroup diffoptions Data diff options.
@@ -955,15 +991,13 @@
  * Various options to change lyd_diff() behavior.
  *
  * Default behavior:
- * - data trees are compared with all the siblings,
  * - any default nodes are treated as non-existent and ignored.
  * @{
  */
 
-#define LYD_DIFF_NOSIBLINGS     0x01 /**< Only the single subtree is compared, no siblings. */
-#define LYD_DIFF_WITHDEFAULTS   0x02 /**< Default nodes in the trees are not ignored but treated similarly to explicit
-                                          nodes. Also, leaves and leaf-lists are added into diff even in case only their
-                                          default flag (state) was changed. */
+#define LYD_DIFF_DEFAULTS   0x01 /**< Default nodes in the trees are not ignored but treated similarly to explicit
+                                      nodes. Also, leaves and leaf-lists are added into diff even in case only their
+                                      default flag (state) was changed. */
 
 /** @} diffoptions */
 
@@ -992,7 +1026,19 @@
  * @return LY_SUCCESS on success,
  * @return LY_ERR on error.
  */
-LY_ERR lyd_diff(const struct lyd_node *first, const struct lyd_node *second, int options, struct lyd_node **diff);
+LY_ERR lyd_diff_tree(const struct lyd_node *first, const struct lyd_node *second, int options, struct lyd_node **diff);
+
+/**
+ * @brief Learn the differences between 2 data trees including all the following siblings.
+ *
+ * @param[in] first First data tree.
+ * @param[in] second Second data tree.
+ * @param[in] options Bitmask of options flags, see @ref diffoptions.
+ * @param[out] diff Generated diff.
+ * @return LY_SUCCESS on success,
+ * @return LY_ERR on error.
+ */
+LY_ERR lyd_diff_siblings(const struct lyd_node *first, const struct lyd_node *second, int options, struct lyd_node **diff);
 
 /**
  * @brief Callback for diff nodes.
@@ -1005,7 +1051,7 @@
 typedef LY_ERR (*lyd_diff_cb)(const struct lyd_node *diff_node, struct lyd_node *data_node, void *cb_data);
 
 /**
- * @brief Apply a difference on a data tree but restrict the operation to one module.
+ * @brief Apply the whole diff on a data tree but restrict the operation to one module.
  *
  * @param[in,out] data Data to apply the diff on.
  * @param[in] diff Diff to apply.
@@ -1019,14 +1065,14 @@
                              lyd_diff_cb diff_cb, void *cb_data);
 
 /**
- * @brief Apply a difference on a data tree.
+ * @brief Apply the whole diff tree on a data tree.
  *
  * @param[in,out] data Data to apply the diff on.
  * @param[in] diff Diff to apply.
  * @return LY_SUCCESS on success,
  * @return LY_ERR on error.
  */
-LY_ERR lyd_diff_apply(struct lyd_node **data, const struct lyd_node *diff);
+LY_ERR lyd_diff_apply_all(struct lyd_node **data, const struct lyd_node *diff);
 
 /**
  * @brief Merge 2 diffs into each other but restrict the operation to one module.
@@ -1060,7 +1106,7 @@
  * @return LY_SUCCESS on success,
  * @return LY_ERR on error.
  */
-LY_ERR lyd_diff_merge(const struct lyd_node *src_diff, struct lyd_node **diff);
+LY_ERR lyd_diff_merge_all(const struct lyd_node *src_diff, struct lyd_node **diff);
 
 /**
  * @brief Reverse a diff and make the opposite changes. Meaning change create to delete, delete to create,
@@ -1071,7 +1117,7 @@
  * @return LY_SUCCESS on success.
  * @return LY_ERR on error.
  */
-LY_ERR lyd_diff_reverse(const struct lyd_node *src_diff, struct lyd_node **diff);
+LY_ERR lyd_diff_reverse_all(const struct lyd_node *src_diff, struct lyd_node **diff);
 
 /**
  * @brief Find the target in data of a compiled ly_path structure (instance-identifier).
diff --git a/src/tree_data_free.c b/src/tree_data_free.c
index 9cb946e..7cd1283 100644
--- a/src/tree_data_free.c
+++ b/src/tree_data_free.c
@@ -23,19 +23,18 @@
 #include "tree_data_internal.h"
 #include "plugins_types.h"
 
-API void
-lyd_free_meta(const struct ly_ctx *ctx, struct lyd_meta *meta, int recursive)
+static void
+lyd_free_meta(struct lyd_meta *meta, int siblings)
 {
     struct lyd_meta *iter;
 
-    LY_CHECK_ARG_RET(NULL, ctx, );
     if (!meta) {
         return;
     }
 
     if (meta->parent) {
         if (meta->parent->meta == meta) {
-            if (recursive) {
+            if (siblings) {
                 meta->parent->meta = NULL;
             } else {
                 meta->parent->meta = meta->next;
@@ -43,7 +42,7 @@
         } else {
             for (iter = meta->parent->meta; iter->next != meta; iter = iter->next);
             if (iter->next) {
-                if (recursive) {
+                if (siblings) {
                     iter->next = NULL;
                 } else {
                     iter->next = meta->next;
@@ -52,7 +51,7 @@
         }
     }
 
-    if (!recursive) {
+    if (!siblings) {
         meta->next = NULL;
     }
 
@@ -60,14 +59,26 @@
         meta = iter;
         iter = iter->next;
 
-        FREE_STRING(ctx, meta->name);
-        meta->value.realtype->plugin->free(ctx, &meta->value);
+        FREE_STRING(meta->annotation->module->ctx, meta->name);
+        meta->value.realtype->plugin->free(meta->annotation->module->ctx, &meta->value);
         free(meta);
     }
 }
 
 API void
-ly_free_attr(const struct ly_ctx *ctx, struct ly_attr *attr, int recursive)
+lyd_free_meta_single(struct lyd_meta *meta)
+{
+    lyd_free_meta(meta, 0);
+}
+
+API void
+lyd_free_meta_siblings(struct lyd_meta *meta)
+{
+    lyd_free_meta(meta, 1);
+}
+
+static void
+ly_free_attr(const struct ly_ctx *ctx, struct ly_attr *attr, int siblings)
 {
     struct ly_attr *iter;
     LY_ARRAY_COUNT_TYPE u;
@@ -79,7 +90,7 @@
 
     if (attr->parent) {
         if (attr->parent->attr == attr) {
-            if (recursive) {
+            if (siblings) {
                 attr->parent->attr = NULL;
             } else {
                 attr->parent->attr = attr->next;
@@ -87,7 +98,7 @@
         } else {
             for (iter = attr->parent->attr; iter->next != attr; iter = iter->next);
             if (iter->next) {
-                if (recursive) {
+                if (siblings) {
                     iter->next = NULL;
                 } else {
                     iter->next = attr->next;
@@ -96,7 +107,7 @@
         }
     }
 
-    if (!recursive) {
+    if (!siblings) {
         attr->next = NULL;
     }
 
@@ -117,6 +128,18 @@
     }
 }
 
+API void
+ly_free_attr_single(const struct ly_ctx *ctx, struct ly_attr *attr)
+{
+    ly_free_attr(ctx, attr, 0);
+}
+
+API void
+ly_free_attr_siblings(const struct ly_ctx *ctx, struct ly_attr *attr)
+{
+    ly_free_attr(ctx, attr, 1);
+}
+
 void
 ly_free_val_prefs(const struct ly_ctx *ctx, struct ly_prefix *val_prefs)
 {
@@ -175,10 +198,10 @@
     }
 
     if (!node->schema) {
-        ly_free_attr(LYD_NODE_CTX(node), opaq->attr, 1);
+        ly_free_attr_siblings(LYD_NODE_CTX(node), opaq->attr);
     } else {
         /* free the node's metadata */
-        lyd_free_meta(LYD_NODE_CTX(node), node->meta, 1);
+        lyd_free_meta_siblings(node->meta);
     }
 
     /* unlink only the nodes from the first level, nodes in subtree are freed all, so no unlink is needed */
diff --git a/src/tree_data_helpers.c b/src/tree_data_helpers.c
index e11815b..7551667 100644
--- a/src/tree_data_helpers.c
+++ b/src/tree_data_helpers.c
@@ -198,7 +198,7 @@
             } else {
                 *meta = (*meta)->next;
             }
-            lyd_free_meta(LYD_NODE_CTX(node), meta2, 0);
+            lyd_free_meta_single(meta2);
             break;
         }
 
@@ -242,8 +242,7 @@
     switch (value_type) {
     case LYD_ANYDATA_DATATREE:
         if (value->tree) {
-            t->value.tree = lyd_dup(value->tree, NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_SIBLINGS);
-            LY_CHECK_RET(!t->value.tree, LY_EINT);
+            LY_CHECK_RET(lyd_dup_siblings(value->tree, NULL, LYD_DUP_RECURSIVE, &t->value.tree));
         }
         break;
     case LYD_ANYDATA_STRING:
diff --git a/src/tree_schema.c b/src/tree_schema.c
index b958df4..e89cd01 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -749,17 +749,18 @@
     return lys_set_implemented_internal(mod, 1);
 }
 
-struct lysp_submodule *
+LY_ERR
 lys_parse_mem_submodule(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, struct lys_parser_ctx *main_ctx,
-                        LY_ERR (*custom_check)(const struct ly_ctx*, struct lysp_module*, struct lysp_submodule*, void*), void *check_data)
+                        LY_ERR (*custom_check)(const struct ly_ctx*, struct lysp_module*, struct lysp_submodule*, void*),
+                        void *check_data, struct lysp_submodule **submodule)
 {
-    LY_ERR ret = LY_EINVAL;
+    LY_ERR ret;
     struct lysp_submodule *submod = NULL, *latest_sp;
     struct lys_yang_parser_ctx *yangctx = NULL;
     struct lys_yin_parser_ctx *yinctx = NULL;
     struct lys_parser_ctx *pctx;
 
-    LY_CHECK_ARG_RET(ctx, ctx, in, NULL);
+    LY_CHECK_ARG_RET(ctx, ctx, in, LY_EINVAL);
 
     switch (format) {
     case LYS_IN_YIN:
@@ -802,7 +803,7 @@
     }
 
     if (custom_check) {
-        LY_CHECK_GOTO(custom_check(PARSER_CTX(pctx), NULL, submod, check_data), error);
+        LY_CHECK_GOTO(ret = custom_check(PARSER_CTX(pctx), NULL, submod, check_data), error);
     }
 
     if (latest_sp) {
@@ -818,7 +819,8 @@
     } else {
         yin_parser_ctx_free(yinctx);
     }
-    return submod;
+    *submodule = submod;
+    return LY_SUCCESS;
 
 error:
     lysp_submodule_free(ctx, submod);
@@ -827,27 +829,28 @@
     } else {
         yin_parser_ctx_free(yinctx);
     }
-    return NULL;
+    return ret;
 }
 
-struct lys_module *
+LY_ERR
 lys_parse_mem_module(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, int implement,
-                     LY_ERR (*custom_check)(const struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
-                     void *check_data)
+                     LY_ERR (*custom_check)(const struct ly_ctx *ctx, struct lysp_module *mod,
+                                            struct lysp_submodule *submod, void *data), void *check_data,
+                     struct lys_module **module)
 {
     struct lys_module *mod = NULL, *latest, *mod_dup;
     struct lysp_import *imp;
     struct lysp_include *inc;
-    LY_ERR ret = LY_EINVAL;
+    LY_ERR ret;
     LY_ARRAY_COUNT_TYPE u, v;
     struct lys_yang_parser_ctx *yangctx = NULL;
     struct lys_yin_parser_ctx *yinctx = NULL;
     struct lys_parser_ctx *pctx = NULL;
 
-    LY_CHECK_ARG_RET(ctx, ctx, in, NULL);
+    LY_CHECK_ARG_RET(ctx, ctx, in, LY_EINVAL);
 
     mod = calloc(1, sizeof *mod);
-    LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), NULL);
+    LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), LY_EMEM);
     mod->ctx = ctx;
 
     switch (format) {
@@ -861,6 +864,7 @@
         break;
     default:
         LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
+        ret = LY_EINVAL;
         break;
     }
     LY_CHECK_GOTO(ret, error);
@@ -893,13 +897,14 @@
     }
 
     if (custom_check) {
-        LY_CHECK_GOTO(custom_check(ctx, mod->parsed, NULL, check_data), error);
+        LY_CHECK_GOTO(ret = custom_check(ctx, mod->parsed, NULL, check_data), error);
     }
 
     if (implement) {
         /* mark the loaded module implemented */
         if (ly_ctx_get_module_implemented(ctx, mod->name)) {
             LOGERR(ctx, LY_EDENIED, "Module \"%s\" is already implemented in the context.", mod->name);
+            ret = LY_EDENIED;
             goto error;
         }
         mod->implemented = 1;
@@ -917,6 +922,7 @@
                 LOGERR(ctx, LY_EEXIST, "Module \"%s\" with no revision is already present in the context.",
                        mod->name);
             }
+            ret = LY_EEXIST;
             goto error;
         } else {
             /* add the parsed data to the currently compiled-only module in the context */
@@ -931,8 +937,8 @@
 
     if (!mod->implemented) {
         /* pre-compile features and identities of the module */
-        LY_CHECK_GOTO(lys_feature_precompile(NULL, ctx, mod, mod->parsed->features, &mod->dis_features), error);
-        LY_CHECK_GOTO(lys_identity_precompile(NULL, ctx, mod, mod->parsed->identities, &mod->dis_identities), error);
+        LY_CHECK_GOTO(ret = lys_feature_precompile(NULL, ctx, mod, mod->parsed->features, &mod->dis_features), error);
+        LY_CHECK_GOTO(ret = lys_identity_precompile(NULL, ctx, mod, mod->parsed->identities, &mod->dis_identities), error);
     }
 
     if (latest) {
@@ -947,39 +953,44 @@
     mod->parsed->parsing = 1;
     LY_ARRAY_FOR(mod->parsed->imports, u) {
         imp = &mod->parsed->imports[u];
-        if (!imp->module && lysp_load_module(ctx, imp->name, imp->rev[0] ? imp->rev : NULL, 0, 0, &imp->module)) {
-            goto error_ctx;
+        if (!imp->module) {
+            LY_CHECK_GOTO(ret = lysp_load_module(ctx, imp->name, imp->rev[0] ? imp->rev : NULL, 0, 0, &imp->module),
+                          error_ctx);
         }
         /* check for importing the same module twice */
         for (v = 0; v < u; ++v) {
             if (imp->module == mod->parsed->imports[v].module) {
-                LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Single revision of the module \"%s\" referred twice.", imp->name);
+                LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Single revision of the module \"%s\" referred twice.",
+                       imp->name);
+                ret = LY_EVALID;
                 goto error_ctx;
             }
         }
     }
     LY_ARRAY_FOR(mod->parsed->includes, u) {
         inc = &mod->parsed->includes[u];
-        if (!inc->submodule && lysp_load_submodule(pctx, mod->parsed, inc)) {
-            goto error_ctx;
+        if (!inc->submodule) {
+            LY_CHECK_GOTO(ret = lysp_load_submodule(pctx, mod->parsed, inc), error_ctx);
         }
         if (!mod->implemented) {
             /* pre-compile features and identities of the submodule */
-            LY_CHECK_GOTO(lys_feature_precompile(NULL, ctx, mod, inc->submodule->features, &mod->dis_features), error);
-            LY_CHECK_GOTO(lys_identity_precompile(NULL, ctx, mod, inc->submodule->identities, &mod->dis_identities), error);
+            LY_CHECK_GOTO(ret = lys_feature_precompile(NULL, ctx, mod, inc->submodule->features, &mod->dis_features), error);
+            LY_CHECK_GOTO(ret = lys_identity_precompile(NULL, ctx, mod, inc->submodule->identities, &mod->dis_identities),
+                          error);
         }
     }
     mod->parsed->parsing = 0;
 
     /* check name collisions - typedefs and TODO groupings */
-    LY_CHECK_GOTO(lysp_check_typedefs(pctx, mod->parsed), error_ctx);
+    LY_CHECK_GOTO(ret = lysp_check_typedefs(pctx, mod->parsed), error_ctx);
 
     if (format == LYS_IN_YANG) {
         yang_parser_ctx_free(yangctx);
     } else {
         yin_parser_ctx_free(yinctx);
     }
-    return mod;
+    *module = mod;
+    return LY_SUCCESS;
 
 error_ctx:
     ly_set_rm(&ctx->list, mod, NULL);
@@ -994,23 +1005,25 @@
         yin_parser_ctx_free(yinctx);
     }
 
-    return NULL;
+    return ret;
 }
 
-API struct lys_module *
-lys_parse(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format)
+API LY_ERR
+lys_parse(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, const struct lys_module **module)
 {
     struct lys_module *mod;
     char *filename, *rev, *dot;
     size_t len;
 
-    LY_CHECK_ARG_RET(NULL, ctx, in, format > LYS_IN_UNKNOWN, NULL);
+    if (module) {
+        *module = NULL;
+    }
+    LY_CHECK_ARG_RET(NULL, ctx, in, format > LYS_IN_UNKNOWN, LY_EINVAL);
 
     /* remember input position */
     in->func_start = in->current;
 
-    mod = lys_parse_mem_module(ctx, in, format, 1, NULL, NULL);
-    LY_CHECK_RET(!mod, NULL);
+    LY_CHECK_RET(lys_parse_mem_module(ctx, in, format, 1, NULL, NULL, &mod));
 
     switch (in->type) {
     case LY_IN_FILEPATH:
@@ -1045,65 +1058,66 @@
         /* nothing special to do */
         break;
     default:
-        LOGINT(ctx);
+        LOGINT_RET(ctx);
         break;
     }
 
     lys_parser_fill_filepath(ctx, in, &mod->filepath);
-    lys_compile(&mod, 0);
+    LY_CHECK_RET(lys_compile(&mod, 0));
 
-    return mod;
+    if (module) {
+        *module = mod;
+    }
+    return LY_SUCCESS;
 }
 
-API struct lys_module *
-lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format)
+API LY_ERR
+lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, const struct lys_module **module)
 {
 	LY_ERR ret;
     struct ly_in *in = NULL;
-    struct lys_module *result = NULL;
 
-    LY_CHECK_ARG_RET(ctx, data, format != LYS_IN_UNKNOWN, NULL);
+    LY_CHECK_ARG_RET(ctx, data, format != LYS_IN_UNKNOWN, LY_EINVAL);
 
-    LY_CHECK_ERR_RET(ret = ly_in_new_memory(data, &in), LOGERR(ctx, ret, "Unable to create input handler."), NULL);
+    LY_CHECK_ERR_RET(ret = ly_in_new_memory(data, &in), LOGERR(ctx, ret, "Unable to create input handler."), ret);
 
-    result = lys_parse(ctx, in, format);
+    ret = lys_parse(ctx, in, format, module);
     ly_in_free(in, 0);
 
-    return result;
+    return ret;
 }
 
-API struct lys_module *
-lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format)
+API LY_ERR
+lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, const struct lys_module **module)
 {
 	LY_ERR ret;
     struct ly_in *in = NULL;
-    struct lys_module *result = NULL;
 
-    LY_CHECK_ARG_RET(ctx, fd != -1, format != LYS_IN_UNKNOWN, NULL);
+    LY_CHECK_ARG_RET(ctx, fd > -1, format != LYS_IN_UNKNOWN, LY_EINVAL);
 
-    LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, &in), LOGERR(ctx, ret, "Unable to create input handler."), NULL);
+    LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, &in), LOGERR(ctx, ret, "Unable to create input handler."), ret);
 
-    result = lys_parse(ctx, in, format);
+    ret = lys_parse(ctx, in, format, module);
     ly_in_free(in, 0);
 
-    return result;
+    return ret;
 }
 
-API struct lys_module *
-lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format)
+API LY_ERR
+lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, const struct lys_module **module)
 {
 	LY_ERR ret;
     struct ly_in *in = NULL;
-    struct lys_module *result = NULL;
 
-    LY_CHECK_ARG_RET(ctx, path, format != LYS_IN_UNKNOWN, NULL);
+    LY_CHECK_ARG_RET(ctx, path, format != LYS_IN_UNKNOWN, LY_EINVAL);
 
-    LY_CHECK_ERR_RET(ret = ly_in_new_filepath(path, 0, &in), LOGERR(ctx, ret, "Unable to create input handler for filepath %s.", path), NULL);
+    LY_CHECK_ERR_RET(ret = ly_in_new_filepath(path, 0, &in),
+                     LOGERR(ctx, ret, "Unable to create input handler for filepath %s.", path), ret);
 
-    result = lys_parse(ctx, in, format);
+    ret = lys_parse(ctx, in, format, module);
     ly_in_free(in, 0);
 
-    return result;
+    return ret;
 }
 
 API LY_ERR
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index d62473b..ca53a39 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -911,7 +911,7 @@
 static LY_ERR
 lys_compile_import(struct lysc_ctx *ctx, struct lysp_import *imp_p, struct lysc_import *imp)
 {
-    struct lys_module *mod = NULL;
+    const struct lys_module *mod = NULL;
     LY_ERR ret = LY_SUCCESS;
 
     DUP_STRING(ctx->ctx, imp_p->prefix, imp->prefix);
@@ -928,16 +928,18 @@
             if (ly_in_new_filepath(imp->module->filepath, 0, &in)) {
                 LOGINT(ctx->ctx);
             } else {
-                mod = lys_parse(ctx->ctx, in, !strcmp(&imp->module->filepath[strlen(imp->module->filepath - 4)], ".yin") ? LYS_IN_YIN : LYS_IN_YANG);
+                LY_CHECK_RET(lys_parse(ctx->ctx, in, !strcmp(&imp->module->filepath[strlen(imp->module->filepath - 4)],
+                                                             ".yin") ? LYS_IN_YIN : LYS_IN_YANG, &mod));
                 if (mod != imp->module) {
-                    LOGERR(ctx->ctx, LY_EINT, "Filepath \"%s\" of the module \"%s\" does not match.", imp->module->filepath, imp->module->name);
+                    LOGERR(ctx->ctx, LY_EINT, "Filepath \"%s\" of the module \"%s\" does not match.",
+                           imp->module->filepath, imp->module->name);
                     mod = NULL;
                 }
             }
             ly_in_free(in, 1);
         }
         if (!mod) {
-            if (lysp_load_module(ctx->ctx, imp->module->name, imp->module->revision, 0, 1, &mod)) {
+            if (lysp_load_module(ctx->ctx, imp->module->name, imp->module->revision, 0, 1, (struct lys_module **)&mod)) {
                 LOGERR(ctx->ctx, LY_ENOTFOUND, "Unable to reload \"%s\" module to import it into \"%s\", source data not found.",
                        imp->module->name, ctx->mod->name);
                 return LY_ENOTFOUND;
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index e079640..bedf795 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -755,34 +755,42 @@
 
     LY_CHECK_RET(lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name, revision,
                                       &filepath, &format));
-    LY_CHECK_ERR_RET(!filepath, if (required) {LOGERR(ctx, LY_ENOTFOUND, "Data model \"%s%s%s\" not found in local searchdirs.",
-                                       name, revision ? "@" : "", revision ? revision : "");}, LY_ENOTFOUND);
+    if (!filepath) {
+        if (required) {
+            LOGERR(ctx, LY_ENOTFOUND, "Data model \"%s%s%s\" not found in local searchdirs.", name, revision ? "@" : "",
+                   revision ? revision : "");
+        }
+        return LY_ENOTFOUND;
+    }
 
     LOGVRB("Loading schema from \"%s\" file.", filepath);
 
     /* get the (sub)module */
-    LY_CHECK_ERR_GOTO(ret = ly_in_new_filepath(filepath, 0, &in), LOGERR(ctx, ret, "Unable to create input handler for filepath %s.", filepath), cleanup);
+    LY_CHECK_ERR_GOTO(ret = ly_in_new_filepath(filepath, 0, &in),
+                      LOGERR(ctx, ret, "Unable to create input handler for filepath %s.", filepath), cleanup);
     check_data.name = name;
     check_data.revision = revision;
     check_data.path = filepath;
     check_data.submoduleof = main_name;
     if (main_ctx) {
-        mod = lys_parse_mem_submodule(ctx, in, format, main_ctx, lysp_load_module_check, &check_data);
+        ret = lys_parse_mem_submodule(ctx, in, format, main_ctx, lysp_load_module_check, &check_data,
+                                      (struct lysp_submodule **)&mod);
     } else {
-        mod = lys_parse_mem_module(ctx, in, format, implement, lysp_load_module_check, &check_data);
+        ret = lys_parse_mem_module(ctx, in, format, implement, lysp_load_module_check, &check_data,
+                                   (struct lys_module **)&mod);
 
     }
-    LY_CHECK_ERR_GOTO(!mod, ly_in_free(in, 1);ly_errcode(ctx), cleanup);
+    LY_CHECK_ERR_GOTO(ret, ly_in_free(in, 1), cleanup);
 
     if (main_ctx) {
-        lys_parser_fill_filepath(ctx, in, &((struct lysp_submodule*)mod)->filepath);
+        lys_parser_fill_filepath(ctx, in, &((struct lysp_submodule *)mod)->filepath);
     } else {
-        lys_parser_fill_filepath(ctx, in, &((struct lys_module*)mod)->filepath);
+        lys_parser_fill_filepath(ctx, in, &((struct lys_module *)mod)->filepath);
     }
     ly_in_free(in, 1);
 
     if (mod && implement) {
-        lys_compile((struct lys_module**)&mod, 0);
+        lys_compile((struct lys_module **)&mod, 0);
     }
 
     *result = mod;
@@ -794,7 +802,8 @@
 }
 
 LY_ERR
-lysp_load_module(struct ly_ctx *ctx, const char *name, const char *revision, int implement, int require_parsed, struct lys_module **mod)
+lysp_load_module(struct ly_ctx *ctx, const char *name, const char *revision, int implement, int require_parsed,
+                 struct lys_module **mod)
 {
     const char *module_data = NULL;
     LYS_INFORMAT format = LYS_IN_UNKNOWN;
@@ -848,7 +857,7 @@
                     LY_CHECK_RET(ly_in_new_memory(module_data, &in));
                     check_data.name = name;
                     check_data.revision = revision;
-                    *mod = lys_parse_mem_module(ctx, in, format, implement, lysp_load_module_check, &check_data);
+                    lys_parse_mem_module(ctx, in, format, implement, lysp_load_module_check, &check_data, mod);
                     ly_in_free(in, 0);
                     if (module_data_free) {
                         module_data_free((void*)module_data, ctx->imp_clb_data);
@@ -970,7 +979,7 @@
                 check_data.name = inc->name;
                 check_data.revision = inc->rev[0] ? inc->rev : NULL;
                 check_data.submoduleof = mod->mod->name;
-                submod = lys_parse_mem_submodule(ctx, in, format, pctx, lysp_load_module_check, &check_data);
+                lys_parse_mem_submodule(ctx, in, format, pctx, lysp_load_module_check, &check_data, &submod);
                 ly_in_free(in, 0);
                 if (submodule_data_free) {
                     submodule_data_free((void*)submodule_data, ctx->imp_clb_data);
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 880a297..2952413 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -520,7 +520,8 @@
  */
 const char *lys_datatype2str(LY_DATA_TYPE basetype);
 
-typedef LY_ERR (*lys_custom_check)(const struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *check_data);
+typedef LY_ERR (*lys_custom_check)(const struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod,
+                                   void *check_data);
 
 /**
  * @brief Parse module from a string.
@@ -533,10 +534,11 @@
  * @param[in] implement Flag if the schema is supposed to be marked as implemented.
  * @param[in] custom_check Callback to check the parsed schema before it is accepted.
  * @param[in] check_data Caller's data to pass to the custom_check callback.
- * @return Pointer to the data model structure or NULL on error.
+ * @param[out] module Parsed module.
+ * @return LY_ERR value.
  */
-struct lys_module *lys_parse_mem_module(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, int implement,
-                                        lys_custom_check custom_check, void *check_data);
+LY_ERR lys_parse_mem_module(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, int implement,
+                            lys_custom_check custom_check, void *check_data, struct lys_module **module);
 
 /**
  * @brief Parse submodule from a string.
@@ -549,11 +551,12 @@
  * @param[in] main_ctx Parser context of the main module.
  * @param[in] custom_check Callback to check the parsed schema before it is accepted.
  * @param[in] check_data Caller's data to pass to the custom_check callback.
- * @return Pointer to the data model structure or NULL on error.
+ * @param[out] submodule Parsed submodule.
+ * @return LY_ERR value.
  */
-struct lysp_submodule *lys_parse_mem_submodule(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format,
-                                               struct lys_parser_ctx *main_ctx, lys_custom_check custom_check,
-                                               void *check_data);
+LY_ERR lys_parse_mem_submodule(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format,
+                               struct lys_parser_ctx *main_ctx, lys_custom_check custom_check,
+                               void *check_data, struct lysp_submodule **submodule);
 
 /**
  * @brief Fill filepath value if available in input handler @p in
diff --git a/src/validation.c b/src/validation.c
index 631fde6..437ce21 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -117,7 +117,7 @@
     LY_CHECK_RET(lyd_diff_add(node, op, NULL, NULL, NULL, NULL, NULL, &new_diff));
 
     /* merge into existing diff */
-    ret = lyd_diff_merge(new_diff, diff);
+    ret = lyd_diff_merge_all(new_diff, diff);
 
     lyd_free_tree(new_diff);
     return ret;
@@ -1256,7 +1256,7 @@
  * @return LY_ERR value.
  */
 static LY_ERR
-_lyd_validate(struct lyd_node **tree, const struct lys_module *module, const struct ly_ctx *ctx, int val_opts,
+lyd_validate(struct lyd_node **tree, const struct lys_module *module, const struct ly_ctx *ctx, int val_opts,
               struct lyd_node **diff)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -1319,15 +1319,15 @@
 }
 
 API LY_ERR
-lyd_validate(struct lyd_node **tree, const struct ly_ctx *ctx, int val_opts, struct lyd_node **diff)
+lyd_validate_all(struct lyd_node **tree, const struct ly_ctx *ctx, int val_opts, struct lyd_node **diff)
 {
-    return _lyd_validate(tree, NULL, ctx, val_opts, diff);
+    return lyd_validate(tree, NULL, ctx, val_opts, diff);
 }
 
 API LY_ERR
 lyd_validate_module(struct lyd_node **tree, const struct lys_module *module, int val_opts, struct lyd_node **diff)
 {
-    return _lyd_validate(tree, module, NULL, val_opts, diff);
+    return lyd_validate(tree, module, NULL, val_opts, diff);
 }
 
 /**
diff --git a/src/xpath.c b/src/xpath.c
index 3a1f3df..55a0f6b 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -431,7 +431,7 @@
                 break;
             case LYD_ANYDATA_DATATREE:
                 LY_CHECK_RET(ly_out_new_memory(&buf, 0, &out));
-                rc = lyd_print(out, any->value.tree, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+                rc = lyd_print_all(out, any->value.tree, LYD_XML, 0);
                 ly_out_free(out, NULL, 0);
                 LY_CHECK_RET(rc < 0, -rc);
                 break;