plugins ext FEATURE initial schema-mount support

Only for XML data for now. Includes lots of other
changes needed to support this extension.
diff --git a/src/common.h b/src/common.h
index 7e80b1e..f8094d3 100644
--- a/src/common.h
+++ b/src/common.h
@@ -328,6 +328,8 @@
                                            more times */
     uint16_t flags;                   /**< context settings, see @ref contextoptions */
 
+    ly_ext_data_clb ext_clb;          /**< optional callback for providing extension-specific run-time data for extensions */
+    void *ext_clb_data;               /**< optional private data for ::ly_ctx.ext_clb */
     pthread_key_t errlist_key;        /**< key for the thread-specific list of errors related to the context */
     pthread_mutex_t lyb_hash_lock;    /**< lock for storing LYB schema hashes in schema nodes */
 };
diff --git a/src/context.c b/src/context.c
index 3d79958..15043d3 100644
--- a/src/context.c
+++ b/src/context.c
@@ -319,7 +319,7 @@
 }
 
 static LY_ERR
-ly_ctx_new_yl_legacy(struct ly_ctx *ctx, struct lyd_node *yltree)
+ly_ctx_new_yl_legacy(struct ly_ctx *ctx, const struct lyd_node *yltree)
 {
     struct lyd_node *module, *node;
     struct ly_set *set;
@@ -329,11 +329,12 @@
     ly_bool imported = 0;
     const struct lys_module *mod;
     LY_ERR ret = LY_SUCCESS;
+    uint32_t i, j;
 
     LY_CHECK_RET(ret = lyd_find_xpath(yltree, "/ietf-yang-library:yang-library/modules-state/module", &set));
 
     /* process the data tree */
-    for (uint32_t i = 0; i < set->count; ++i) {
+    for (i = 0; i < set->count; ++i) {
         module = set->dnodes[i];
 
         /* initiate */
@@ -365,8 +366,8 @@
         LY_CHECK_ERR_GOTO(!feature_arr, ret = LY_EMEM, cleanup);
 
         /* Parse features into an array of strings */
-        for (uint32_t u = 0; u < features.count; u++) {
-            feature_arr[u] = lyd_get_value(features.dnodes[u]);
+        for (j = 0; j < features.count; ++j) {
+            feature_arr[j] = lyd_get_value(features.dnodes[j]);
         }
         feature_arr[features.count] = NULL;
         ly_set_clean(&features, free);
@@ -387,32 +388,72 @@
     return ret;
 }
 
-static LY_ERR
-ly_ctx_new_yl_common(const char *search_dir, const char *input, LYD_FORMAT format, int options,
-        LY_ERR (*parser_func)(const struct ly_ctx *, const char *, LYD_FORMAT, uint32_t, uint32_t, struct lyd_node **),
-        struct ly_ctx **ctx)
+LIBYANG_API_DEF LY_ERR
+ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format, int options, struct ly_ctx **ctx)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct ly_ctx *ctx_yl = NULL;
+    struct lyd_node *data_yl = NULL;
+
+    LY_CHECK_ARG_RET(NULL, path, ctx, LY_EINVAL);
+
+    /* create a seperate context for the data */
+    LY_CHECK_GOTO(ret = ly_ctx_new(search_dir, 0, &ctx_yl), cleanup);
+
+    /* parse yang library data tree */
+    LY_CHECK_GOTO(ret = lyd_parse_data_path(ctx_yl, path, format, 0, LYD_VALIDATE_PRESENT, &data_yl), cleanup);
+
+    /* create the new context */
+    ret = ly_ctx_new_yldata(search_dir, data_yl, options, ctx);
+
+cleanup:
+    lyd_free_all(data_yl);
+    ly_ctx_destroy(ctx_yl);
+    return ret;
+}
+
+LIBYANG_API_DEF LY_ERR
+ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format, int options, struct ly_ctx **ctx)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct ly_ctx *ctx_yl = NULL;
+    struct lyd_node *data_yl = NULL;
+
+    LY_CHECK_ARG_RET(NULL, data, ctx, LY_EINVAL);
+
+    /* create a seperate context for the data */
+    LY_CHECK_GOTO(ret = ly_ctx_new(search_dir, 0, &ctx_yl), cleanup);
+
+    /* parse yang library data tree */
+    LY_CHECK_GOTO(ret = lyd_parse_data_mem(ctx_yl, data, format, 0, LYD_VALIDATE_PRESENT, &data_yl), cleanup);
+
+    /* create the new context */
+    ret = ly_ctx_new_yldata(search_dir, data_yl, options, ctx);
+
+cleanup:
+    lyd_free_all(data_yl);
+    ly_ctx_destroy(ctx_yl);
+    return ret;
+}
+
+LIBYANG_API_DEF LY_ERR
+ly_ctx_new_yldata(const char *search_dir, const struct lyd_node *tree, int options, struct ly_ctx **ctx)
 {
     const char *name = NULL, *revision = NULL;
     struct lyd_node *module, *node;
-    struct lyd_node *yltree = NULL;
     struct ly_set *set = NULL;
     const char **feature_arr = NULL;
     struct ly_set features = {0};
     LY_ERR ret = LY_SUCCESS;
     const struct lys_module *mod;
-    struct ly_ctx *ctx_yl = NULL, *ctx_new = NULL;
+    struct ly_ctx *ctx_new = NULL;
     ly_bool no_expl_compile = 0;
+    uint32_t i, j;
 
-    /* create a seperate context in case it is LY_CTX_NO_YANGLIBRARY since it needs it for parsing */
-    if (options & LY_CTX_NO_YANGLIBRARY) {
-        LY_CHECK_GOTO(ret = ly_ctx_new(search_dir, 0, &ctx_yl), cleanup);
-        LY_CHECK_GOTO(ret = ly_ctx_new(search_dir, options, &ctx_new), cleanup);
-    } else {
-        LY_CHECK_GOTO(ret = ly_ctx_new(search_dir, options, &ctx_new), cleanup);
-    }
+    LY_CHECK_ARG_RET(NULL, tree, ctx, LY_EINVAL);
 
-    /* parse yang library data tree */
-    LY_CHECK_GOTO(ret = parser_func(ctx_yl ? ctx_yl : ctx_new, input, format, 0, LYD_VALIDATE_PRESENT, &yltree), cleanup);
+    /* create a new context */
+    LY_CHECK_GOTO(ret = ly_ctx_new(search_dir, options, &ctx_new), cleanup);
 
     /* redundant to compile modules one-by-one */
     if (!(options & LY_CTX_EXPLICIT_COMPILE)) {
@@ -420,20 +461,20 @@
         no_expl_compile = 1;
     }
 
-    LY_CHECK_GOTO(ret = lyd_find_xpath(yltree, "/ietf-yang-library:yang-library/module-set[1]/module", &set), cleanup);
+    LY_CHECK_GOTO(ret = lyd_find_xpath(tree, "/ietf-yang-library:yang-library/module-set[1]/module", &set), cleanup);
     if (set->count == 0) {
         /* perhaps a legacy data tree? */
-        LY_CHECK_GOTO(ret = ly_ctx_new_yl_legacy(ctx_new, yltree), cleanup);
+        LY_CHECK_GOTO(ret = ly_ctx_new_yl_legacy(ctx_new, tree), cleanup);
     } else {
         /* process the data tree */
-        for (uint32_t i = 0; i < set->count; ++i) {
+        for (i = 0; i < set->count; ++i) {
             module = set->dnodes[i];
 
             /* initiate */
             name = NULL;
             revision = NULL;
 
-            /* Iterate over data */
+            /* iterate over data */
             LY_LIST_FOR(lyd_child(module), node) {
                 if (!strcmp(node->schema->name, "name")) {
                     name = lyd_get_value(node);
@@ -447,9 +488,9 @@
             feature_arr = malloc((features.count + 1) * sizeof *feature_arr);
             LY_CHECK_ERR_GOTO(!feature_arr, ret = LY_EMEM, cleanup);
 
-            /* Parse features into an array of strings */
-            for (uint32_t u = 0; u < features.count; u++) {
-                feature_arr[u] = lyd_get_value(features.dnodes[u]);
+            /* parse features into an array of strings */
+            for (j = 0; j < features.count; ++j) {
+                feature_arr[j] = lyd_get_value(features.dnodes[j]);
             }
             feature_arr[features.count] = NULL;
             ly_set_clean(&features, NULL);
@@ -466,10 +507,6 @@
         }
     }
 
-    /* free data because their context may be recompiled */
-    lyd_free_all(yltree);
-    yltree = NULL;
-
     /* compile */
     LY_CHECK_GOTO(ret = ly_ctx_compile(ctx_new), cleanup);
 
@@ -479,34 +516,17 @@
     }
 
 cleanup:
-    lyd_free_all(yltree);
     ly_set_free(set, NULL);
     ly_set_erase(&features, NULL);
-    ly_ctx_destroy(ctx_yl);
     *ctx = ctx_new;
     if (ret) {
         ly_ctx_destroy(*ctx);
         *ctx = NULL;
     }
-
     return ret;
 }
 
 LIBYANG_API_DEF LY_ERR
-ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format, int options, struct ly_ctx **ctx)
-{
-    LY_CHECK_ARG_RET(NULL, path, ctx, LY_EINVAL);
-    return ly_ctx_new_yl_common(search_dir, path, format, options, lyd_parse_data_path, ctx);
-}
-
-LIBYANG_API_DEF LY_ERR
-ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format, int options, struct ly_ctx **ctx)
-{
-    LY_CHECK_ARG_RET(NULL, data, ctx, LY_EINVAL);
-    return ly_ctx_new_yl_common(search_dir, data, format, options, lyd_parse_data_mem, ctx);
-}
-
-LIBYANG_API_DEF LY_ERR
 ly_ctx_compile(struct ly_ctx *ctx)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -641,15 +661,6 @@
     return ctx->change_count;
 }
 
-LIBYANG_API_DEF void
-ly_ctx_set_module_imp_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data)
-{
-    LY_CHECK_ARG_RET(ctx, ctx, );
-
-    ctx->imp_clb = clb;
-    ctx->imp_clb_data = user_data;
-}
-
 LIBYANG_API_DEF ly_module_imp_clb
 ly_ctx_get_module_imp_clb(const struct ly_ctx *ctx, void **user_data)
 {
@@ -661,6 +672,29 @@
     return ctx->imp_clb;
 }
 
+LIBYANG_API_DEF void
+ly_ctx_set_module_imp_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data)
+{
+    LY_CHECK_ARG_RET(ctx, ctx, );
+
+    ctx->imp_clb = clb;
+    ctx->imp_clb_data = user_data;
+}
+
+LIBYANG_API_DEF ly_ext_data_clb
+ly_ctx_set_ext_data_clb(struct ly_ctx *ctx, ly_ext_data_clb clb, void *user_data)
+{
+    ly_ext_data_clb prev;
+
+    LY_CHECK_ARG_RET(ctx, ctx, NULL);
+
+    prev = ctx->ext_clb;
+    ctx->ext_clb = clb;
+    ctx->ext_clb_data = user_data;
+
+    return prev;
+}
+
 LIBYANG_API_DEF struct lys_module *
 ly_ctx_get_module_iter(const struct ly_ctx *ctx, uint32_t *index)
 {
diff --git a/src/context.h b/src/context.h
index fdd87e2..8752e56 100644
--- a/src/context.h
+++ b/src/context.h
@@ -224,7 +224,7 @@
 LIBYANG_API_DECL LY_ERR ly_ctx_new(const char *search_dir, uint16_t options, struct ly_ctx **new_ctx);
 
 /**
- * @brief Create libyang context according to the content of the given yang-library data.
+ * @brief Create libyang context according to the provided yang-library data in a file.
  *
  * This function loads the yang-library data from the given path. If you need to pass the data as
  * string, use ::::ly_ctx_new_ylmem(). Both functions extend functionality of ::ly_ctx_new() by loading
@@ -244,20 +244,13 @@
  * @param[out] ctx Pointer to the created libyang context if LY_SUCCESS returned.
  * @return LY_ERR return value
  */
-LIBYANG_API_DECL LY_ERR ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format, int options, struct ly_ctx **ctx);
+LIBYANG_API_DECL LY_ERR ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format, int options,
+        struct ly_ctx **ctx);
 
 /**
- * @brief Create libyang context according to the content of the given yang-library data.
+ * @brief Create libyang context according to the provided yang-library data in a string.
  *
- * This function loads the yang-library data from the given string. If you need to pass the data as
- * path to a file holding the data, use ::ly_ctx_new_ylpath(). Both functions extend functionality of
- * ::ly_ctx_new() by loading modules specified in the ietf-yang-library form into the context being created.
- * The preferred tree model revision is 2019-01-04. However, only the first module-set is processed and loaded
- * into the context. If there are no matching nodes from this tree, the legacy tree (originally from model revision 2016-04-09)
- * is processed. Note, that the modules are loaded the same way as in case of ::ly_ctx_load_module(), so the schema paths in the
- * yang-library data are ignored and the modules are loaded from the context's search locations. On the other hand, YANG features
- * of the modules are set as specified in the yang-library data.
- * To get yang library data from a libyang context, use ::ly_ctx_get_yanglib_data().
+ * Details in ::ly_ctx_new_ylpath().
  *
  * @param[in] search_dir Directory where libyang will search for the imported or included modules and submodules.
  * If no such directory is available, NULL is accepted.
@@ -267,7 +260,23 @@
  * @param[out] ctx Pointer to the created libyang context if LY_SUCCESS returned.
  * @return LY_ERR return value
  */
-LIBYANG_API_DECL LY_ERR ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format, int options, struct ly_ctx **ctx);
+LIBYANG_API_DECL LY_ERR ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format, int options,
+        struct ly_ctx **ctx);
+
+/**
+ * @brief Create libyang context according to the provided yang-library data in a data tree.
+ *
+ * Details in ::ly_ctx_new_ylpath().
+ *
+ * @param[in] search_dir Directory where libyang will search for the imported or included modules and submodules.
+ * If no such directory is available, NULL is accepted.
+ * @param[in] tree Data tree containing yang-library data.
+ * @param[in] options Context options, see @ref contextoptions.
+ * @param[out] ctx Pointer to the created libyang context if LY_SUCCESS returned.
+ * @return LY_ERR return value
+ */
+LIBYANG_API_DECL LY_ERR ly_ctx_new_yldata(const char *search_dir, const struct lyd_node *tree, int options,
+        struct ly_ctx **ctx);
 
 /**
  * @brief Compile (recompile) the context applying all the performed changes after the last context compilation.
@@ -410,6 +419,11 @@
  */
 LIBYANG_API_DECL void ly_ctx_set_module_imp_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data);
 
+typedef LY_ERR (*ly_ext_data_clb)(const struct lysc_ext_instance *ext, void *user_data, void **ext_data,
+        ly_bool *ext_data_free);
+
+LIBYANG_API_DECL ly_ext_data_clb ly_ctx_set_ext_data_clb(struct ly_ctx *ctx, ly_ext_data_clb clb, void *user_data);
+
 /**
  * @brief Get YANG module of the given name and revision.
  *
diff --git a/src/in.c b/src/in.c
index c16b1c3..b893dd2 100644
--- a/src/in.c
+++ b/src/in.c
@@ -58,6 +58,16 @@
 }
 
 LIBYANG_API_DEF LY_ERR
+ly_in_reset(struct ly_in *in)
+{
+    LY_CHECK_ARG_RET(NULL, in, LY_EINVAL);
+
+    in->current = in->func_start = in->start;
+    in->line = 1;
+    return LY_SUCCESS;
+}
+
+LIBYANG_API_DEF LY_ERR
 ly_in_new_fd(int fd, struct ly_in **in)
 {
     size_t length;
@@ -186,16 +196,6 @@
 }
 
 LIBYANG_API_DEF LY_ERR
-ly_in_reset(struct ly_in *in)
-{
-    LY_CHECK_ARG_RET(NULL, in, LY_EINVAL);
-
-    in->current = in->func_start = in->start;
-    in->line = 1;
-    return LY_SUCCESS;
-}
-
-LIBYANG_API_DEF LY_ERR
 ly_in_new_filepath(const char *filepath, size_t len, struct ly_in **in)
 {
     LY_ERR ret;
@@ -318,6 +318,12 @@
 
 }
 
+LIBYANG_API_DEF size_t
+ly_in_parsed(const struct ly_in *in)
+{
+    return in->current - in->func_start;
+}
+
 LIBYANG_API_DEF void
 ly_in_free(struct ly_in *in, ly_bool destroy)
 {
@@ -371,12 +377,6 @@
     return LY_SUCCESS;
 }
 
-LIBYANG_API_DEF size_t
-ly_in_parsed(const struct ly_in *in)
-{
-    return in->current - in->func_start;
-}
-
 LY_ERR
 ly_in_skip(struct ly_in *in, size_t count)
 {
@@ -395,7 +395,7 @@
     ly_set_erase(&lydctx->node_types, NULL);
     ly_set_erase(&lydctx->meta_types, NULL);
     ly_set_erase(&lydctx->node_when, NULL);
-    ly_set_erase(&lydctx->node_exts, NULL);
+    ly_set_erase(&lydctx->ext_val, free);
 }
 
 LY_ERR
@@ -525,7 +525,7 @@
 LY_ERR
 lyd_parser_create_meta(struct lyd_ctx *lydctx, struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod,
         const char *name, size_t name_len, const void *value, size_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format,
-        void *prefix_data, uint32_t hints)
+        void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node)
 {
     ly_bool incomplete;
     struct lyd_meta *first = NULL;
@@ -536,7 +536,7 @@
     }
 
     LY_CHECK_RET(lyd_create_meta(parent, meta, mod, name, name_len, value, value_len, dynamic, format, prefix_data,
-            hints, 0, &incomplete));
+            hints, ctx_node, 0, &incomplete));
 
     if (incomplete && !(lydctx->parse_opts & LYD_PARSE_ONLY)) {
         LY_CHECK_RET(ly_set_add(&lydctx->meta_types, *meta, 1, NULL));
diff --git a/src/log.h b/src/log.h
index d67eb96..e9a7c5b 100644
--- a/src/log.h
+++ b/src/log.h
@@ -241,8 +241,7 @@
  * @typedef LY_ERR
  * @brief libyang's error codes returned by the libyang functions.
  */
-typedef enum
-{
+typedef enum {
     LY_SUCCESS = 0, /**< no error, not set by functions, included just to complete #LY_ERR enumeration */
     LY_EMEM,        /**< Memory allocation failure */
     LY_ESYS,        /**< System call failure */
diff --git a/src/parser_data.h b/src/parser_data.h
index 53f03dc..79898ab 100644
--- a/src/parser_data.h
+++ b/src/parser_data.h
@@ -157,6 +157,9 @@
                                                  modified manually. If this flag is used incorrectly (for unordered data),
                                                  the behavior is undefined and most functions executed with these
                                                  data will not work correctly. */
+#define LYD_PARSE_SUBTREE 0x400000          /**< Parse only the current data subtree with any descendants, no siblings.
+                                                 Also, a new return value ::LY_ENOT is returned if there is a sibling
+                                                 subtree following in the input data. */
 
 #define LYD_PARSE_OPTS_MASK 0xFFFF0000      /**< Mask for all the LYD_PARSE_ options. */
 
@@ -258,8 +261,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.
  */
-LIBYANG_API_DECL LY_ERR lyd_parse_data_path(const struct ly_ctx *ctx, const char *path, LYD_FORMAT format, uint32_t parse_options,
-        uint32_t validate_options, struct lyd_node **tree);
+LIBYANG_API_DECL LY_ERR lyd_parse_data_path(const struct ly_ctx *ctx, const char *path, LYD_FORMAT format,
+        uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree);
 
 /**
  * @brief Parse (and validate) data from the input handler as an extension data tree following the schema tree of the given
@@ -280,8 +283,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.
  */
-LIBYANG_API_DECL LY_ERR lyd_parse_ext_data(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
-        uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree);
+LIBYANG_API_DECL LY_ERR lyd_parse_ext_data(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in,
+        LYD_FORMAT format, uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree);
 
 /**
  * @ingroup datatree
@@ -394,13 +397,13 @@
  * @return LY_ERR value.
  * @return LY_ENOT if @p data_type is a NETCONF message and the root XML element is not the expected one.
  */
-LIBYANG_API_DECL LY_ERR lyd_parse_ext_op(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
-        enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op);
+LIBYANG_API_DECL LY_ERR lyd_parse_ext_op(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in,
+        LYD_FORMAT format, enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op);
 
 /**
  * @brief Fully validate a data tree.
  *
- * The data tree is modified in-place.  As a result of the validation, some data might be removed
+ * The data tree is modified in-place. As a result of the validation, some data might be removed
  * from the tree. In that case, the removed items are freed, not just unlinked.
  *
  * @param[in,out] tree Data tree to recursively validate. May be changed by validation, might become NULL.
@@ -410,12 +413,13 @@
  * @return LY_SUCCESS on success.
  * @return LY_ERR error on error.
  */
-LIBYANG_API_DECL LY_ERR lyd_validate_all(struct lyd_node **tree, const struct ly_ctx *ctx, uint32_t val_opts, struct lyd_node **diff);
+LIBYANG_API_DECL LY_ERR lyd_validate_all(struct lyd_node **tree, const struct ly_ctx *ctx, uint32_t val_opts,
+        struct lyd_node **diff);
 
 /**
  * @brief Fully validate a data tree of a module.
  *
- * The data tree is modified in-place.  As a result of the validation, some data might be removed
+ * The data tree is modified in-place. As a result of the validation, some data might be removed
  * from the tree. In that case, the removed items are freed, not just unlinked.
  *
  * @param[in,out] tree Data tree to recursively validate. May be changed by validation, might become NULL.
@@ -425,7 +429,8 @@
  * @return LY_SUCCESS on success.
  * @return LY_ERR error on error.
  */
-LIBYANG_API_DECL LY_ERR lyd_validate_module(struct lyd_node **tree, const struct lys_module *module, uint32_t val_opts, struct lyd_node **diff);
+LIBYANG_API_DECL LY_ERR lyd_validate_module(struct lyd_node **tree, const struct lys_module *module, uint32_t val_opts,
+        struct lyd_node **diff);
 
 /**
  * @brief Validate an RPC/action request, reply, or notification.
diff --git a/src/parser_internal.h b/src/parser_internal.h
index dba6078..67baeed 100644
--- a/src/parser_internal.h
+++ b/src/parser_internal.h
@@ -56,9 +56,9 @@
 #define LYD_PARSER_BUFSIZE 4078
     char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
     struct ly_set node_when;       /**< set of nodes with "when" conditions */
-    struct ly_set node_exts;       /**< set of nodes and extensions connected with a plugin providing own validation callback */
     struct ly_set node_types;      /**< set of nodes validated with LY_EINCOMPLETE result */
     struct ly_set meta_types;      /**< set of metadata validated with LY_EINCOMPLETE result */
+    struct ly_set ext_val;         /**< set of first siblings parsed by extensions to validate */
     struct lyd_node *op_node;      /**< if an RPC/action/notification is being parsed, store the pointer to it */
 
     /* callbacks */
@@ -82,9 +82,9 @@
     uint32_t path_len;
     char path[LYD_PARSER_BUFSIZE];
     struct ly_set node_when;
-    struct ly_set node_exts;
     struct ly_set node_types;
     struct ly_set meta_types;
+    struct ly_set ext_val;
     struct lyd_node *op_node;
 
     /* callbacks */
@@ -104,9 +104,9 @@
     uint32_t path_len;
     char path[LYD_PARSER_BUFSIZE];
     struct ly_set node_when;
-    struct ly_set node_exts;
     struct ly_set node_types;
     struct ly_set meta_types;
+    struct ly_set ext_val;
     struct lyd_node *op_node;
 
     /* callbacks */
@@ -131,9 +131,9 @@
     uint32_t path_len;
     char path[LYD_PARSER_BUFSIZE];
     struct ly_set node_when;
-    struct ly_set node_exts;
     struct ly_set node_types;
     struct ly_set meta_types;
+    struct ly_set ext_val;
     struct lyd_node *op_node;
 
     /* callbacks */
@@ -143,9 +143,17 @@
 };
 
 /**
+ * @brief Parsed extension instance data to validate.
+ */
+struct lyd_ctx_ext_val {
+    struct lysc_ext_instance *ext;
+    struct lyd_node *sibling;
+};
+
+/**
  * @brief Common part to supplement the specific ::lyd_ctx_free_clb callbacks.
  */
-void lyd_ctx_free(struct lyd_ctx *);
+void lyd_ctx_free(struct lyd_ctx *ctx);
 
 /**
  * @brief Parse submodule from YANG data.
@@ -207,12 +215,13 @@
  * @param[out] envp Individual parsed envelopes tree, returned only by specific @p data_type and possibly even if
  * an error occurs later.
  * @param[out] parsed Set to add all the parsed siblings into.
+ * @param[out] subtree_sibling Set if ::LYD_PARSE_SUBTREE is used and another subtree is following in @p in.
  * @param[out] lydctx_p Data parser context to finish validation.
  * @return LY_ERR value.
  */
 LY_ERR lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
         struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
-        struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p);
+        struct lyd_node **envp, struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p);
 
 /**
  * @brief Parse JSON string as a YANG data tree.
@@ -226,12 +235,13 @@
  * @param[in] val_opts Options for the validation phase, see @ref datavalidationoptions.
  * @param[in] data_type Expected data type of the data.
  * @param[out] parsed Set to add all the parsed siblings into.
+ * @param[out] subtree_sibling Set if ::LYD_PARSE_SUBTREE is used and another subtree is following in @p in.
  * @param[out] lydctx_p Data parser context to finish validation.
  * @return LY_ERR value.
  */
 LY_ERR lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
         struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
-        struct ly_set *parsed, struct lyd_ctx **lydctx_p);
+        struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p);
 
 /**
  * @brief Parse binary LYB data as a YANG data tree.
@@ -245,12 +255,13 @@
  * @param[in] val_opts Options for the validation phase, see @ref datavalidationoptions.
  * @param[in] data_type Expected data type of the data.
  * @param[out] parsed Set to add all the parsed siblings into.
+ * @param[out] subtree_sibling Set if ::LYD_PARSE_SUBTREE is used and another subtree is following in @p in.
  * @param[out] lydctx_p Data parser context to finish validation.
  * @return LY_ERR value.
  */
 LY_ERR lyd_parse_lyb(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
         struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
-        struct ly_set *parsed, struct lyd_ctx **lydctx_p);
+        struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p);
 
 /**
  * @brief Search all the parents for an operation node, check validity based on internal parser flags.
@@ -305,10 +316,11 @@
  * @param[in] format Prefix format.
  * @param[in] prefix_data Prefix format data (see ::ly_resolve_prefix()).
  * @param[in] hints [Value hint](@ref lydvalhints) from the parser regarding the value type.
+ * @param[in] ctx_node Value context node.
  * @return LY_ERR value.
  */
 LY_ERR lyd_parser_create_meta(struct lyd_ctx *lydctx, struct lyd_node *parent, struct lyd_meta **meta,
-        const struct lys_module *mod, const char *name, size_t name_len, const void *value,
-        size_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints);
+        const struct lys_module *mod, const char *name, size_t name_len, const void *value, size_t value_len,
+        ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node);
 
 #endif /* LY_PARSER_INTERNAL_H_ */
diff --git a/src/parser_json.c b/src/parser_json.c
index eb62897..e1dd7fe 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -614,7 +614,7 @@
                     if (mod) {
                         ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, node, NULL, mod,
                                 meta->name.name, strlen(meta->name.name), meta->value, ly_strlen(meta->value),
-                                NULL, LY_VALUE_JSON, NULL, meta->hints);
+                                NULL, LY_VALUE_JSON, NULL, meta->hints, node->schema);
                         LY_CHECK_GOTO(ret, cleanup);
                     } else if (lydctx->parse_opts & LYD_PARSE_STRICT) {
                         if (meta->name.prefix) {
@@ -631,7 +631,7 @@
                     }
                 }
                 /* add/correct flags */
-                lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &node->meta, lydctx->parse_opts);
+                lyd_parse_set_data_flags(node, &lydctx->node_when, &node->meta, lydctx->parse_opts);
 
                 /* done */
                 break;
@@ -812,12 +812,11 @@
             /* create metadata */
             meta = NULL;
             ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, node, &meta, mod, name, name_len, lydctx->jsonctx->value,
-                    lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic, LY_VALUE_JSON, NULL,
-                    LYD_HINT_DATA);
+                    lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic, LY_VALUE_JSON, NULL, LYD_HINT_DATA, node->schema);
             LY_CHECK_GOTO(ret, cleanup);
 
             /* add/correct flags */
-            lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &meta, lydctx->parse_opts);
+            lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_opts);
         } else {
             /* create attribute */
             const char *module_name;
@@ -1239,7 +1238,7 @@
                 LY_CHECK_ERR_RET(ret, LOG_LOCBACK(1, 1, 0, 0), ret);
 
                 /* add any missing default children */
-                ret = lyd_new_implicit_r(*node, lyd_node_child_p(*node), NULL, NULL, &lydctx->node_when, &lydctx->node_exts,
+                ret = lyd_new_implicit_r(*node, lyd_node_child_p(*node), NULL, NULL, &lydctx->node_when,
                         &lydctx->node_types, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
                 LY_CHECK_ERR_RET(ret, LOG_LOCBACK(1, 1, 0, 0), ret);
             }
@@ -1280,7 +1279,7 @@
         LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status));
 
         /* add/correct flags */
-        lyd_parse_set_data_flags(*node, &lydctx->node_when, &lydctx->node_exts, &(*node)->meta, lydctx->parse_opts);
+        lyd_parse_set_data_flags(*node, &lydctx->node_when, &(*node)->meta, lydctx->parse_opts);
     } else if (ret == LY_ENOT) {
         /* parse it again as an opaq node */
         ret = lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent,
@@ -1533,7 +1532,7 @@
 LY_ERR
 lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
         struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
-        struct ly_set *parsed, struct lyd_ctx **lydctx_p)
+        struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
 {
     LY_ERR rc = LY_SUCCESS;
     struct lyd_json_ctx *lydctx = NULL;
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index 3352ed9..2cd4158 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -414,11 +414,12 @@
  * @brief Parse YANG node metadata.
  *
  * @param[in] lybctx LYB context.
+ * @param[in] sparent Schema parent node of the metadata.
  * @param[out] meta Parsed metadata.
  * @return LY_ERR value.
  */
 static LY_ERR
-lyb_parse_metadata(struct lyd_lyb_ctx *lybctx, struct lyd_meta **meta)
+lyb_parse_metadata(struct lyd_lyb_ctx *lybctx, const struct lysc_node *sparent, struct lyd_meta **meta)
 {
     LY_ERR ret = LY_SUCCESS;
     ly_bool dynamic;
@@ -455,7 +456,7 @@
 
         /* create metadata */
         ret = lyd_parser_create_meta((struct lyd_ctx *)lybctx, NULL, meta, mod, meta_name, strlen(meta_name), meta_value,
-                ly_strlen(meta_value), &dynamic, LY_VALUE_JSON, NULL, LYD_HINT_DATA);
+                ly_strlen(meta_value), &dynamic, LY_VALUE_JSON, NULL, LYD_HINT_DATA, sparent);
 
         /* free strings */
         free(meta_name);
@@ -927,17 +928,18 @@
  * @brief Parse header for non-opaq node.
  *
  * @param[in] lybctx LYB context.
+ * @param[in] sparent Schema parent node of the metadata.
  * @param[out] flags Parsed node flags.
  * @param[out] meta Parsed metadata of the node.
  * @return LY_ERR value.
  */
 static LY_ERR
-lyb_parse_node_header(struct lyd_lyb_ctx *lybctx, uint32_t *flags, struct lyd_meta **meta)
+lyb_parse_node_header(struct lyd_lyb_ctx *lybctx, const struct lysc_node *sparent, uint32_t *flags, struct lyd_meta **meta)
 {
     LY_ERR ret;
 
     /* create and read metadata */
-    ret = lyb_parse_metadata(lybctx, meta);
+    ret = lyb_parse_metadata(lybctx, sparent, meta);
     LY_CHECK_RET(ret);
 
     /* read flags */
@@ -1002,9 +1004,8 @@
 
         /* add any missing default children */
         impl_opts = (lybctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0;
-        ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL,
-                NULL, &lybctx->node_when, &lybctx->node_exts,
-                &lybctx->node_types, impl_opts, NULL);
+        ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lybctx->node_when, &lybctx->node_types,
+                impl_opts, NULL);
         LY_CHECK_RET(ret);
     }
 
@@ -1124,7 +1125,7 @@
     const struct ly_ctx *ctx = lybctx->lybctx->ctx;
 
     /* read necessary basic data */
-    ret = lyb_parse_node_header(lybctx, &flags, &meta);
+    ret = lyb_parse_node_header(lybctx, snode, &flags, &meta);
     LY_CHECK_GOTO(ret, error);
 
     /* parse value type */
@@ -1212,7 +1213,7 @@
     uint32_t flags;
 
     /* read necessary basic data */
-    ret = lyb_parse_node_header(lybctx, &flags, &meta);
+    ret = lyb_parse_node_header(lybctx, snode, &flags, &meta);
     LY_CHECK_GOTO(ret, error);
 
     /* create node */
@@ -1263,7 +1264,7 @@
     uint32_t flags;
 
     /* read necessary basic data */
-    ret = lyb_parse_node_header(lybctx, &flags, &meta);
+    ret = lyb_parse_node_header(lybctx, snode, &flags, &meta);
     LY_CHECK_GOTO(ret, error);
 
     /* read value of term node and create it */
@@ -1338,7 +1339,7 @@
 
     while (LYB_LAST_SIBLING(lybctx->lybctx).written) {
         /* read necessary basic data */
-        ret = lyb_parse_node_header(lybctx, &flags, &meta);
+        ret = lyb_parse_node_header(lybctx, snode, &flags, &meta);
         LY_CHECK_GOTO(ret, error);
 
         /* create list node */
@@ -1619,13 +1620,15 @@
 LY_ERR
 lyd_parse_lyb(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
         struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
-        struct ly_set *parsed, struct lyd_ctx **lydctx_p)
+        struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
 {
     uint32_t int_opts;
 
     assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
     assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
 
+    LY_CHECK_ARG_RET(ctx, !(parse_opts & LYD_PARSE_SUBTREE), LY_EINVAL);
+
     switch (data_type) {
     case LYD_TYPE_DATA_YANG:
         int_opts = LYD_INTOPT_WITH_SIBLINGS;
@@ -1644,6 +1647,9 @@
         return LY_EINT;
     }
 
+    if (subtree_sibling) {
+        *subtree_sibling = 0;
+    }
     return _lyd_parse_lyb(ctx, ext, parent, first_p, in, parse_opts, val_opts, int_opts, parsed, lydctx_p);
 }
 
diff --git a/src/parser_xml.c b/src/parser_xml.c
index fcfc8f9..e874231 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -48,12 +48,12 @@
  * @brief Parse and create XML metadata.
  *
  * @param[in] lydctx XML data parser context.
- * @param[in] parent_exts Extension instances of the parent node.
+ * @param[in] sparent Schema node of the parent.
  * @param[out] meta List of created metadata instances.
  * @return LY_ERR value.
  */
 static LY_ERR
-lydxml_metadata(struct lyd_xml_ctx *lydctx, struct lysc_ext_instance *parent_exts, struct lyd_meta **meta)
+lydxml_metadata(struct lyd_xml_ctx *lydctx, const struct lysc_node *sparent, struct lyd_meta **meta)
 {
     LY_ERR ret = LY_SUCCESS;
     const struct lyxml_ns *ns;
@@ -67,9 +67,9 @@
     *meta = NULL;
 
     /* check for NETCONF filter unqualified attributes */
-    LY_ARRAY_FOR(parent_exts, u) {
-        if (!strcmp(parent_exts[u].def->name, "get-filter-element-attributes") &&
-                !strcmp(parent_exts[u].def->module->name, "ietf-netconf")) {
+    LY_ARRAY_FOR(sparent->exts, u) {
+        if (!strcmp(sparent->exts[u].def->name, "get-filter-element-attributes") &&
+                !strcmp(sparent->exts[u].def->module->name, "ietf-netconf")) {
             filter_attrs = 1;
             break;
         }
@@ -141,7 +141,7 @@
 
         /* create metadata */
         ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
-                xmlctx->value_len, &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA);
+                xmlctx->value_len, &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, sparent);
         LY_CHECK_GOTO(ret, cleanup);
 
         /* next attribute */
@@ -407,6 +407,77 @@
 }
 
 /**
+ * @brief Try to parse data with a parent based on an extension instance.
+ *
+ * @param[in] lydctx XML data parser context.
+ * @param[in,out] parent Parent node where the children are inserted.
+ * @return LY_SUCCESS on success;
+ * @return LY_ENOT if no extension instance parsed the data;
+ * @return LY_ERR on error.
+ */
+static LY_ERR
+lydxml_nested_ext(struct lyd_xml_ctx *lydctx, struct lyd_node *parent)
+{
+    LY_ERR r;
+    struct ly_in in_bck, in_start, in_ext;
+    LY_ARRAY_COUNT_TYPE u;
+    struct lysc_ext_instance *nested_exts = NULL;
+    lyplg_ext_data_parse_clb ext_parse_cb;
+    struct lyd_ctx_ext_val *ext_val;
+
+    /* backup current input */
+    in_bck = *lydctx->xmlctx->in;
+
+    /* go back in the input for extension parsing */
+    in_start = *lydctx->xmlctx->in;
+    if (lydctx->xmlctx->status != LYXML_ELEM_CONTENT) {
+        assert((lydctx->xmlctx->status == LYXML_ELEMENT) || (lydctx->xmlctx->status == LYXML_ATTRIBUTE));
+        in_start.current = lydctx->xmlctx->prefix ? lydctx->xmlctx->prefix : lydctx->xmlctx->name;
+    }
+    do {
+        --in_start.current;
+    } while (in_start.current[0] != '<');
+
+    /* check if there are any nested extension instances */
+    if (parent && parent->schema) {
+        nested_exts = parent->schema->exts;
+    }
+    LY_ARRAY_FOR(nested_exts, u) {
+        /* prepare the input and try to parse this extension data */
+        in_ext = in_start;
+        ext_parse_cb = nested_exts[u].def->plugin->parse;
+        r = ext_parse_cb(&in_ext, LYD_XML, &nested_exts[u], parent, lydctx->parse_opts | LYD_PARSE_ONLY);
+        if (!r) {
+            /* data successfully parsed, remember for validation */
+            if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
+                ext_val = malloc(sizeof *ext_val);
+                LY_CHECK_ERR_RET(!ext_val, LOGMEM(lydctx->xmlctx->ctx), LY_EMEM);
+                ext_val->ext = &nested_exts[u];
+                ext_val->sibling = lyd_child(parent);
+                LY_CHECK_RET(ly_set_add(&lydctx->ext_val, ext_val, 1, NULL));
+            }
+
+            /* adjust the xmlctx accordingly */
+            *lydctx->xmlctx->in = in_ext;
+            lydctx->xmlctx->status = LYXML_ELEM_CONTENT;
+            lydctx->xmlctx->dynamic = 0;
+            ly_set_rm_index(&lydctx->xmlctx->elements, lydctx->xmlctx->elements.count - 1, free);
+            lyxml_ns_rm(lydctx->xmlctx);
+            LY_CHECK_RET(lyxml_ctx_next(lydctx->xmlctx));
+            return LY_SUCCESS;
+        } else if (r != LY_ENOT) {
+            /* fatal error */
+            return r;
+        }
+        /* data was not from this module, continue */
+    }
+
+    /* no extensions or none matched, restore input */
+    *lydctx->xmlctx->in = in_bck;
+    return LY_ENOT;
+}
+
+/**
  * @brief Parse XML subtree.
  *
  * @param[in] lydctx XML YANG data parser context.
@@ -420,9 +491,6 @@
 lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_set *parsed)
 {
     LY_ERR ret = LY_SUCCESS, r;
-    LY_ARRAY_COUNT_TYPE u;
-
-    lyplg_ext_data_parse_clb ext_parse;
     const char *prefix, *name, *val;
     size_t prefix_len, name_len;
     struct lyxml_ctx *xmlctx;
@@ -435,9 +503,9 @@
     uint32_t prev_parse_opts, prev_int_opts;
     struct lyd_node *node = NULL, *anchor;
     void *val_prefix_data = NULL;
-    struct lysc_ext_instance *exts = NULL;
     LY_VALUE_FORMAT format;
     uint32_t getnext_opts;
+    ly_bool parse_subtree;
 
     assert(parent || first_p);
 
@@ -445,6 +513,10 @@
     ctx = xmlctx->ctx;
     getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
 
+    parse_subtree = lydctx->parse_opts & LYD_PARSE_SUBTREE ? 1 : 0;
+    /* all descendants should be parsed */
+    lydctx->parse_opts &= ~LYD_PARSE_SUBTREE;
+
     assert(xmlctx->status == LYXML_ELEMENT);
 
     /* remember element prefix and name */
@@ -462,6 +534,18 @@
     }
     mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
     if (!mod) {
+        /* check for extension data */
+        r = lydxml_nested_ext(lydctx, parent);
+        if (!r) {
+            /* successfully parsed */
+            return r;
+        } else if (r != LY_ENOT) {
+            /* error */
+            ret = r;
+            goto error;
+        }
+
+        /* unknown module */
         if (lydctx->parse_opts & LYD_PARSE_STRICT) {
             LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
             ret = LY_EVALID;
@@ -486,22 +570,18 @@
             snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
         }
         if (!snode) {
-            /* Check if data of an extension */
-            if (parent && parent->schema) {
-                exts = parent->schema->exts;
+            /* check for extension data */
+            r = lydxml_nested_ext(lydctx, parent);
+            if (!r) {
+                /* successfully parsed */
+                return r;
+            } else if (r != LY_ENOT) {
+                /* error */
+                ret = r;
+                goto error;
             }
-            LY_ARRAY_FOR(exts, u) {
-                ext_parse = exts[u].def->plugin->parse;
-                r = ext_parse(xmlctx->in, LYD_XML, &exts[u], parent, lydctx->parse_opts,
-                        lydctx->val_opts);
-                if (r == LY_SUCCESS) {
-                    /* Data was from this module*/
-                    return LY_SUCCESS;
-                } else if (r != LY_ENOT) {
-                    /* Error while parsing */
-                }
-                /* Data was not from this module */
-            }
+
+            /* unknown data node */
             if (lydctx->parse_opts & LYD_PARSE_STRICT) {
                 if (parent) {
                     LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
@@ -537,7 +617,7 @@
     /* create metadata/attributes */
     if (xmlctx->status == LYXML_ATTRIBUTE) {
         if (snode) {
-            ret = lydxml_metadata(lydctx, snode->exts, &meta);
+            ret = lydxml_metadata(lydctx, snode, &meta);
             LY_CHECK_GOTO(ret, error);
         } else {
             assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
@@ -648,8 +728,8 @@
             LY_CHECK_GOTO(ret, error);
 
             /* add any missing default children */
-            ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_exts,
-                    &lydctx->node_types, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
+            ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_types,
+                    (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
             LY_CHECK_GOTO(ret, error);
         }
 
@@ -711,12 +791,14 @@
 
     /* add/correct flags */
     if (snode) {
-        lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &meta, lydctx->parse_opts);
+        lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_opts);
     }
 
     /* parser next */
     assert(xmlctx->status == LYXML_ELEM_CLOSE);
-    LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
+    if (!parse_subtree) {
+        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
+    }
 
     /* add metadata/attributes */
     if (snode) {
@@ -1398,12 +1480,13 @@
 LY_ERR
 lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
         struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
-        struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
+        struct lyd_node **envp, struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
 {
     LY_ERR rc = LY_SUCCESS;
     struct lyd_xml_ctx *lydctx;
     uint32_t i, int_opts = 0, close_elem = 0;
     ly_bool parsed_data_nodes = 0;
+    enum LYXML_PARSER_STATUS status;
 
     assert(ctx && in && lydctx_p);
     assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
@@ -1420,7 +1503,9 @@
 
     switch (data_type) {
     case LYD_TYPE_DATA_YANG:
-        int_opts = LYD_INTOPT_WITH_SIBLINGS;
+        if (!(parse_opts & LYD_PARSE_SUBTREE)) {
+            int_opts = LYD_INTOPT_WITH_SIBLINGS;
+        }
         break;
     case LYD_TYPE_RPC_YANG:
         int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
@@ -1489,10 +1574,20 @@
         lydctx->op_node = NULL;
     }
 
+    if (parse_opts & LYD_PARSE_SUBTREE) {
+        /* check for a sibling element */
+        assert(subtree_sibling);
+        if (!lyxml_ctx_peek(lydctx->xmlctx, &status) && (status == LYXML_ELEMENT)) {
+            *subtree_sibling = 1;
+        } else {
+            *subtree_sibling = 0;
+        }
+    }
+
 cleanup:
     /* there should be no unres stored if validation should be skipped */
     assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
-            !lydctx->node_when.count && !lydctx->node_exts.count));
+            !lydctx->node_when.count));
 
     if (rc) {
         lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
diff --git a/src/path.c b/src/path.c
index e631e3a..932a039 100644
--- a/src/path.c
+++ b/src/path.c
@@ -446,6 +446,7 @@
             break;
         case LY_VALUE_CANON:
         case LY_VALUE_XML:
+        case LY_VALUE_STR_NS:
             /* not really defined or accepted */
             LOGINT_RET(ctx);
         }
diff --git a/src/plugins_exts.c b/src/plugins_exts.c
index df797f9..eb688d5 100644
--- a/src/plugins_exts.c
+++ b/src/plugins_exts.c
@@ -1,9 +1,10 @@
 /**
  * @file plugins_exts.c
  * @author Radek Krejci <rkrejci@cesnet.cz>
- * @brief Internally implemented YANG extensions.
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief helper functions for extension plugins
  *
- * Copyright (c) 2019 CESNET, z.s.p.o.
+ * Copyright (c) 2019 - 2022 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -69,3 +70,14 @@
 {
     return ctx->pmod;
 }
+
+LIBYANG_API_DEF LY_ERR
+lyplg_ext_get_data(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, void **ext_data, ly_bool *ext_data_free)
+{
+    if (!ctx->ext_clb) {
+        lyplg_ext_log(ext, LY_LLERR, LY_EINVAL, NULL, "Failed to get extension data, no callback set.");
+        return LY_EINVAL;
+    }
+
+    return ctx->ext_clb(ext, ctx->ext_clb_data, ext_data, ext_data_free);
+}
diff --git a/src/plugins_exts.h b/src/plugins_exts.h
index d856420..2dba714 100644
--- a/src/plugins_exts.h
+++ b/src/plugins_exts.h
@@ -100,7 +100,7 @@
 /**
  * @brief Extensions API version
  */
-#define LYPLG_EXT_API_VERSION 1
+#define LYPLG_EXT_API_VERSION 2
 
 /**
  * @brief Macro to define plugin information in external plugins
@@ -130,16 +130,28 @@
  *
  * @param[in] cctx Current compile context.
  * @param[in] p_ext Parsed extension instance data.
- * @param[in,out] c_ext Prepared compiled extension instance structure where an addition, extension-specific, data are supposed to be placed
- * for later use (data validation or use of external tool).
+ * @param[in,out] c_ext Prepared compiled extension instance structure where an addition, extension-specific, data are
+ * supposed to be placed for later use (data validation or use of external tool).
  * @return LY_SUCCESS in case of success.
  * @return LY_EVALID in case of non-conforming parsed data.
  * @return LY_ENOT in case the extension instance is not supported and should be removed.
  */
-typedef LY_ERR (*lyplg_ext_compile_clb)(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext, struct lysc_ext_instance *c_ext);
+typedef LY_ERR (*lyplg_ext_compile_clb)(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext,
+        struct lysc_ext_instance *c_ext);
 
 /**
- * @brief Callback to free the extension specific data created by the ::lyplg_ext_compile_clb callback of the same extension plugin.
+ * @brief Callback to print the compiled extension instance's private data in the INFO format.
+ *
+ * @param[in] ctx YANG printer context to provide output handler and other information for printing.
+ * @param[in] ext The compiled extension instance, mainly to access the extensions.
+ * @param[in,out] flag Flag to be shared with the caller regarding the opening brackets - 0 if the '{' not yet printed,
+ * 1 otherwise.
+ * @return LY_SUCCESS when everything was fine, other LY_ERR values in case of failure
+ */
+typedef LY_ERR (*lyplg_ext_schema_printer_clb)(struct lyspr_ctx *ctx, struct lysc_ext_instance *ext, ly_bool *flag);
+
+/**
+ * @brief Callback to free the extension-specific data created by its compilation.
  *
  * @param[in] ctx libyang context.
  * @param[in,out] ext Compiled extension structure where the data to free are placed.
@@ -147,57 +159,50 @@
 typedef void (*lyplg_ext_free_clb)(struct ly_ctx *ctx, struct lysc_ext_instance *ext);
 
 /**
- * @brief Callback to decide if data instance is valid according to the schema.
+ * @brief Callback for parsing YANG instance data described by an extension instance.
  *
- * The callback is used only for the extension instances placed in the data nodes or type (the
- * ::lysc_ext_instance.parent_stmt value must be ::LY_STMT_IS_DATA_NODE() values or ::LY_STMT_TYPE):
+ * This callback is used only for nested data definition (with a standard YANG schema parent).
+ * Note that the siblings parsed by this function and directly connected to @p parent must have the flag ::LYD_EXT set.
  *
- * @param[in] ext Extension instance to be checked.
- * @param[in] node Data node connected with the extension instance.
- *
- * @return LY_SUCCESS on data validation success.
- * @return LY_EVALID in case the validation fails.
+ * @param[in] in Input handler with the data to parse.
+ * @param[in] format Format if the data in @p in.
+ * @param[in] ext Compiled extension instance.
+ * @param[in,out] parent Data parent to append to.
+ * @param[in] parse_opts Parse options, see @ref dataparseroptions. They will always include ::LYD_PARSE_ONLY.
+ * @return LY_SUCCESS on success.
+ * @return LY_ENOT if the data are not described by @p ext.
+ * @return LY_ERR on error.
  */
-typedef LY_ERR (*lyplg_ext_data_validation_clb)(struct lysc_ext_instance *ext, struct lyd_node *node);
+typedef LY_ERR (*lyplg_ext_data_parse_clb)(struct ly_in *in, LYD_FORMAT format, struct lysc_ext_instance *ext,
+        struct lyd_node *parent, uint32_t parse_opts);
 
 /**
- * @brief Callback to print the compiled extension instance's private data in the INFO format.
+ * @brief Callback for validating parsed YANG instance data described by an extension instance.
  *
- * @param[in] ctx YANG printer context to provide output handler and other information for printing.
- * @param[in] ext The compiled extension instance, mainly to access the extensions.
- * @param[in, out] flag Flag to be shared with the caller regarding the opening brackets - 0 if the '{' not yet printed,
- * 1 otherwise.
+ * This callback is used only for nested data definition (with a standard YANG schema parent).
  *
- * @return LY_SUCCESS when everything was fine, other LY_ERR values in case of failure
+ * @param[in] ext Compiled extension instance.
+ * @param[in] sibling First sibling parsed by ::lyplg_ext_data_parse_clb.
+ * @param[in] val_opts Validation options, see @ref datavalidationoptions.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR on error.
  */
-typedef LY_ERR (*lyplg_ext_schema_printer_clb)(struct lyspr_ctx *ctx, struct lysc_ext_instance *ext, ly_bool *flag);
-
-/**
- * @brief Callback to data according to extension specification.
- *
- * @param[in] in
- * @param[in] format
- * @param[in] ext
- * @param[in] parent
- * @param[in] parse_opts
- * @param[in] val_opts
- * @param[out] ly_err
- */
-typedef LY_ERR (*lyplg_ext_data_parse_clb)(struct ly_in *in, LYD_FORMAT format,
-        struct lysc_ext_instance *ext, struct lyd_node *parent,
-        uint32_t parse_opts, uint32_t val_opts);
+typedef LY_ERR (*lyplg_ext_data_validate_clb)(struct lysc_ext_instance *ext, struct lyd_node *sibling, uint32_t val_opts);
 
 /**
  * @brief Extension plugin implementing various aspects of a YANG extension
  */
 struct lyplg_ext {
-    const char *id;                         /**< Plugin identification (mainly for distinguish incompatible versions of the plugins for external tools) */
-    lyplg_ext_compile_clb compile;          /**< Callback to compile extension instance from the parsed data */
-    lyplg_ext_schema_printer_clb sprinter;  /**< Callback to print the compiled content (info format) of the extension instance */
-    lyplg_ext_free_clb free;                /**< Free the extension instance specific data created by ::lyplg_ext.compile callback */
+    const char *id;                         /**< plugin identification (mainly for distinguish incompatible versions
+                                                 of the plugins for external tools) */
+    lyplg_ext_compile_clb compile;          /**< callback to compile extension instance from the parsed data */
+    lyplg_ext_schema_printer_clb sprinter;  /**< callback to print the compiled content (info format) of the extension
+                                                 instance */
+    lyplg_ext_free_clb free;                /**< free the extension-specific data created by its compilation */
 
-    lyplg_ext_data_parse_clb parse;         /**< Callback to parse data instance according to the extension definition. */
-    lyplg_ext_data_validation_clb validate; /**< Callback to decide if data instance is valid according to the schema. */
+    lyplg_ext_data_parse_clb parse;         /**< callback to parse data instance according to the extension definition */
+    lyplg_ext_data_validate_clb validate;   /**< callback to validate parsed data instances according to the extension
+                                                 definition */
 };
 
 struct lyplg_ext_record {
@@ -214,6 +219,19 @@
     struct lyplg_ext plugin;     /**< data to utilize plugin implementation */
 };
 
+LIBYANG_API_DECL LY_ERR lyplg_ext_get_data(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, void **ext_data,
+        ly_bool *ext_data_free);
+
+/**
+ * @brief Insert extension instance data into a parent.
+ *
+ * @param[in] parent Parent node to insert into.
+ * @param[in] first First top-level sibling node to insert.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR error on error.
+ */
+LIBYANG_API_DECL LY_ERR lyd_insert_ext(struct lyd_node *parent, struct lyd_node *first);
+
 /**
  * @brief Provide a log message from an extension plugin.
  *
diff --git a/src/plugins_exts/metadata.c b/src/plugins_exts/metadata.c
index 2313090..bc70694 100644
--- a/src/plugins_exts/metadata.c
+++ b/src/plugins_exts/metadata.c
@@ -161,10 +161,10 @@
 
         .plugin.id = "libyang 2 - metadata, version 1",
         .plugin.compile = &annotation_compile,
-        .plugin.parse = NULL,
-        .plugin.validate = NULL,
         .plugin.sprinter = &annotation_schema_printer,
-        .plugin.free = annotation_free
+        .plugin.free = annotation_free,
+        .plugin.parse = NULL,
+        .plugin.validate = NULL
     },
     {0}     /* terminating zeroed record */
 };
diff --git a/src/plugins_exts/nacm.c b/src/plugins_exts/nacm.c
index a222dfe..d8e1ca8 100644
--- a/src/plugins_exts/nacm.c
+++ b/src/plugins_exts/nacm.c
@@ -158,10 +158,10 @@
 
         .plugin.id = "libyang 2 - NACM, version 1",
         .plugin.compile = &nacm_compile,
-        .plugin.parse = NULL,
-        .plugin.validate = NULL,
         .plugin.sprinter = NULL,
-        .plugin.free = NULL
+        .plugin.free = NULL,
+        .plugin.parse = NULL,
+        .plugin.validate = NULL
     }, {
         .module = "ietf-netconf-acm",
         .revision = "2018-02-14",
@@ -169,10 +169,10 @@
 
         .plugin.id = "libyang 2 - NACM, version 1",
         .plugin.compile = &nacm_compile,
-        .plugin.parse = NULL,
-        .plugin.validate = NULL,
         .plugin.sprinter = NULL,
-        .plugin.free = NULL
+        .plugin.free = NULL,
+        .plugin.parse = NULL,
+        .plugin.validate = NULL
     }, {
         .module = "ietf-netconf-acm",
         .revision = "2012-02-22",
@@ -180,10 +180,10 @@
 
         .plugin.id = "libyang 2 - NACM, version 1",
         .plugin.compile = &nacm_compile,
-        .plugin.parse = NULL,
-        .plugin.validate = NULL,
         .plugin.sprinter = NULL,
-        .plugin.free = NULL
+        .plugin.free = NULL,
+        .plugin.parse = NULL,
+        .plugin.validate = NULL
     }, {
         .module = "ietf-netconf-acm",
         .revision = "2018-02-14",
@@ -191,10 +191,10 @@
 
         .plugin.id = "libyang 2 - NACM, version 1",
         .plugin.compile = &nacm_compile,
-        .plugin.parse = NULL,
-        .plugin.validate = NULL,
         .plugin.sprinter = NULL,
-        .plugin.free = NULL
+        .plugin.free = NULL,
+        .plugin.parse = NULL,
+        .plugin.validate = NULL
     },
     {0} /* terminating zeroed item */
 };
diff --git a/src/plugins_exts/schema_mount.c b/src/plugins_exts/schema_mount.c
index 4b1c1cf..d367fe7 100644
--- a/src/plugins_exts/schema_mount.c
+++ b/src/plugins_exts/schema_mount.c
@@ -15,6 +15,7 @@
 #define _GNU_SOURCE
 
 #include <assert.h>
+#include <pthread.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
@@ -27,164 +28,772 @@
 #include "tree_schema.h"
 
 /**
+ * @brief Internal schema mount data structure for holding all the contexts of parsed data.
+ */
+struct lyplg_ext_sm {
+    struct lyplg_ext_sm_shared {
+        pthread_mutex_t lock;           /**< lock for accessing this shared structure */
+
+        struct {
+            struct ly_ctx *ctx;         /**< context shared between all data of this mount point */
+            const char *mount_point;    /**< mount point name */
+            const char *content_id;     /**< yang-library content-id (alternatively module-set-id),
+                                             stored in the dictionary of the ext instance context */
+        } *schemas;                     /**< array of shared schema schemas */
+        uint32_t schema_count;          /**< length of schemas array */
+        uint32_t ref_count;             /**< number of references to this structure (mount-points with the same name
+                                             in the module) */
+    } *shared;                          /**< shared schema mount points */
+
+    struct lyplg_ext_sm_inln {
+        struct {
+            struct ly_ctx *ctx;         /**< context created for single inline schema data */
+        } *schemas;                     /**< array of inline schemas */
+        uint32_t schema_count;          /**< length of schemas array */
+    } inln;                             /**< inline mount points */
+};
+
+#define EXT_LOGERR_MEM_RET(ext) \
+        lyplg_ext_log(ext, LY_LLERR, LY_EMEM, NULL, "Memory allocation failed (%s:%d).", __FILE__, __LINE__); \
+        return LY_EMEM
+
+#define EXT_LOGERR_MEM_GOTO(ext, rc, label) \
+        lyplg_ext_log(ext, LY_LLERR, LY_EMEM, NULL, "Memory allocation failed (%s:%d).", __FILE__, __LINE__); \
+        rc = LY_EMEM; \
+        goto label
+
+#define EXT_LOGERR_INT_RET(ext) \
+        lyplg_ext_log(ext, LY_LLERR, LY_EINT, NULL, "Internal error (%s:%d).", __FILE__, __LINE__); \
+        return LY_EINT
+
+/**
  * @brief Check if given mount point is unique among its' siblings
  *
  * @param cctx Compilation context.
  * @param c_ext Compiled extension instance for checking uniqueness.
  * @param p_ext Extension instance of the mount-point for comparison.
- *
- * @return LY_SUCCESS if is unique. LY_EINVAL otherwise.
+ * @return LY_SUCCESS if is unique;
+ * @return LY_EINVAL otherwise.
  */
 static LY_ERR
-schema_mount_unique_mount_point(struct lysc_ctx *cctx, const struct lysc_ext_instance *c_ext,
+schema_mount_compile_unique_mp(struct lysc_ctx *cctx, const struct lysc_ext_instance *c_ext,
         const struct lysp_ext_instance *p_ext)
 {
-    struct lysp_module *pmod;
-    struct lysp_ext_instance *exts;
-    LY_ARRAY_COUNT_TYPE u, v;
-    struct lysp_node *parent;
-    struct lysp_import *module;
-    char *ext_prefix, *ext_name;
+    struct lysc_ext_instance *exts;
+    LY_ARRAY_COUNT_TYPE u;
+    struct lysc_node *parent;
 
-    /* Check if it is the only instance of the mount-point among its' siblings */
-    parent = (struct lysp_node *) c_ext->parent;
+    /* check if it is the only instance of the mount-point among its' siblings */
+    parent = (struct lysc_node *)c_ext->parent;
     exts = parent->exts;
-    pmod = lysc_ctx_get_pmod(cctx);
     LY_ARRAY_FOR(exts, u) {
-        /* Extract prefix and name of the extension */
-        ext_prefix = strdup(exts[u].name);
-        ext_name = strstr(exts[u].name, ":");
-        ext_name++;
-        ext_prefix[strstr(ext_prefix, ":") - ext_prefix] = '\0';
-
-        module = NULL;
-        LY_ARRAY_FOR(pmod->imports, v) {
-            if (!strcmp(pmod->imports[v].prefix, ext_prefix)) {
-                /* Found the matching module */
-                module = &pmod->imports[v];
-                break;
-            }
+        if (&exts[u] == c_ext) {
+            continue;
         }
-        free(ext_prefix);
-        if ((&exts[u] != p_ext) && module && (!strcmp(module->name, "ietf-yang-schema-mount")) &&
-                (!strcmp(exts[u].name, "mount-point"))) {
-            /* Found another instance of mount-point only one allowed per node */
+
+        if (!strcmp(exts[u].def->module->name, "ietf-yang-schema-mount") && !strcmp(exts[u].def->name, "mount-point")) {
+            lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx), "Multiple extension \"%s\" instances.",
+                    p_ext->name);
             return LY_EINVAL;
         }
     }
     return LY_SUCCESS;
 }
 
+struct lyplg_ext_sm_shared_cb_data {
+    const struct lysc_ext_instance *ext;
+    struct lyplg_ext_sm_shared *sm_shared;
+};
+
+static LY_ERR
+schema_mount_compile_mod_dfs_cb(struct lysc_node *node, void *data, ly_bool *dfs_continue)
+{
+    struct lyplg_ext_sm_shared_cb_data *cb_data = data;
+    struct lyplg_ext_sm *sm_data;
+    struct lysc_ext_instance *exts;
+    LY_ARRAY_COUNT_TYPE u;
+
+    (void)dfs_continue;
+
+    if (node == cb_data->ext->parent) {
+        /* parent of the current compiled extension, skip */
+        return LY_SUCCESS;
+    }
+
+    /* find the same mount point */
+    exts = node->exts;
+    LY_ARRAY_FOR(exts, u) {
+        if (!strcmp(exts[u].def->module->name, "ietf-yang-schema-mount") && !strcmp(exts[u].def->name, "mount-point") &&
+                (exts[u].argument == cb_data->ext->argument)) {
+            /* same mount point, break the DFS search */
+            sm_data = exts[u].data;
+            cb_data->sm_shared = sm_data->shared;
+            return LY_EEXIST;
+        }
+    }
+
+    /* not found, continue search */
+    return LY_SUCCESS;
+}
+
+static struct lyplg_ext_sm_shared *
+schema_mount_compile_find_shared(const struct lys_module *mod, const struct lysc_ext_instance *ext)
+{
+    struct lyplg_ext_sm_shared_cb_data cb_data;
+    LY_ERR r;
+
+    /* prepare cb_data */
+    cb_data.ext = ext;
+    cb_data.sm_shared = NULL;
+
+    /* try to find the same mount point */
+    r = lysc_module_dfs_full(mod, schema_mount_compile_mod_dfs_cb, &cb_data);
+    assert((!r && !cb_data.sm_shared) || ((r == LY_EEXIST) && cb_data.sm_shared));
+
+    return cb_data.sm_shared;
+}
+
 /**
  * @brief Schema mount compile.
- *
  * Checks if it can be a valid extension instance for yang schema mount.
  *
  * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile.
  */
 static LY_ERR
-schema_mount_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext,
-        struct lysc_ext_instance *c_ext)
+schema_mount_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext, struct lysc_ext_instance *c_ext)
 {
     const struct lys_module *cur_mod;
+    struct lyplg_ext_sm *sm_data;
 
-    /* Check if processing right callback */
     assert(!strcmp(p_ext->name, "yangmnt:mount-point"));
 
-    /* Check if mount point was found in YANG version 1.1 module */
+    /* check YANG version 1.1 */
     cur_mod = lysc_ctx_get_cur_mod(cctx);
     if (cur_mod->parsed->version != LYS_VERSION_1_1) {
+        lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
+                "Extension \"%s\" instance not allowed in YANG version 1 module.", p_ext->name);
         return LY_EINVAL;
     }
 
-    /* Check if its' parent is a container or a list */
+    /* check parent nodetype */
     if ((p_ext->parent_stmt != LY_STMT_CONTAINER) && (p_ext->parent_stmt != LY_STMT_LIST)) {
+        lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
+                "Extension \"%s\" instance allowed only in container or list statement.", p_ext->name);
         return LY_EINVAL;
     }
 
-    /* Check if the only mount-point among siblings */
-    if (schema_mount_unique_mount_point(cctx, c_ext, p_ext)) {
+    /* check uniqueness */
+    if (schema_mount_compile_unique_mp(cctx, c_ext, p_ext)) {
         return LY_EINVAL;
     }
 
-    (void)c_ext;
+    /* init internal data */
+    sm_data = calloc(1, sizeof *sm_data);
+    if (!sm_data) {
+        EXT_LOGERR_MEM_RET(c_ext);
+    }
+    c_ext->data = sm_data;
+
+    /* reuse/init shared schema */
+    sm_data->shared = schema_mount_compile_find_shared(c_ext->module, c_ext);
+    if (sm_data->shared) {
+        ++sm_data->shared->ref_count;
+    } else {
+        sm_data->shared = calloc(1, sizeof *sm_data->shared);
+        if (!sm_data->shared) {
+            free(sm_data);
+            EXT_LOGERR_MEM_RET(c_ext);
+        }
+        pthread_mutex_init(&sm_data->shared->lock, NULL);
+        sm_data->shared->ref_count = 1;
+    }
 
     return LY_SUCCESS;
 }
 
 /**
- * @brief Parse callback for schema mount.
+ * @brief Learn details about the current mount point.
  *
- * Check if data is valid for schema mount and inserts it to the parent.
+ * @param[in] ext Compiled extension instance.
+ * @param[in] ext_data Extension data retrieved by the callback.
+ * @param[out] config Whether the whole schema should keep its config or be set to false.
+ * @param[out] shared Whether the schema is shared or inline.
+ * @return LY_ERR value.
  */
 static LY_ERR
-schema_mount_parse(struct ly_in *in, LYD_FORMAT format, struct lysc_ext_instance *ext,
-        struct lyd_node *parent, uint32_t parse_opts, uint32_t val_opts)
+schema_mount_get_smount(const struct lysc_ext_instance *ext, const struct lyd_node *ext_data, ly_bool *config,
+        ly_bool *shared)
 {
-    LY_ERR ret = LY_SUCCESS;
-    const struct ly_ctx *ctx;
-    struct lyd_node *subtree, *yanglib, *mount_point, *final = NULL;
-    struct ly_err_item *err;
-    ly_bool found_yanglib = 0, found_mount_point = 0;
-    uint32_t old_log_opts;
+    struct lyd_node *mpoint, *node;
+    char *path = NULL;
+    LY_ERR r;
 
-    ctx = LYD_CTX(parent);
+    /* find the mount point */
+    if (asprintf(&path, "/ietf-yang-schema-mount:schema-mounts/mount-point[module='%s'][label='%s']", ext->module->name,
+            ext->argument) == -1) {
+        EXT_LOGERR_MEM_RET(ext);
+    }
+    r = ext_data ? lyd_find_path(ext_data, path, 0, &mpoint) : LY_ENOTFOUND;
+    free(path);
+    if (r) {
+        /* missing mount-point, cannot be data for this extension (https://datatracker.ietf.org/doc/html/rfc8528#page-10) */
+        return LY_ENOT;
+    }
 
-    old_log_opts = ly_log_options(LY_LOSTORE_LAST);
-    /* Check if intended for schema-mount - had both required data nodes */
-    while (1) {
-        /* Parse by sub-trees */
-        if (lyd_parse_data(ctx, NULL, in, 0, parse_opts, val_opts, &subtree)) {
-            /* Either end or error - must check */
-            err = ly_err_first(ctx);
-            if (err->vecode == LYVE_SYNTAX_XML) {
-                /* Could just be EOF - check */
-                /* TODO: Search in error message  if EOF then break */
-                lyd_insert_sibling(final, subtree, NULL);
-                break;
-            } else {
-                /* Other parsing error encountered */
-                ret = LY_EINVAL;
-                goto cleanup;
+    /* check config */
+    if (!lyd_find_path(mpoint, "config", 0, &node) && !strcmp(lyd_get_value(node), "false")) {
+        *config = 0;
+    } else {
+        *config = 1;
+    }
+
+    /* check schema-ref */
+    if (lyd_find_path(mpoint, "shared-schema", 0, NULL)) {
+        if (lyd_find_path(mpoint, "inline", 0, NULL)) {
+            EXT_LOGERR_INT_RET(ext);
+        }
+        *shared = 0;
+    } else {
+        *shared = 1;
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Create schema (context) based on retrieved extension data.
+ *
+ * @param[in] ext Compiled extension instance.
+ * @param[in] ext_data Extension data retrieved by the callback.
+ * @param[in] config Whether the whole schema should keep its config or be set to false.
+ * @param[out] ext_ctx Schema to use for parsing the data.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+schema_mount_create_ctx(const struct lysc_ext_instance *ext, const struct lyd_node *ext_data, ly_bool config,
+        struct ly_ctx **ext_ctx)
+{
+    LY_ERR r;
+    const char * const *searchdirs;
+    const struct lys_module *mod;
+    struct lysc_node *root, *node;
+    uint32_t idx = 0;
+
+    /* get searchdirs from the current context */
+    searchdirs = ly_ctx_get_searchdirs(ext->module->ctx);
+
+    /* create the context based on the data */
+    if ((r = ly_ctx_new_yldata(searchdirs ? searchdirs[0] : NULL, ext_data, ly_ctx_get_options(ext->module->ctx), ext_ctx))) {
+        lyplg_ext_log(ext, LY_LLERR, r, NULL, "Failed to create context for the schema-mount data.");
+        return r;
+    }
+
+    if (!config) {
+        /* manually change the config of all schema nodes in all the modules */
+        while ((mod = ly_ctx_get_module_iter(*ext_ctx, &idx))) {
+            if (!mod->implemented) {
+                continue;
             }
-        }
 
-        if (!final) {
-            /* If there was nothing inserted yet this subtree becomes the one to insert into */
-            final = subtree;
-        }
+            LY_LIST_FOR(mod->compiled->data, root) {
+                LYSC_TREE_DFS_BEGIN(root, node) {
+                    node->flags &= ~LYS_CONFIG_W;
+                    node->flags |= LYS_CONFIG_R;
 
-        lyd_find_path(subtree, "/ietf-yang-library:yang-library", 0, &yanglib);
-        if (yanglib && !(yanglib->flags & LYD_DEFAULT)) {
-            /* Found and not created by flags */
-            found_yanglib = 1;
-            lyd_insert_sibling(final, yanglib, NULL);
-            continue;
-        }
-        lyd_find_path(subtree, "/ietf-yang-schema-mount:mount-points", 0, &mount_point);
-        if (mount_point && !(mount_point->flags & LYD_DEFAULT)) {
-            /* Was found and not created by flags */
-            found_mount_point = 1;
-            lyd_insert_sibling(final, mount_point, NULL);
-            continue;
+                    LYSC_TREE_DFS_END(root, node);
+                }
+            }
         }
     }
 
-    if (found_mount_point && found_yanglib) {
-        /* It is valid data and can be inserted into the parent */
-        lyd_insert_child(parent, final);
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Get schema (context) for a shared-schema mount point.
+ *
+ * @param[in] ext Compiled extension instance.
+ * @param[in] ext_data Extension data retrieved by the callback.
+ * @param[in] config Whether the whole schema should keep its config or be set to false.
+ * @param[out] ext_ctx Schema to use for parsing the data.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+schema_mount_get_ctx_shared(struct lysc_ext_instance *ext, const struct lyd_node *ext_data, ly_bool config,
+        const struct ly_ctx **ext_ctx)
+{
+    struct lyplg_ext_sm *sm_data = ext->data;
+    LY_ERR ret = LY_SUCCESS, r;
+    struct lyd_node *node = NULL;
+    struct ly_ctx *new_ctx;
+    uint32_t i;
+    const char *content_id = NULL;
+    void *mem;
+
+    assert(sm_data && sm_data->shared);
+
+    /* get yang-library content-id or module-set-id */
+    if (ext_data) {
+        lyd_find_path(ext_data, "/ietf-yang-library:yang-library/content-id", 0, &node);
+        if (!node) {
+            lyd_find_path(ext_data, "/ietf-yang-library:modules-state/module-set-id", 0, &node);
+        }
+        if (node) {
+            content_id = lyd_get_value(node);
+        }
+    }
+    if (!content_id) {
+        lyplg_ext_log(ext, LY_LLERR, LY_EVALID, NULL, "Missing \"content-id\" or \"module-set-id\" in ietf-yang-library data.");
+        return LY_EVALID;
+    }
+
+    /* LOCK */
+    if ((r = pthread_mutex_lock(&sm_data->shared->lock))) {
+        lyplg_ext_log(ext, LY_LLERR, LY_ESYS, NULL, "Mutex lock failed (%s).", strerror(r));
+        return LY_ESYS;
+    }
+
+    /* try to find this mount point */
+    for (i = 0; i < sm_data->shared->schema_count; ++i) {
+        if (ext->argument == sm_data->shared->schemas[i].mount_point) {
+            break;
+        }
+    }
+
+    if (i < sm_data->shared->schema_count) {
+        /* schema exists already */
+        if (strcmp(content_id, sm_data->shared->schemas[i].content_id)) {
+            lyplg_ext_log(ext, LY_LLERR, LY_EVALID, "/ietf-yang-library:yang-library/content-id",
+                    "Shared-schema yang-library content-id \"%s\" differs from \"%s\" used previously.",
+                    content_id, sm_data->shared->schemas[i].content_id);
+            ret = LY_EVALID;
+            goto cleanup;
+        }
     } else {
-        /* It was not data for schema mount */
-        lyd_free_tree(final);
-        ret = LY_ENOT;
+        /* no schema found, create it */
+        if ((r = schema_mount_create_ctx(ext, ext_data, config, &new_ctx))) {
+            ret = r;
+            goto cleanup;
+        }
+
+        /* new entry */
+        mem = realloc(sm_data->shared->schemas, (i + 1) * sizeof *sm_data->shared->schemas);
+        if (!mem) {
+            ly_ctx_destroy(new_ctx);
+            EXT_LOGERR_MEM_GOTO(ext, ret, cleanup);
+        }
+        sm_data->shared->schemas = mem;
+        ++sm_data->shared->schema_count;
+
+        /* fill entry */
+        sm_data->shared->schemas[i].ctx = new_ctx;
+        sm_data->shared->schemas[i].mount_point = ext->argument;
+        lydict_insert(ext->module->ctx, content_id, 0, &sm_data->shared->schemas[i].content_id);
+    }
+
+    /* use the context */
+    *ext_ctx = sm_data->shared->schemas[i].ctx;
+
+cleanup:
+    /* UNLOCK */
+    pthread_mutex_unlock(&sm_data->shared->lock);
+
+    return ret;
+}
+
+/**
+ * @brief Get schema (context) for an inline mount point.
+ *
+ * @param[in] ext Compiled extension instance.
+ * @param[in] ext_data Extension data retrieved by the callback.
+ * @param[in] config Whether the whole schema should keep its config or be set to false.
+ * @param[out] ext_ctx Schema to use for parsing the data.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+schema_mount_get_ctx_inline(struct lysc_ext_instance *ext, const struct lyd_node *ext_data, ly_bool config,
+        const struct ly_ctx **ext_ctx)
+{
+    struct lyplg_ext_sm *sm_data = ext->data;
+    LY_ERR r;
+    struct ly_ctx *new_ctx;
+    uint32_t i;
+    void *mem;
+
+    assert(sm_data && sm_data->shared);
+
+    i = sm_data->inln.schema_count;
+
+    /* always new schema required, create context */
+    if ((r = schema_mount_create_ctx(ext, ext_data, config, &new_ctx))) {
+        return r;
+    }
+
+    /* new entry */
+    mem = realloc(sm_data->inln.schemas, (i + 1) * sizeof *sm_data->inln.schemas);
+    if (!mem) {
+        ly_ctx_destroy(new_ctx);
+        EXT_LOGERR_MEM_RET(ext);
+    }
+    sm_data->inln.schemas = mem;
+    ++sm_data->inln.schema_count;
+
+    /* fill entry */
+    sm_data->inln.schemas[i].ctx = new_ctx;
+
+    /* use the context */
+    *ext_ctx = sm_data->inln.schemas[i].ctx;
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Get schema (context) for a mount point.
+ *
+ * @param[in] ext Compiled extension instance.
+ * @param[out] ext_ctx Schema to use for parsing the data.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+schema_mount_get_ctx(struct lysc_ext_instance *ext, const struct ly_ctx **ext_ctx)
+{
+    LY_ERR ret = LY_SUCCESS, r;
+    struct lyd_node *iter, *ext_data = NULL;
+    ly_bool ext_data_free = 0, config, shared;
+
+    *ext_ctx = NULL;
+
+    /* get operational data with ietf-yang-library and ietf-yang-schema-mount data */
+    if ((r = lyplg_ext_get_data(ext->module->ctx, ext, (void **)&ext_data, &ext_data_free))) {
+        ret = r;
+        goto cleanup;
+    }
+
+    LY_LIST_FOR(ext_data, iter) {
+        if (iter->flags & LYD_NEW) {
+            /* must be validated for the parent-reference prefix data to be stored */
+            lyplg_ext_log(ext, LY_LLERR, LY_EINVAL, NULL, "Provided ext data have not been validated.");
+            ret = LY_EINVAL;
+            goto cleanup;
+        }
+    }
+
+    /* learn about this mount point */
+    if ((r = schema_mount_get_smount(ext, ext_data, &config, &shared))) {
+        ret = r;
+        goto cleanup;
+    }
+
+    /* create/get the context for parsing the data */
+    if (shared) {
+        r = schema_mount_get_ctx_shared(ext, ext_data, config, ext_ctx);
+    } else {
+        r = schema_mount_get_ctx_inline(ext, ext_data, config, ext_ctx);
+    }
+    if (r) {
+        ret = r;
+        goto cleanup;
+    }
+
+cleanup:
+    if (ext_data_free) {
+        lyd_free_all(ext_data);
+    }
+    return ret;
+}
+
+/**
+ * @brief Parse callback for schema mount.
+ * Check if data if valid for schema mount and inserts it to the parent.
+ */
+static LY_ERR
+schema_mount_parse(struct ly_in *in, LYD_FORMAT format, struct lysc_ext_instance *ext, struct lyd_node *parent,
+        uint32_t parse_opts)
+{
+    LY_ERR ret = LY_SUCCESS, r;
+    const struct ly_ctx *ext_ctx;
+    struct lyd_node *subtree, *first = NULL;
+    struct ly_err_item *err;
+    uint32_t old_log_opts;
+
+    /* get context based on ietf-yang-library data */
+    if ((r = schema_mount_get_ctx(ext, &ext_ctx))) {
+        return r;
+    }
+
+    /* prepare opts */
+    old_log_opts = ly_log_options(LY_LOSTORE_LAST);
+    assert(parse_opts & LYD_PARSE_ONLY);
+    parse_opts |= LYD_PARSE_SUBTREE;
+
+    do {
+        /* parse by nested subtrees */
+        r = lyd_parse_data(ext_ctx, NULL, in, format, parse_opts, 0, &subtree);
+        if (r && (r != LY_ENOT)) {
+            /* error, maybe valid, maybe not, print as verbose */
+            err = ly_err_first(ext_ctx);
+            if (!err) {
+                lyplg_ext_log(ext, LY_LLVRB, 0, NULL, "Unknown parsing error (err code %d).", r);
+            } else {
+                lyplg_ext_log(ext, LY_LLVRB, 0, NULL, "%s (err code %d).", err->msg, err->no);
+            }
+            ret = LY_ENOT;
+            goto cleanup;
+        }
+
+        /* set the special flag and insert into siblings */
+        subtree->flags |= LYD_EXT;
+        lyd_insert_sibling(first, subtree, &first);
+    } while (r == LY_ENOT);
+
+    /* append to parent */
+    if (first && (r = lyd_insert_ext(parent, first))) {
+        lyplg_ext_log(ext, LY_LLERR, r, NULL, "Failed to append parsed data.");
+        ret = r;
+        goto cleanup;
     }
 
 cleanup:
     ly_log_options(old_log_opts);
+    if (ret) {
+        lyd_free_siblings(first);
+    }
     return ret;
 }
 
 /**
+ * @brief Duplicate all accessible parent references for a shared-schema mount point.
+ *
+ * @param[in] ext Compiled extension instance.
+ * @param[in] ctx_node Context node for evaluating the parent-reference XPath expressions.
+ * @param[in] ext_data Extension data retrieved by the callback.
+ * @param[in] trg_ctx Mounted data context to use for duplication.
+ * @param[out] ref_set Set of all top-level parent-ref subtrees connected to each other, may be empty.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+schema_mount_dup_parent_ref(const struct lysc_ext_instance *ext, const struct lyd_node *ctx_node,
+        const struct lyd_node *ext_data, const struct ly_ctx *trg_ctx, struct ly_set **ref_set)
+{
+    LY_ERR ret = LY_SUCCESS;
+    char *path = NULL;
+    struct ly_set *set = NULL, *par_set = NULL;
+    struct lyd_node_term *term;
+    struct lyd_node *dup = NULL, *top_node, *first;
+    struct lyd_value_xpath10 *xp_val;
+    uint32_t i, j;
+
+    *ref_set = NULL;
+
+    if (!ext_data) {
+        /* we expect the same ext data as before and there must be some for data to be parsed */
+        lyplg_ext_log(ext, LY_LLERR, LY_EINVAL, NULL, "No ext data provided.");
+        ret = LY_EINVAL;
+        goto cleanup;
+    }
+
+    /* get all parent references of this mount point */
+    if (asprintf(&path, "/ietf-yang-schema-mount:schema-mounts/mount-point[module='%s'][label='%s']"
+            "/shared-schema/parent-reference", ext->module->name, ext->argument) == -1) {
+        EXT_LOGERR_MEM_GOTO(ext, ret, cleanup);
+    }
+    if ((ret = lyd_find_xpath(ext_data, path, &set))) {
+        goto cleanup;
+    }
+
+    /* prepare result set */
+    if ((ret = ly_set_new(ref_set))) {
+        goto cleanup;
+    }
+
+    first = NULL;
+    for (i = 0; i < set->count; ++i) {
+        term = set->objs[i];
+
+        /* get the referenced nodes (subtrees) */
+        LYD_VALUE_GET(&term->value, xp_val);
+        if ((ret = lyd_find_xpath4(ctx_node, ctx_node, lyxp_get_expr(xp_val->exp), xp_val->format, xp_val->prefix_data,
+                NULL, &par_set))) {
+            goto cleanup;
+        }
+
+        for (j = 0; j < par_set->count; ++j) {
+            /* duplicate with parents in the context of the mounted data */
+            if ((ret = lyd_dup_single_to_ctx(par_set->dnodes[j], trg_ctx, NULL,
+                    LYD_DUP_RECURSIVE | LYD_DUP_WITH_PARENTS | LYD_DUP_WITH_FLAGS, &dup))) {
+                goto cleanup;
+            }
+
+            /* go top-level */
+            while (dup->parent) {
+                dup = lyd_parent(dup);
+            }
+
+            /* check whether the top-level node exists */
+            if (first) {
+                if ((ret = lyd_find_sibling_first(first, dup, &top_node)) && (ret != LY_ENOTFOUND)) {
+                    goto cleanup;
+                }
+            } else {
+                top_node = NULL;
+            }
+
+            if (top_node) {
+                /* merge */
+                ret = lyd_merge_tree(&first, dup, LYD_MERGE_DESTRUCT);
+                dup = NULL;
+                if (ret) {
+                    goto cleanup;
+                }
+            } else {
+                /* insert */
+                if ((ret = lyd_insert_sibling(first, dup, &first))) {
+                    goto cleanup;
+                }
+
+                /* add into the result set because a new top-level node was added */
+                if ((ret = ly_set_add(*ref_set, dup, 1, NULL))) {
+                    goto cleanup;
+                }
+                dup = NULL;
+            }
+        }
+    }
+
+cleanup:
+    free(path);
+    ly_set_free(set, NULL);
+    ly_set_free(par_set, NULL);
+    lyd_free_tree(dup);
+    if (ret && *ref_set) {
+        if ((*ref_set)->count) {
+            lyd_free_siblings((*ref_set)->dnodes[0]);
+        }
+        ly_set_free(*ref_set, NULL);
+        *ref_set = NULL;
+    }
+    return ret;
+}
+
+/**
+ * @brief Validate callback for schema mount.
+ */
+static LY_ERR
+schema_mount_validate(struct lysc_ext_instance *ext, struct lyd_node *sibling, uint32_t val_opts)
+{
+    LY_ERR ret = LY_SUCCESS;
+    uint32_t old_log_opts, i;
+    struct ly_err_item *err;
+    struct lyd_node *iter, *ext_data = NULL, *ref_first = NULL, *orig_parent = lyd_parent(sibling);
+    ly_bool ext_data_free = 0;
+    struct ly_set *ref_set = NULL;
+
+    if (!sibling) {
+        /* some data had to be parsed for this callback to be called */
+        EXT_LOGERR_INT_RET(ext);
+    }
+
+    /* get operational data with ietf-yang-library and ietf-yang-schema-mount data */
+    if ((ret = lyplg_ext_get_data(ext->module->ctx, ext, (void **)&ext_data, &ext_data_free))) {
+        goto cleanup;
+    }
+
+    LY_LIST_FOR(ext_data, iter) {
+        if (iter->flags & LYD_NEW) {
+            /* must be validated for the parent-reference prefix data to be stored */
+            lyplg_ext_log(ext, LY_LLERR, LY_EINVAL, NULL, "Provided ext data have not been validated.");
+            ret = LY_EINVAL;
+            goto cleanup;
+        }
+    }
+
+    /* duplicate the referenced parent nodes into ext context */
+    if ((ret = schema_mount_dup_parent_ref(ext, orig_parent, ext_data, LYD_CTX(sibling), &ref_set))) {
+        goto cleanup;
+    }
+
+    /* create accessible tree, remove LYD_EXT to not call this callback recursively */
+    lyd_unlink_siblings(sibling);
+    LY_LIST_FOR(sibling, iter) {
+        iter->flags &= ~LYD_EXT;
+    }
+    if (ref_set->count) {
+        if ((ret = lyd_insert_sibling(sibling, ref_set->dnodes[0], &sibling))) {
+            goto cleanup;
+        }
+    }
+
+    /* only store messages in the context, log as an extension */
+    old_log_opts = ly_log_options(LY_LOSTORE_LAST);
+
+    /* validate all the data */
+    ret = lyd_validate_all(&sibling, NULL, val_opts, NULL);
+    ly_log_options(old_log_opts);
+
+    /* restore sibling tree */
+    for (i = 0; i < ref_set->count; ++i) {
+        if (ref_set->dnodes[i] == sibling) {
+            sibling = sibling->next;
+        }
+        lyd_free_tree(ref_set->dnodes[i]);
+    }
+    LY_LIST_FOR(sibling, iter) {
+        iter->flags |= LYD_EXT;
+    }
+    lyd_insert_ext(orig_parent, sibling);
+
+    if (ret) {
+        /* log the error in the original context */
+        err = ly_err_first(LYD_CTX(sibling));
+        if (!err) {
+            lyplg_ext_log(ext, LY_LLERR, ret, NULL, "Unknown validation error (err code %d).", ret);
+        } else {
+            lyplg_ext_log(ext, LY_LLERR, err->no, err->path, "%s", err->msg);
+        }
+        goto cleanup;
+    }
+
+cleanup:
+    ly_set_free(ref_set, NULL);
+    lyd_free_siblings(ref_first);
+    if (ext_data_free) {
+        lyd_free_all(ext_data);
+    }
+    return ret;
+}
+
+/**
+ * @brief Schema mount free.
+ *
+ * Implementation of ::lyplg_ext_free_clb callback set as ::lyext_plugin::free.
+ */
+static void
+schema_mount_free(struct ly_ctx *ctx, struct lysc_ext_instance *ext)
+{
+    struct lyplg_ext_sm *sm_data = ext->data;
+    uint32_t i;
+
+    if (!sm_data) {
+        return;
+    }
+
+    if (!--sm_data->shared->ref_count) {
+        for (i = 0; i < sm_data->shared->schema_count; ++i) {
+            ly_ctx_destroy(sm_data->shared->schemas[i].ctx);
+            lydict_remove(ctx, sm_data->shared->schemas[i].content_id);
+        }
+        free(sm_data->shared->schemas);
+        pthread_mutex_destroy(&sm_data->shared->lock);
+        free(sm_data->shared);
+    }
+
+    for (i = 0; i < sm_data->inln.schema_count; ++i) {
+        ly_ctx_destroy(sm_data->inln.schemas[i].ctx);
+    }
+    free(sm_data->inln.schemas);
+    free(sm_data);
+}
+
+/**
  * @brief Plugin descriptions for the Yang Schema Mount extension.
  *
  * Note that external plugins are supposed to use:
@@ -199,10 +808,10 @@
 
         .plugin.id = "libyang 2 - Schema Mount, version 1",
         .plugin.compile = &schema_mount_compile,
-        .plugin.parse = &schema_mount_parse,
-        .plugin.validate = NULL,
         .plugin.sprinter = NULL,
-        .plugin.free = NULL
+        .plugin.free = &schema_mount_free,
+        .plugin.parse = &schema_mount_parse,
+        .plugin.validate = &schema_mount_validate
     },
     {0} /* terminating zeroed item */
 };
diff --git a/src/plugins_exts/yangdata.c b/src/plugins_exts/yangdata.c
index 0c96a14..55a03e3 100644
--- a/src/plugins_exts/yangdata.c
+++ b/src/plugins_exts/yangdata.c
@@ -172,10 +172,10 @@
 
         .plugin.id = "libyang 2 - yang-data, version 1",
         .plugin.compile = &yangdata_compile,
-        .plugin.parse = NULL,
-        .plugin.validate = NULL,
         .plugin.sprinter = &yangdata_schema_printer,
-        .plugin.free = yangdata_free
+        .plugin.free = yangdata_free,
+        .plugin.parse = NULL,
+        .plugin.validate = NULL
     },
     {0}     /* terminating zeroed record */
 };
diff --git a/src/plugins_types.c b/src/plugins_types.c
index 372c783..5d0a82d 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -134,6 +134,7 @@
         mod = ly_schema_resolved_resolve_prefix(ctx, prefix, prefix_len, prefix_data);
         break;
     case LY_VALUE_XML:
+    case LY_VALUE_STR_NS:
         mod = ly_xml_resolve_prefix(ctx, prefix, prefix_len, prefix_data);
         break;
     case LY_VALUE_CANON:
@@ -147,8 +148,8 @@
 }
 
 LIBYANG_API_DEF const struct lys_module *
-lyplg_type_identity_module(const struct ly_ctx *ctx, const struct lysc_node *ctx_node,
-        const char *prefix, size_t prefix_len, LY_VALUE_FORMAT format, const void *prefix_data)
+lyplg_type_identity_module(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *prefix,
+        size_t prefix_len, LY_VALUE_FORMAT format, const void *prefix_data)
 {
     if (prefix_len) {
         return ly_resolve_prefix(ctx, prefix, prefix_len, format, prefix_data);
@@ -163,8 +164,9 @@
         case LY_VALUE_CANON:
         case LY_VALUE_JSON:
         case LY_VALUE_LYB:
+        case LY_VALUE_STR_NS:
             /* use context node module (as specified) */
-            return ctx_node->module;
+            return ctx_node ? ctx_node->module : NULL;
         case LY_VALUE_XML:
             /* use the default namespace */
             return ly_xml_resolve_prefix(ctx, NULL, 0, prefix_data);
@@ -253,6 +255,7 @@
         prefix = ly_schema_resolved_get_prefix(mod, prefix_data);
         break;
     case LY_VALUE_XML:
+    case LY_VALUE_STR_NS:
         prefix = ly_xml_get_prefix(mod, prefix_data);
         break;
     case LY_VALUE_CANON:
@@ -784,6 +787,7 @@
     case LY_VALUE_CANON:
     case LY_VALUE_LYB:
     case LY_VALUE_JSON:
+    case LY_VALUE_STR_NS:
         prefix_opt = LY_PATH_PREFIX_STRICT_INHERIT;
         break;
     }
@@ -861,7 +865,7 @@
 {
     LY_ERR ret;
     struct lyxp_set set = {0};
-    const char *val_str;
+    const char *val_str, *xp_err_msg;
     uint32_t i;
     int rc;
 
@@ -871,9 +875,19 @@
     ret = lyxp_eval(LYD_CTX(node), lref->path, node->schema->module, LY_VALUE_SCHEMA_RESOLVED, lref->prefixes,
             node, tree, NULL, &set, LYXP_IGNORE_WHEN);
     if (ret) {
-        ret = LY_ENOTFOUND;
+        if (ly_errcode(LYD_CTX(node)) == ret) {
+            xp_err_msg = ly_errmsg(LYD_CTX(node));
+        } else {
+            xp_err_msg = NULL;
+        }
+
         val_str = lref->plugin->print(LYD_CTX(node), value, LY_VALUE_CANON, NULL, NULL, NULL);
-        if (asprintf(errmsg, "Invalid leafref value \"%s\" - XPath evaluation error.", val_str) == -1) {
+        if (xp_err_msg) {
+            rc = asprintf(errmsg, "Invalid leafref value \"%s\" - XPath evaluation error (%s).", val_str, xp_err_msg);
+        } else {
+            rc = asprintf(errmsg, "Invalid leafref value \"%s\" - XPath evaluation error.", val_str);
+        }
+        if (rc == -1) {
             *errmsg = NULL;
             ret = LY_EMEM;
         }
diff --git a/src/plugins_types.h b/src/plugins_types.h
index 13cee84..e9aa723 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -223,8 +223,8 @@
  * @return LY_EMEM If there is not enough memory for allocating error record, the @p err is not touched in that case.
  * @return LY_SUCCESS if @p ecode is LY_SUCCESS, the @p err is not touched in this case.
  */
-LIBYANG_API_DECL LY_ERR ly_err_new(struct ly_err_item **err, LY_ERR ecode, LY_VECODE vecode, char *path, char *apptag, const char *err_format, ...)
-_FORMAT_PRINTF(6, 7);
+LIBYANG_API_DECL LY_ERR ly_err_new(struct ly_err_item **err, LY_ERR ecode, LY_VECODE vecode, char *path, char *apptag,
+        const char *err_format, ...) _FORMAT_PRINTF(6, 7);
 
 /**
  * @brief Destructor for the error records created with ::ly_err_new().
@@ -251,8 +251,8 @@
  * @param[out] err Pointer to store error information in case of failure.
  * @return LY_ERR value
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_check_hints(uint32_t hints, const char *value, size_t value_len, LY_DATA_TYPE type, int *base,
-        struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_check_hints(uint32_t hints, const char *value, size_t value_len, LY_DATA_TYPE type,
+        int *base, struct ly_err_item **err);
 
 /**
  * @brief Check that the value of a type is allowed based on its status.
@@ -297,8 +297,9 @@
  * @return Resolved prefix module,
  * @return NULL otherwise.
  */
-LIBYANG_API_DECL const struct lys_module *lyplg_type_identity_module(const struct ly_ctx *ctx, const struct lysc_node *ctx_node,
-        const char *prefix, size_t prefix_len, LY_VALUE_FORMAT format, const void *prefix_data);
+LIBYANG_API_DECL const struct lys_module *lyplg_type_identity_module(const struct ly_ctx *ctx,
+        const struct lysc_node *ctx_node, const char *prefix, size_t prefix_len, LY_VALUE_FORMAT format,
+        const void *prefix_data);
 
 /**
  * @brief Implement a module (just like ::lys_set_implemented()), but keep maintaining unresolved items.
@@ -311,7 +312,8 @@
  * @return LY_ERECOMPILE if the context need to be recompiled, should be returned.
  * @return LY_ERR value.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_make_implemented(struct lys_module *mod, const char **features, struct lys_glob_unres *unres);
+LIBYANG_API_DECL LY_ERR lyplg_type_make_implemented(struct lys_module *mod, const char **features,
+        struct lys_glob_unres *unres);
 
 /**
  * @brief Get the bitmap size of a bits value bitmap.
@@ -364,8 +366,8 @@
  * @param[in,out] prefix_data_p Resulting prefix data for the value in format @p format_p.
  * @return LY_ERR value.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_prefix_data_new(const struct ly_ctx *ctx, const void *value, size_t value_len, LY_VALUE_FORMAT format,
-        const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p);
+LIBYANG_API_DECL LY_ERR lyplg_type_prefix_data_new(const struct ly_ctx *ctx, const void *value, size_t value_len,
+        LY_VALUE_FORMAT format, const void *prefix_data, LY_VALUE_FORMAT *format_p, void **prefix_data_p);
 /**
  * @brief Duplicate prefix data.
  *
@@ -377,7 +379,8 @@
  * @param[out] dup Duplicated prefix data.
  * @return LY_ERR value.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_prefix_data_dup(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *orig, void **dup);
+LIBYANG_API_DECL LY_ERR lyplg_type_prefix_data_dup(const struct ly_ctx *ctx, LY_VALUE_FORMAT format, const void *orig,
+        void **dup);
 
 /**
  * @brief Free internal prefix data.
@@ -396,7 +399,7 @@
  *
  * @param[in] ctx libyang Context
  * @param[in] value Lexical representation of the value to be stored.
- * @param[in] value_len Length (number of bytes) of the given \p value.
+ * @param[in] value_len Length (number of bytes) of the given @p value.
  * @param[in] options [Type plugin store options](@ref plugintypestoreopts).
  * @param[in] format Input format of the value.
  * @param[in] prefix_data Format-specific data for resolving any prefixes (see ly_resolve_prefix()).
@@ -408,8 +411,8 @@
  * @return LY_ERECOMPILE if the context need to be recompiled, should be returned.
  * @return LY_ERR value on error.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_lypath_new(const struct ly_ctx *ctx, const char *value, size_t value_len, uint32_t options,
-        LY_VALUE_FORMAT format, void *prefix_data, const struct lysc_node *ctx_node,
+LIBYANG_API_DECL LY_ERR lyplg_type_lypath_new(const struct ly_ctx *ctx, const char *value, size_t value_len,
+        uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, const struct lysc_node *ctx_node,
         struct lys_glob_unres *unres, struct ly_path **path, struct ly_err_item **err);
 
 /**
@@ -457,18 +460,18 @@
  * @param[in] format Input format of the value, see the description for details.
  * @param[in] prefix_data Format-specific data for resolving any prefixes (see ly_resolve_prefix()).
  * @param[in] hints Bitmap of [value hints](@ref lydvalhints) of all the allowed value types.
- * @param[in] ctx_node Schema context node of @p value.
+ * @param[in] ctx_node Schema context node of @p value, may be NULL for metadata.
  * @param[out] storage Storage for the value in the type's specific encoding. Except for _canonical, all the members
  * should be filled by the plugin (if it fills them at all).
  * @param[in,out] unres Global unres structure for newly implemented modules.
  * @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic
- *             error message is prepared instead. The error structure can be created by ::ly_err_new().
+ * error message is prepared instead. The error structure can be created by ::ly_err_new().
  * @return LY_SUCCESS on success,
  * @return LY_EINCOMPLETE in case the ::lyplg_type_validate_clb should be called to finish value validation in data,
  * @return LY_ERR value on error.
  */
-LIBYANG_API_DECL typedef LY_ERR (*lyplg_type_store_clb)(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
-        size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+LIBYANG_API_DECL typedef LY_ERR (*lyplg_type_store_clb)(const struct ly_ctx *ctx, const struct lysc_type *type,
+        const void *value, size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
         const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
 
 /**
@@ -612,13 +615,14 @@
 /**
  * @brief Implementation of ::lyplg_type_print_clb for a generic simple type.
  */
-LIBYANG_API_DECL const void *lyplg_type_print_simple(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
-        void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_simple(const struct ly_ctx *ctx, const struct lyd_value *value,
+        LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
 
 /**
  * @brief Implementation of ::lyplg_type_dup_clb for a generic simple type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_dup_simple(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
+LIBYANG_API_DECL LY_ERR lyplg_type_dup_simple(const struct ly_ctx *ctx, const struct lyd_value *original,
+        struct lyd_value *dup);
 
 /**
  * @brief Implementation of ::lyplg_type_free_clb for a generic simple type.
@@ -638,9 +642,9 @@
 /**
  * @brief Implementation of ::lyplg_type_store_clb for the built-in binary type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_store_binary(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
-        uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
-        struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_binary(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+        size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+        const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
 
 /**
  * @brief Implementation of ::lyplg_type_compare_clb for the built-in binary type.
@@ -650,13 +654,14 @@
 /**
  * @brief Implementation of ::lyplg_type_print_clb for the built-in binary type.
  */
-LIBYANG_API_DECL const void *lyplg_type_print_binary(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
-        void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_binary(const struct ly_ctx *ctx, const struct lyd_value *value,
+        LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
 
 /**
  * @brief Implementation of ::lyplg_type_dup_clb for the built-in binary type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_dup_binary(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
+LIBYANG_API_DECL LY_ERR lyplg_type_dup_binary(const struct ly_ctx *ctx, const struct lyd_value *original,
+        struct lyd_value *dup);
 
 /**
  * @brief Implementation of ::lyplg_type_free_clb for the built-in binary type.
@@ -676,9 +681,9 @@
 /**
  * @brief Implementation of the ::lyplg_type_store_clb for the built-in bits type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_store_bits(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
-        uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
-        struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_bits(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+        size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+        const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
 
 /**
  * @brief Implementation of the ::lyplg_type_compare_clb for the built-in bits type.
@@ -688,13 +693,14 @@
 /**
  * @brief Implementation of the ::lyplg_type_print_clb for the built-in bits type.
  */
-LIBYANG_API_DECL const void *lyplg_type_print_bits(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
-        void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_bits(const struct ly_ctx *ctx, const struct lyd_value *value,
+        LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
 
 /**
  * @brief Implementation of the ::lyplg_type_dup_clb for the built-in bits type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_dup_bits(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
+LIBYANG_API_DECL LY_ERR lyplg_type_dup_bits(const struct ly_ctx *ctx, const struct lyd_value *original,
+        struct lyd_value *dup);
 
 /**
  * @brief Implementation of the ::lyplg_type_free_clb for the built-in bits type.
@@ -714,9 +720,9 @@
 /**
  * @brief Implementation of ::lyplg_type_store_clb for the built-in boolean type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_store_boolean(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
-        uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
-        struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_boolean(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+        size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+        const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
 
 /**
  * @brief Implementation of ::lyplg_type_compare_clb for the built-in boolean type.
@@ -726,8 +732,8 @@
 /**
  * @brief Implementation of ::lyplg_type_print_clb for the built-in boolean type.
  */
-LIBYANG_API_DECL const void *lyplg_type_print_boolean(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
-        void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_boolean(const struct ly_ctx *ctx, const struct lyd_value *value,
+        LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
 
 /** @} pluginsTypesBoolean */
 
@@ -742,9 +748,9 @@
 /**
  * @brief Implementation of ::lyplg_type_store_clb for the built-in decimal64 type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_store_decimal64(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
-        uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
-        struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_decimal64(const struct ly_ctx *ctx, const struct lysc_type *type,
+        const void *value, size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+        const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
 
 /**
  * @brief Implementation of ::lyplg_type_compare_clb for the built-in decimal64 type.
@@ -754,8 +760,8 @@
 /**
  * @brief Implementation of ::lyplg_type_print_clb for the built-in decimal64 type.
  */
-LIBYANG_API_DECL const void *lyplg_type_print_decimal64(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
-        void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_decimal64(const struct ly_ctx *ctx, const struct lyd_value *value,
+        LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
 
 /** @} pluginsTypesDecimal64 */
 
@@ -770,9 +776,9 @@
 /**
  * @brief Implementation of ::lyplg_type_store_clb for the built-in empty type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_store_empty(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
-        uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
-        struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_empty(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+        size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+        const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
 
 /** @} pluginsTypesEmpty */
 
@@ -787,15 +793,15 @@
 /**
  * @brief Implementation of ::lyplg_type_store_clb for the built-in enumeration type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_store_enum(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
-        uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
-        struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_enum(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+        size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+        const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
 
 /**
  * @brief Implementation of ::lyplg_type_print_clb for the built-in enumeration type.
  */
-LIBYANG_API_DECL const void *lyplg_type_print_enum(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
-        void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_enum(const struct ly_ctx *ctx, const struct lyd_value *value,
+        LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
 
 /** @} pluginsTypesEnumeration */
 
@@ -810,9 +816,9 @@
 /**
  * @brief Implementation of ::lyplg_type_store_clb for the built-in identityref type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_store_identityref(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
-        uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
-        struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_identityref(const struct ly_ctx *ctx, const struct lysc_type *type,
+        const void *value, size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+        const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
 
 /**
  * @brief Implementation of ::lyplg_type_compare_clb for the built-in identityref type.
@@ -822,8 +828,8 @@
 /**
  * @brief Implementation of ::lyplg_type_print_clb for the built-in identityref type.
  */
-LIBYANG_API_DECL const void *lyplg_type_print_identityref(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
-        void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_identityref(const struct ly_ctx *ctx, const struct lyd_value *value,
+        LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
 
 /** @} pluginsTypesIdentityref */
 
@@ -838,15 +844,15 @@
 /**
  * @brief Implementation of ::lyplg_type_store_clb for the built-in instance-identifier type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_store_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
-        uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
-        struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type,
+        const void *value, size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+        const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
 
 /**
  * @brief Implementation of ::lyplg_type_validate_clb for the built-in instance-identifier type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_validate_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type, const struct lyd_node *ctx_node,
-        const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_validate_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type,
+        const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err);
 
 /**
  * @brief Implementation of ::lyplg_type_compare_clb for the built-in instance-identifier type.
@@ -856,13 +862,14 @@
 /**
  * @brief Implementation of ::lyplg_type_print_clb for the built-in instance-identifier type.
  */
-LIBYANG_API_DECL const void *lyplg_type_print_instanceid(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
-        void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_instanceid(const struct ly_ctx *ctx, const struct lyd_value *value,
+        LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
 
 /**
  * @brief Implementation of ::lyplg_type_dup_clb for the built-in instance-identifier type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_dup_instanceid(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
+LIBYANG_API_DECL LY_ERR lyplg_type_dup_instanceid(const struct ly_ctx *ctx, const struct lyd_value *original,
+        struct lyd_value *dup);
 
 /**
  * @brief Implementation of ::lyplg_type_free_clb for the built-in instance-identifier type.
@@ -882,9 +889,9 @@
 /**
  * @brief Implementation of ::lyplg_type_store_clb for the built-in signed integer types.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_store_int(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
-        uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
-        struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_int(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+        size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+        const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
 
 /**
  * @brief Implementation of ::lyplg_type_compare_clb for the built-in signed integer types.
@@ -894,15 +901,15 @@
 /**
  * @brief Implementation of ::lyplg_type_print_clb for the built-in signed integer types.
  */
-LIBYANG_API_DECL const void *lyplg_type_print_int(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
-        void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_int(const struct ly_ctx *ctx, const struct lyd_value *value,
+        LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
 
 /**
  * @brief Implementation of ::lyplg_type_store_clb for the built-in unsigned integer types.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_store_uint(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
-        uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
-        struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_uint(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+        size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+        const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
 
 /**
  * @brief Implementation of ::lyplg_type_compare_clb for the built-in unsigned integer types.
@@ -912,8 +919,8 @@
 /**
  * @brief Implementation of ::lyplg_type_print_clb for the built-in unsigned integer types.
  */
-LIBYANG_API_DECL const void *lyplg_type_print_uint(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
-        void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_uint(const struct ly_ctx *ctx, const struct lyd_value *value,
+        LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
 
 /** @} pluginsTypesInteger */
 
@@ -928,9 +935,9 @@
 /**
  * @brief Implementation of ::lyplg_type_store_clb for the built-in leafref type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_store_leafref(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
-        uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
-        struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_leafref(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+        size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+        const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
 
 /**
  * @brief Implementation of ::lyplg_type_compare_clb for the built-in leafref type.
@@ -940,19 +947,20 @@
 /**
  * @brief Implementation of ::lyplg_type_print_clb for the built-in leafref type.
  */
-LIBYANG_API_DECL const void *lyplg_type_print_leafref(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
-        void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_leafref(const struct ly_ctx *ctx, const struct lyd_value *value,
+        LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
 
 /**
  * @brief Implementation of ::lyplg_type_dup_clb for the built-in leafref type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_dup_leafref(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
+LIBYANG_API_DECL LY_ERR lyplg_type_dup_leafref(const struct ly_ctx *ctx, const struct lyd_value *original,
+        struct lyd_value *dup);
 
 /**
  * @brief Implementation of ::lyplg_type_validate_clb for the built-in leafref type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_validate_leafref(const struct ly_ctx *ctx, const struct lysc_type *type, const struct lyd_node *ctx_node,
-        const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_validate_leafref(const struct ly_ctx *ctx, const struct lysc_type *type,
+        const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err);
 
 /**
  * @brief Implementation of ::lyplg_type_free_clb for the built-in leafref type.
@@ -972,9 +980,9 @@
 /**
  * @brief Implementation of ::lyplg_type_store_clb for the built-in string type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_store_string(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
-        uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
-        struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_string(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+        size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+        const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
 
 /** @} pluginsTypesString */
 
@@ -989,9 +997,9 @@
 /**
  * @brief Implementation of ::lyplg_type_store_clb for the built-in union type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
-        uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
-        struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+        size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+        const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
 
 /**
  * @brief Implementation of ::lyplg_type_compare_clb for the built-in union type.
@@ -1001,19 +1009,20 @@
 /**
  * @brief Implementation of ::lyplg_type_print_clb for the built-in union type.
  */
-LIBYANG_API_DECL const void *lyplg_type_print_union(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
-        void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_union(const struct ly_ctx *ctx, const struct lyd_value *value,
+        LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
 
 /**
  * @brief Implementation of ::lyplg_type_dup_clb for the built-in union type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
+LIBYANG_API_DECL LY_ERR lyplg_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original,
+        struct lyd_value *dup);
 
 /**
  * @brief Implementation of ::lyplg_type_validate_clb for the built-in union type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_validate_union(const struct ly_ctx *ctx, const struct lysc_type *type, const struct lyd_node *ctx_node,
-        const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_validate_union(const struct ly_ctx *ctx, const struct lysc_type *type,
+        const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err);
 
 /**
  * @brief Implementation of ::lyplg_type_free_clb for the built-in union type.
@@ -1033,9 +1042,9 @@
 /**
  * @brief Implementation of ::lyplg_type_store_clb for the ietf-yang-types xpath1.0 type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_store_xpath10(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
-        uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
-        struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_store_xpath10(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value,
+        size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+        const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
 
 /**
  * @brief Implementation of ::lyplg_type_compare_clb for the ietf-yang-types xpath1.0 type.
@@ -1045,13 +1054,14 @@
 /**
  * @brief Implementation of ::lyplg_type_print_clb for the ietf-yang-types xpath1.0 type.
  */
-LIBYANG_API_DECL const void *lyplg_type_print_xpath10(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
-        void *prefix_data, ly_bool *dynamic, size_t *value_len);
+LIBYANG_API_DECL const void *lyplg_type_print_xpath10(const struct ly_ctx *ctx, const struct lyd_value *value,
+        LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
 
 /**
  * @brief Implementation of ::lyplg_type_dup_clb for the ietf-yang-types xpath1.0 type.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_dup_xpath10(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
+LIBYANG_API_DECL LY_ERR lyplg_type_dup_xpath10(const struct ly_ctx *ctx, const struct lyd_value *original,
+        struct lyd_value *dup);
 
 /**
  * @brief Implementation of ::lyplg_type_free_clb for the ietf-yang-types xpath1.0 type.
@@ -1074,8 +1084,8 @@
  * @param[out] err Error information in case of failure. The error structure can be freed by ::ly_err_free().
  * @return LY_ERR value according to the result of the parsing and validation.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_parse_int(const char *datatype, int base, int64_t min, int64_t max, const char *value, size_t value_len,
-        int64_t *ret, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_parse_int(const char *datatype, int base, int64_t min, int64_t max, const char *value,
+        size_t value_len, int64_t *ret, struct ly_err_item **err);
 
 /**
  * @brief Unsigned integer value parser and validator.
@@ -1090,8 +1100,8 @@
  * @param[out] err Error information in case of failure. The error structure can be freed by ::ly_err_free().
  * @return LY_ERR value according to the result of the parsing and validation.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_parse_uint(const char *datatype, int base, uint64_t max, const char *value, size_t value_len,
-        uint64_t *ret, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_parse_uint(const char *datatype, int base, uint64_t max, const char *value,
+        size_t value_len, uint64_t *ret, struct ly_err_item **err);
 
 /**
  * @brief Convert a string with a decimal64 value into libyang representation:
@@ -1104,7 +1114,8 @@
  * @param[out] err Error information in case of failure. The error structure can be freed by ::ly_err_free().
  * @return LY_ERR value according to the result of the parsing and validation.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_parse_dec64(uint8_t fraction_digits, const char *value, size_t value_len, int64_t *ret, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_parse_dec64(uint8_t fraction_digits, const char *value, size_t value_len, int64_t *ret,
+        struct ly_err_item **err);
 
 /**
  * @brief Decide if the @p derived identity is derived from (based on) the @p base identity.
@@ -1127,8 +1138,8 @@
  * @param[out] err Error information in case of failure. The error structure can be freed by ::ly_err_free().
  * @return LY_ERR value according to the result of the validation.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_validate_range(LY_DATA_TYPE basetype, struct lysc_range *range, int64_t value, const char *strval,
-        size_t strval_len, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_validate_range(LY_DATA_TYPE basetype, struct lysc_range *range, int64_t value,
+        const char *strval, size_t strval_len, struct ly_err_item **err);
 
 /**
  * @brief Data type validator for pattern-restricted string values.
@@ -1142,7 +1153,8 @@
  * @return LY_EVALID when @p does not match any of the patterns.
  * @return LY_ESYS in case of PCRE2 error.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_validate_patterns(struct lysc_pattern **patterns, const char *str, size_t str_len, struct ly_err_item **err);
+LIBYANG_API_DECL LY_ERR lyplg_type_validate_patterns(struct lysc_pattern **patterns, const char *str, size_t str_len,
+        struct ly_err_item **err);
 
 /**
  * @brief Find leafref target in data.
@@ -1155,8 +1167,8 @@
  * @param[out] errmsg Error message in case of error.
  * @return LY_ERR value.
  */
-LIBYANG_API_DECL LY_ERR lyplg_type_resolve_leafref(const struct lysc_type_leafref *lref, const struct lyd_node *node, struct lyd_value *value,
-        const struct lyd_node *tree, struct lyd_node **target, char **errmsg);
+LIBYANG_API_DECL LY_ERR lyplg_type_resolve_leafref(const struct lysc_type_leafref *lref, const struct lyd_node *node,
+        struct lyd_value *value, const struct lyd_node *tree, struct lyd_node **target, char **errmsg);
 
 /** @} pluginsTypes */
 
diff --git a/src/plugins_types/identityref.c b/src/plugins_types/identityref.c
index 7eee215..8b7985d 100644
--- a/src/plugins_types/identityref.c
+++ b/src/plugins_types/identityref.c
@@ -249,9 +249,11 @@
     ret = identityref_check_base(ident, type_ident, value, value_len, err);
     LY_CHECK_GOTO(ret, cleanup);
 
-    /* check status */
-    ret = lyplg_type_check_status(ctx_node, ident->flags, format, prefix_data, ident->name, err);
-    LY_CHECK_GOTO(ret, cleanup);
+    if (ctx_node) {
+        /* check status */
+        ret = lyplg_type_check_status(ctx_node, ident->flags, format, prefix_data, ident->name, err);
+        LY_CHECK_GOTO(ret, cleanup);
+    }
 
     /* store value */
     storage->ident = ident;
diff --git a/src/plugins_types/instanceid.c b/src/plugins_types/instanceid.c
index 4481067..d151d0a 100644
--- a/src/plugins_types/instanceid.c
+++ b/src/plugins_types/instanceid.c
@@ -64,6 +64,7 @@
     case LY_VALUE_CANON:
     case LY_VALUE_JSON:
     case LY_VALUE_LYB:
+    case LY_VALUE_STR_NS:
         /* the same prefix is inherited and skipped */
         inherit_prefix = 1;
         break;
diff --git a/src/plugins_types/node_instanceid.c b/src/plugins_types/node_instanceid.c
index 31781d6..3e3eba7 100644
--- a/src/plugins_types/node_instanceid.c
+++ b/src/plugins_types/node_instanceid.c
@@ -64,6 +64,7 @@
     case LY_VALUE_CANON:
     case LY_VALUE_JSON:
     case LY_VALUE_LYB:
+    case LY_VALUE_STR_NS:
         /* the same prefix is inherited and skipped */
         inherit_prefix = 1;
         break;
@@ -172,6 +173,7 @@
     case LY_VALUE_CANON:
     case LY_VALUE_LYB:
     case LY_VALUE_JSON:
+    case LY_VALUE_STR_NS:
         prefix_opt = LY_PATH_PREFIX_STRICT_INHERIT;
         break;
     }
@@ -191,7 +193,7 @@
 
     /* resolve it on schema tree, use JSON format instead of LYB because for this type they are equal but for some
      * nested types (such as numbers in predicates in the path) LYB would be invalid */
-    ret = ly_path_compile(ctx, NULL, ctx_node, NULL, exp, (ctx_node->flags & LYS_IS_OUTPUT) ?
+    ret = ly_path_compile(ctx, NULL, ctx_node, NULL, exp, (ctx_node && (ctx_node->flags & LYS_IS_OUTPUT)) ?
             LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_MANY, 1, (format == LY_VALUE_LYB) ?
             LY_VALUE_JSON : format, prefix_data, &path);
     if (ret) {
diff --git a/src/plugins_types/xpath1.0.c b/src/plugins_types/xpath1.0.c
index 2d29e58..cdcc113 100644
--- a/src/plugins_types/xpath1.0.c
+++ b/src/plugins_types/xpath1.0.c
@@ -12,17 +12,22 @@
  *     https://opensource.org/licenses/BSD-3-Clause
  */
 
+#define _GNU_SOURCE
+
 #include "plugins_types.h"
 
+#include <assert.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include "libyang.h"
 
 #include "common.h"
 #include "compat.h"
 
-/* internal header */
+/* internal headers */
+#include "xml.h"
 #include "xpath.h"
 
 /**
@@ -35,16 +40,6 @@
  */
 
 /**
- * @brief Stored value structure for xpath1.0
- */
-struct lyd_value_xpath10 {
-    struct lyxp_expr *exp;
-    const struct ly_ctx *ctx;
-    void *prefix_data;
-    LY_VALUE_FORMAT format;
-};
-
-/**
  * @brief Print xpath1.0 token in the specific format.
  *
  * @param[in] token Token to transform.
@@ -268,9 +263,8 @@
 
 LIBYANG_API_DEF LY_ERR
 lyplg_type_store_xpath10(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
-        uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
-        const struct lysc_node *UNUSED(ctx_node), struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres),
-        struct ly_err_item **err)
+        uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
+        struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres), struct ly_err_item **err)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lysc_type_str *type_str = (struct lysc_type_str *)type;
@@ -298,17 +292,28 @@
     ret = lyplg_type_validate_patterns(type_str->patterns, value, value_len, err);
     LY_CHECK_GOTO(ret, cleanup);
 
-    /* store format-specific data and context for later prefix resolution */
-    ret = lyplg_type_prefix_data_new(ctx, value, value_len, format, prefix_data, &val->format, &val->prefix_data);
-    LY_CHECK_GOTO(ret, cleanup);
-    val->ctx = ctx;
-
     /* parse */
     ret = lyxp_expr_parse(ctx, value_len ? value : "", value_len, 1, &val->exp);
     LY_CHECK_GOTO(ret, cleanup);
+    val->ctx = ctx;
 
-    /* store canonical value */
-    if ((format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) || (format == LY_VALUE_LYB)) {
+    if (ctx_node && !strcmp(ctx_node->name, "parent-reference") && !strcmp(ctx_node->module->name, "ietf-yang-schema-mount")) {
+        /* special case, this type uses prefix-namespace mapping provided directly in data, keep empty for now */
+        val->format = format = LY_VALUE_STR_NS;
+        ret = ly_set_new((struct ly_set **)&val->prefix_data);
+        LY_CHECK_GOTO(ret, cleanup);
+    } else {
+        /* store format-specific data and context for later prefix resolution */
+        ret = lyplg_type_prefix_data_new(ctx, value, value_len, format, prefix_data, &val->format, &val->prefix_data);
+        LY_CHECK_GOTO(ret, cleanup);
+    }
+
+    switch (format) {
+    case LY_VALUE_CANON:
+    case LY_VALUE_JSON:
+    case LY_VALUE_LYB:
+    case LY_VALUE_STR_NS:
+        /* store canonical value */
         if (options & LYPLG_TYPE_STORE_DYNAMIC) {
             ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
             options &= ~LYPLG_TYPE_STORE_DYNAMIC;
@@ -317,13 +322,17 @@
             ret = lydict_insert(ctx, value_len ? value : "", value_len, &storage->_canonical);
             LY_CHECK_GOTO(ret, cleanup);
         }
-    } else {
+        break;
+    case LY_VALUE_SCHEMA:
+    case LY_VALUE_SCHEMA_RESOLVED:
+    case LY_VALUE_XML:
         /* JSON format with prefix is the canonical one */
         ret = xpath10_print_value(val, LY_VALUE_JSON, NULL, &canon, err);
         LY_CHECK_GOTO(ret, cleanup);
 
         ret = lydict_insert_zc(ctx, canon, &storage->_canonical);
         LY_CHECK_GOTO(ret, cleanup);
+        break;
     }
 
 cleanup:
@@ -333,6 +342,91 @@
 
     if (ret) {
         lyplg_type_free_xpath10(ctx, storage);
+    } else if (val->format == LY_VALUE_STR_NS) {
+        /* needs validation */
+        return LY_EINCOMPLETE;
+    }
+    return ret;
+}
+
+/**
+ * @brief Implementation of ::lyplg_type_validate_clb for the xpath1.0 ietf-yang-types type.
+ */
+static LY_ERR
+lyplg_type_validate_xpath10(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *UNUSED(type),
+        const struct lyd_node *ctx_node, const struct lyd_node *UNUSED(tree), struct lyd_value *storage,
+        struct ly_err_item **err)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct lyd_value_xpath10 *val;
+    struct ly_set *set = NULL;
+    uint32_t i;
+    const char *pref, *uri;
+    struct lyxml_ns *ns;
+
+    *err = NULL;
+    LYD_VALUE_GET(storage, val);
+
+    if (val->format != LY_VALUE_STR_NS) {
+        /* nothing to validate */
+        return LY_SUCCESS;
+    }
+
+    /* the XML namespace set must exist */
+    assert(val->prefix_data);
+
+    /* special handling of this particular node */
+    assert(!strcmp(LYD_NAME(ctx_node), "parent-reference") &&
+            !strcmp(ctx_node->schema->module->name, "ietf-yang-schema-mount"));
+
+    /* get all the prefix mappings */
+    if ((ret = lyd_find_xpath(ctx_node, "../../../namespace", &set))) {
+        goto cleanup;
+    }
+
+    for (i = 0; i < set->count; ++i) {
+        assert(!strcmp(LYD_NAME(lyd_child(set->dnodes[i])), "prefix"));
+        pref = lyd_get_value(lyd_child(set->dnodes[i]));
+
+        if (!lyd_child(set->dnodes[i])->next) {
+            /* missing URI - invalid mapping, skip */
+            continue;
+        }
+        assert(!strcmp(LYD_NAME(lyd_child(set->dnodes[i])->next), "uri"));
+        uri = lyd_get_value(lyd_child(set->dnodes[i])->next);
+
+        /* create new ns */
+        ns = calloc(1, sizeof *ns);
+        if (!ns) {
+            ret = LY_EMEM;
+            goto cleanup;
+        }
+        ns->prefix = strdup(pref);
+        ns->uri = strdup(uri);
+        if (!ns->prefix || !ns->uri) {
+            free(ns->prefix);
+            free(ns->uri);
+            free(ns);
+            ret = LY_EMEM;
+            goto cleanup;
+        }
+        ns->depth = 1;
+
+        /* add into the XML namespace set */
+        if ((ret = ly_set_add(val->prefix_data, ns, 1, NULL))) {
+            free(ns->prefix);
+            free(ns->uri);
+            free(ns);
+            goto cleanup;
+        }
+    }
+
+cleanup:
+    ly_set_free(set, NULL);
+    if (ret == LY_EMEM) {
+        ly_err_new(err, LY_EMEM, LYVE_DATA, NULL, NULL, LY_EMEM_MSG);
+    } else if (ret) {
+        ly_err_new(err, ret, LYVE_DATA, NULL, NULL, "%s", ly_errmsg(LYD_CTX(ctx_node)));
     }
     return ret;
 }
@@ -347,7 +441,9 @@
 
     LYD_VALUE_GET(value, val);
 
-    if ((format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) || (format == LY_VALUE_LYB)) {
+    /* LY_VALUE_STR_NS should never be transformed */
+    if ((val->format == LY_VALUE_STR_NS) || (format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) ||
+            (format == LY_VALUE_LYB)) {
         /* canonical */
         if (dynamic) {
             *dynamic = 0;
@@ -437,7 +533,7 @@
 
         .plugin.id = "libyang 2 - xpath1.0, version 1",
         .plugin.store = lyplg_type_store_xpath10,
-        .plugin.validate = NULL,
+        .plugin.validate = lyplg_type_validate_xpath10,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.sort = NULL,
         .plugin.print = lyplg_type_print_xpath10,
diff --git a/src/schema_compile_node.c b/src/schema_compile_node.c
index 4523e84..3f61230 100644
--- a/src/schema_compile_node.c
+++ b/src/schema_compile_node.c
@@ -1917,29 +1917,6 @@
     return ret;
 }
 
-/**
- * @brief Find the correct plugin implementing the described type
- *
- * @param[in] mod Module where the type is defined
- * @param[in] name Name of the type (typedef)
- * @param[in] basetype Type's basetype (when the built-in base plugin is supposed to be used)
- * @return Pointer to the plugin implementing the described data type.
- */
-static struct lyplg_type *
-lys_compile_type_get_plugin(struct lys_module *mod, const char *name, LY_DATA_TYPE basetype)
-{
-    struct lyplg_type *p;
-
-    /* try to find loaded user type plugins */
-    p = lyplg_find(LYPLG_TYPE, mod->name, mod->revision, name);
-    if (!p) {
-        /* use the internal built-in type implementation */
-        p = lyplg_find(LYPLG_TYPE, "", NULL, ly_data_type2str[basetype]);
-    }
-
-    return p;
-}
-
 LY_ERR
 lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags, const char *context_name,
         struct lysp_type *type_p, struct lysc_type **type, const char **units, struct lysp_qname **dflt)
@@ -2121,8 +2098,13 @@
             continue;
         }
 
-        /* get plugin for the specific typedef */
-        plugin = lys_compile_type_get_plugin(tctx->tpdf->type.pmod->mod, tctx->tpdf->name, basetype);
+        /* try to find loaded user type plugins */
+        plugin = lyplg_find(LYPLG_TYPE, tctx->tpdf->type.pmod->mod->name, tctx->tpdf->type.pmod->mod->revision,
+                tctx->tpdf->name);
+        if (!plugin) {
+            /* use the internal built-in type implementation */
+            plugin = lyplg_find(LYPLG_TYPE, "", NULL, ly_data_type2str[basetype]);
+        }
         assert(plugin);
 
         if ((basetype != LY_TYPE_LEAFREF) && (u != tpdf_chain.count - 1) && !(tctx->tpdf->type.flags) &&
@@ -3048,6 +3030,7 @@
                 break;
             case LY_VALUE_CANON:
             case LY_VALUE_XML:
+            case LY_VALUE_STR_NS:
                 /* not really defined */
                 LOGINT_RET(ctx->ctx);
             }
diff --git a/src/tree.h b/src/tree.h
index 1c283b7..72ce5e2 100644
--- a/src/tree.h
+++ b/src/tree.h
@@ -238,7 +238,8 @@
     LY_VALUE_SCHEMA_RESOLVED, /**< resolved YANG schema value, prefixes map to module structures directly */
     LY_VALUE_XML,             /**< XML data value, prefixes map to XML namespace prefixes */
     LY_VALUE_JSON,            /**< JSON data value, prefixes map to module names */
-    LY_VALUE_LYB              /**< LYB data binary value, prefix mapping is type-specific (but usually like JSON) */
+    LY_VALUE_LYB,             /**< LYB data binary value, prefix mapping is type-specific (but usually like JSON) */
+    LY_VALUE_STR_NS           /**< any data format value, prefixes map to XML namespace prefixes */
 } LY_VALUE_FORMAT;
 
 /** @} trees */
diff --git a/src/tree_data.c b/src/tree_data.c
index ab4c495..893bdd0 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -346,6 +346,7 @@
     struct ly_set parsed = {0};
     struct lyd_node *first;
     uint32_t i;
+    ly_bool subtree_sibling = 0;
 
     assert(ctx && (parent || first_p));
 
@@ -360,13 +361,16 @@
     /* parse the data */
     switch (format) {
     case LYD_XML:
-        rc = lyd_parse_xml(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, NULL, &parsed, &lydctx);
+        rc = lyd_parse_xml(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, NULL, &parsed,
+                &subtree_sibling, &lydctx);
         break;
     case LYD_JSON:
-        rc = lyd_parse_json(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed, &lydctx);
+        rc = lyd_parse_json(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed,
+                &subtree_sibling, &lydctx);
         break;
     case LYD_LYB:
-        rc = lyd_parse_lyb(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed, &lydctx);
+        rc = lyd_parse_lyb(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed,
+                &subtree_sibling, &lydctx);
         break;
     case LYD_UNKNOWN:
         LOGARG(ctx, format);
@@ -384,8 +388,8 @@
 
     if (!(parse_opts & LYD_PARSE_ONLY)) {
         /* validate data */
-        rc = lyd_validate(first_p, NULL, ctx, val_opts, 0, &lydctx->node_when, &lydctx->node_exts, &lydctx->node_types,
-                &lydctx->meta_types, NULL);
+        rc = lyd_validate(first_p, NULL, ctx, val_opts, 0, &lydctx->node_when, &lydctx->node_types, &lydctx->meta_types,
+                &lydctx->ext_val, NULL);
         LY_CHECK_GOTO(rc, cleanup);
     }
 
@@ -409,6 +413,8 @@
             lyd_free_all(*first_p);
             *first_p = NULL;
         }
+    } else if (subtree_sibling) {
+        rc = LY_ENOT;
     }
     ly_set_erase(&parsed, NULL);
     return rc;
@@ -558,7 +564,7 @@
     /* parse the data */
     switch (format) {
     case LYD_XML:
-        rc = lyd_parse_xml(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &envp, &parsed, &lydctx);
+        rc = lyd_parse_xml(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &envp, &parsed, NULL, &lydctx);
         if (rc && envp) {
             /* special situation when the envelopes were parsed successfully */
             if (tree) {
@@ -569,10 +575,10 @@
         }
         break;
     case LYD_JSON:
-        rc = lyd_parse_json(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &parsed, &lydctx);
+        rc = lyd_parse_json(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &parsed, NULL, &lydctx);
         break;
     case LYD_LYB:
-        rc = lyd_parse_lyb(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &parsed, &lydctx);
+        rc = lyd_parse_lyb(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &parsed, NULL, &lydctx);
         break;
     case LYD_UNKNOWN:
         LOGARG(ctx, format);
@@ -1310,7 +1316,7 @@
     }
 
     return lyd_create_meta(parent, meta, module, name, name_len, val_str, strlen(val_str), NULL, LY_VALUE_JSON,
-            NULL, LYD_HINT_DATA, clear_dflt, NULL);
+            NULL, LYD_HINT_DATA, parent ? parent->schema : NULL, clear_dflt, NULL);
 }
 
 LIBYANG_API_DEF LY_ERR
@@ -1350,7 +1356,7 @@
     }
 
     return lyd_create_meta(parent, meta, mod, attr->name.name, strlen(attr->name.name), attr->value, strlen(attr->value),
-            NULL, attr->format, attr->val_prefix_data, attr->hints, clear_dflt, NULL);
+            NULL, attr->format, attr->val_prefix_data, attr->hints, parent ? parent->schema : NULL, clear_dflt, NULL);
 }
 
 LIBYANG_API_DEF LY_ERR
@@ -1635,8 +1641,9 @@
     }
 
     /* parse the new value into a new meta structure */
-    LY_CHECK_GOTO(ret = lyd_create_meta(NULL, &m2, meta->annotation->module, meta->name, strlen(meta->name), val_str,
-            strlen(val_str), NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, 0, NULL), cleanup);
+    ret = lyd_create_meta(NULL, &m2, meta->annotation->module, meta->name, strlen(meta->name), val_str, strlen(val_str),
+            NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, meta->parent ? meta->parent->schema : NULL, 0, NULL);
+    LY_CHECK_GOTO(ret, cleanup);
 
     /* compare original and new value */
     if (lyd_compare_meta(meta, m2)) {
@@ -2089,8 +2096,8 @@
 
 LY_ERR
 lyd_new_implicit_r(struct lyd_node *parent, struct lyd_node **first, const struct lysc_node *sparent,
-        const struct lys_module *mod, struct ly_set *node_when, struct ly_set *node_exts, struct ly_set *node_types,
-        uint32_t impl_opts, struct lyd_node **diff)
+        const struct lys_module *mod, struct ly_set *node_when, struct ly_set *node_types, uint32_t impl_opts,
+        struct lyd_node **diff)
 {
     LY_ERR ret;
     const struct lysc_node *iter = NULL;
@@ -2123,11 +2130,11 @@
             if (!node && ((struct lysc_node_choice *)iter)->dflt) {
                 /* create default case data */
                 LY_CHECK_RET(lyd_new_implicit_r(parent, first, &((struct lysc_node_choice *)iter)->dflt->node,
-                        NULL, node_when, node_exts, node_types, impl_opts, diff));
+                        NULL, node_when, node_types, impl_opts, diff));
             } else if (node) {
                 /* create any default data in the existing case */
                 assert(node->schema->parent->nodetype == LYS_CASE);
-                LY_CHECK_RET(lyd_new_implicit_r(parent, first, node->schema->parent, NULL, node_when, node_exts, node_types,
+                LY_CHECK_RET(lyd_new_implicit_r(parent, first, node->schema->parent, NULL, node_when, node_types,
                         impl_opts, diff));
             }
             break;
@@ -2142,17 +2149,13 @@
                     /* remember to resolve when */
                     LY_CHECK_RET(ly_set_add(node_when, node, 1, NULL));
                 }
-                if (node_exts) {
-                    /* remember to call all the extension's validation callbacks */
-                    LY_CHECK_RET(lysc_node_ext_tovalidate(node_exts, node));
-                }
                 if (diff) {
                     /* add into diff */
                     LY_CHECK_RET(lyd_val_diff_add(node, LYD_DIFF_OP_CREATE, diff));
                 }
 
                 /* create any default children */
-                LY_CHECK_RET(lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, node_when, node_exts, node_types,
+                LY_CHECK_RET(lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, node_when, node_types,
                         impl_opts, diff));
             }
             break;
@@ -2176,10 +2179,6 @@
                     /* remember to resolve when */
                     LY_CHECK_RET(ly_set_add(node_when, node, 1, NULL));
                 }
-                if (node_exts) {
-                    /* remember to call all the extension's validation callbacks */
-                    LY_CHECK_RET(lysc_node_ext_tovalidate(node_exts, node));
-                }
                 if (diff) {
                     /* add into diff */
                     LY_CHECK_RET(lyd_val_diff_add(node, LYD_DIFF_OP_CREATE, diff));
@@ -2208,10 +2207,6 @@
                         /* remember to resolve when */
                         LY_CHECK_RET(ly_set_add(node_when, node, 1, NULL));
                     }
-                    if (node_exts) {
-                        /* remember to call all the extension's validation callbacks */
-                        LY_CHECK_RET(lysc_node_ext_tovalidate(node_exts, node));
-                    }
                     if (diff) {
                         /* add into diff */
                         LY_CHECK_RET(lyd_val_diff_add(node, LYD_DIFF_OP_CREATE, diff));
@@ -2233,7 +2228,7 @@
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyd_node *node;
-    struct ly_set node_when = {0}, node_exts = {0};
+    struct ly_set node_when = {0};
 
     LY_CHECK_ARG_RET(NULL, tree, LY_EINVAL);
     if (diff) {
@@ -2244,20 +2239,18 @@
         /* skip added default nodes */
         if (((node->flags & (LYD_DEFAULT | LYD_NEW)) != (LYD_DEFAULT | LYD_NEW)) &&
                 (node->schema->nodetype & LYD_NODE_INNER)) {
-            LY_CHECK_GOTO(ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &node_when, &node_exts,
-                    NULL, implicit_options, diff), cleanup);
+            LY_CHECK_GOTO(ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &node_when, NULL,
+                    implicit_options, diff), cleanup);
         }
 
         LYD_TREE_DFS_END(tree, node);
     }
 
     /* resolve when and remove any invalid defaults */
-    LY_CHECK_GOTO(ret = lyd_validate_unres(&tree, NULL, &node_when, LYXP_IGNORE_WHEN, &node_exts, NULL, NULL, diff),
-            cleanup);
+    LY_CHECK_GOTO(ret = lyd_validate_unres(&tree, NULL, &node_when, LYXP_IGNORE_WHEN, NULL, NULL, NULL, 0, diff), cleanup);
 
 cleanup:
     ly_set_erase(&node_when, NULL);
-    ly_set_erase(&node_exts, NULL);
     if (ret && diff) {
         lyd_free_all(*diff);
         *diff = NULL;
@@ -2311,7 +2304,7 @@
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyd_node *root, *d = NULL;
-    struct ly_set node_when = {0}, node_exts = {0};
+    struct ly_set node_when = {0};
 
     LY_CHECK_ARG_RET(NULL, tree, module, LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(*tree ? LYD_CTX(*tree) : NULL, module ? module->ctx : NULL, LY_EINVAL);
@@ -2320,10 +2313,10 @@
     }
 
     /* add all top-level defaults for this module */
-    LY_CHECK_GOTO(ret = lyd_new_implicit_r(NULL, tree, NULL, module, &node_when, &node_exts, NULL, implicit_options, diff), cleanup);
+    LY_CHECK_GOTO(ret = lyd_new_implicit_r(NULL, tree, NULL, module, &node_when, NULL, implicit_options, diff), cleanup);
 
     /* resolve when and remove any invalid defaults */
-    LY_CHECK_GOTO(ret = lyd_validate_unres(tree, module, &node_when, LYXP_IGNORE_WHEN, &node_exts, NULL, NULL, diff),
+    LY_CHECK_GOTO(ret = lyd_validate_unres(tree, module, &node_when, LYXP_IGNORE_WHEN, NULL, NULL, NULL, 0, diff),
             cleanup);
 
     /* process nested nodes */
@@ -2343,7 +2336,6 @@
 
 cleanup:
     ly_set_erase(&node_when, NULL);
-    ly_set_erase(&node_exts, NULL);
     if (ret && diff) {
         lyd_free_all(*diff);
         *diff = NULL;
@@ -2682,7 +2674,7 @@
     LY_CHECK_RET(lyd_insert_check_schema(parent->schema, NULL, node->schema));
 
     if (node->schema && (node->schema->flags & LYS_KEY)) {
-        LOGERR(parent->schema->module->ctx, LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
+        LOGERR(LYD_CTX(parent), LY_EINVAL, "Cannot insert key \"%s\".", node->schema->name);
         return LY_EINVAL;
     }
 
@@ -2700,6 +2692,28 @@
 }
 
 LIBYANG_API_DEF LY_ERR
+lyd_insert_ext(struct lyd_node *parent, struct lyd_node *first)
+{
+    struct lyd_node *iter;
+
+    LY_CHECK_ARG_RET(NULL, parent, first, !first->parent, !first->prev->next,
+            !parent->schema || (parent->schema->nodetype & LYD_NODE_INNER), LY_EINVAL);
+
+    if (first->schema && (first->schema->flags & LYS_KEY)) {
+        LOGERR(LYD_CTX(parent), LY_EINVAL, "Cannot insert key \"%s\".", first->schema->name);
+        return LY_EINVAL;
+    }
+
+    while (first) {
+        iter = first->next;
+        lyd_unlink_tree(first);
+        lyd_insert_node(parent, NULL, first, 0);
+        first = iter;
+    }
+    return LY_SUCCESS;
+}
+
+LIBYANG_API_DEF LY_ERR
 lyd_insert_sibling(struct lyd_node *sibling, struct lyd_node *node, struct lyd_node **first)
 {
     struct lyd_node *iter;
@@ -2886,7 +2900,7 @@
 LY_ERR
 lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod, const char *name,
         size_t name_len, const char *value, size_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format,
-        void *prefix_data, uint32_t hints, ly_bool clear_dflt, ly_bool *incomplete)
+        void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, ly_bool clear_dflt, ly_bool *incomplete)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lysc_ext_instance *ant = NULL;
@@ -2896,7 +2910,7 @@
 
     assert((parent || meta) && mod);
 
-    LOG_LOCSET(parent ? parent->schema : NULL, parent, NULL, NULL);
+    LOG_LOCSET(ctx_node, parent, NULL, NULL);
 
     LY_ARRAY_FOR(mod->compiled->exts, u) {
         if ((mod->compiled->exts[u].def->plugin == lyplg_find(LYPLG_EXTENSION, LYEXT_PLUGIN_INTERNAL_ANNOTATION)) &&
@@ -2920,7 +2934,7 @@
     mt->annotation = ant;
     ant_type = ant->substmts[ANNOTATION_SUBSTMT_TYPE].storage;
     ret = lyd_value_store(mod->ctx, &mt->value, *ant_type, value, value_len, dynamic, format, prefix_data, hints,
-            parent ? parent->schema : NULL, incomplete);
+            ctx_node, incomplete);
     LY_CHECK_ERR_GOTO(ret, free(mt), cleanup);
     ret = lydict_insert(mod->ctx, name, name_len, &mt->name);
     LY_CHECK_ERR_GOTO(ret, free(mt), cleanup);
@@ -2938,7 +2952,7 @@
     }
 
 cleanup:
-    LOG_LOCBACK((parent && parent->schema) ? 1 : 0, parent ? 1 : 0, 0, 0);
+    LOG_LOCBACK(ctx_node ? 1 : 0, parent ? 1 : 0, 0, 0);
     return ret;
 }
 
@@ -3396,34 +3410,88 @@
 }
 
 /**
+ * @brief Find @p schema equivalent in @p trg_ctx.
+ *
+ * @param[in] schema Schema node to find.
+ * @param[in] trg_ctx Target context to search in.
+ * @param[in] parent Data parent of @p schema, if any.
+ * @param[out] trg_schema Found schema from @p trg_ctx to use.
+ * @return LY_RRR value.
+ */
+static LY_ERR
+lyd_dup_find_schema(const struct lysc_node *schema, const struct ly_ctx *trg_ctx, struct lyd_node *parent,
+        const struct lysc_node **trg_schema)
+{
+    const struct lysc_node *node = NULL, *sparent = NULL;
+    const struct lys_module *mod = NULL;
+    char *path;
+
+    if (!schema) {
+        /* opaque node */
+        *trg_schema = NULL;
+        return LY_SUCCESS;
+    }
+
+    if (parent && parent->schema) {
+        /* start from schema parent */
+        sparent = parent->schema;
+    } else {
+        /* start from module */
+        mod = ly_ctx_get_module_implemented(trg_ctx, schema->module->name);
+        if (!mod) {
+            LOGERR(trg_ctx, LY_ENOTFOUND, "Module \"%s\" not present/implemented in the target context.",
+                    schema->module->name);
+            return LY_ENOTFOUND;
+        }
+    }
+
+    /* find the schema node */
+    while ((node = lys_getnext(node, sparent, mod ? mod->compiled : NULL, 0))) {
+        if (!strcmp(node->module->name, schema->module->name) && !strcmp(node->name, schema->name)) {
+            *trg_schema = node;
+            return LY_SUCCESS;
+        }
+    }
+
+    /* schema node not found */
+    path = lysc_path(schema, LYSC_PATH_LOG, NULL, 0);
+    LOGERR(trg_ctx, LY_ENOTFOUND, "Schema node \"%s\" not found in the target context.", path);
+    free(path);
+    return LY_ENOTFOUND;
+}
+
+/**
  * @brief Duplicate a single node and connect it into @p parent (if present) or last of @p first siblings.
  *
- * Ignores LYD_DUP_WITH_PARENTS and LYD_DUP_WITH_SIBLINGS which are supposed to be handled by lyd_dup().
+ * Ignores ::LYD_DUP_WITH_PARENTS and ::LYD_DUP_WITH_SIBLINGS which are supposed to be handled by lyd_dup().
  *
- * @param[in] node Original node to duplicate
+ * @param[in] node Node to duplicate.
+ * @param[in] trg_ctx Target context for duplicated nodes.
  * @param[in] parent Parent to insert into, NULL for top-level sibling.
  * @param[in] insert_last Whether the duplicated node can be inserted as the last child of @p parent. Set for
  * recursive duplication as an optimization.
  * @param[in,out] first First sibling, NULL if no top-level sibling exist yet. Can be also NULL if @p parent is set.
  * @param[in] options Bitmask of options flags, see @ref dupoptions.
- * @param[out] dup_p Pointer where the created duplicated node is placed (besides connecting it int @p parent / @p first sibling).
- * @return LY_ERR value
+ * @param[out] dup_p Pointer where the created duplicated node is placed (besides connecting it to @p parent / @p first).
+ * @return LY_ERR value.
  */
 static LY_ERR
-lyd_dup_r(const struct lyd_node *node, struct lyd_node *parent, ly_bool insert_last, struct lyd_node **first,
-        uint32_t options, struct lyd_node **dup_p)
+lyd_dup_r(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node *parent, ly_bool insert_last,
+        struct lyd_node **first, uint32_t options, struct lyd_node **dup_p)
 {
     LY_ERR ret;
     struct lyd_node *dup = NULL;
     struct lyd_meta *meta;
     struct lyd_attr *attr;
     struct lyd_node_any *any;
+    const struct lysc_type *type;
+    const char *val_can;
 
     LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
 
     if (!node->schema) {
         dup = calloc(1, sizeof(struct lyd_node_opaq));
-        ((struct lyd_node_opaq *)dup)->ctx = LYD_CTX(node);
+        ((struct lyd_node_opaq *)dup)->ctx = trg_ctx;
     } else {
         switch (node->schema->nodetype) {
         case LYS_RPC:
@@ -3442,19 +3510,23 @@
             dup = calloc(1, sizeof(struct lyd_node_any));
             break;
         default:
-            LOGINT(LYD_CTX(node));
+            LOGINT(trg_ctx);
             ret = LY_EINT;
             goto error;
         }
     }
-    LY_CHECK_ERR_GOTO(!dup, LOGMEM(LYD_CTX(node)); ret = LY_EMEM, error);
+    LY_CHECK_ERR_GOTO(!dup, LOGMEM(trg_ctx); ret = LY_EMEM, error);
 
     if (options & LYD_DUP_WITH_FLAGS) {
         dup->flags = node->flags;
     } else {
         dup->flags = (node->flags & LYD_DEFAULT) | LYD_NEW;
     }
-    dup->schema = node->schema;
+    if (trg_ctx == LYD_CTX(node)) {
+        dup->schema = node->schema;
+    } else {
+        LY_CHECK_GOTO(ret = lyd_dup_find_schema(node->schema, trg_ctx, parent, &dup->schema), error);
+    }
     dup->prev = dup;
 
     /* duplicate metadata/attributes */
@@ -3479,17 +3551,17 @@
         if (options & LYD_DUP_RECURSIVE) {
             /* duplicate all the children */
             LY_LIST_FOR(orig->child, child) {
-                LY_CHECK_GOTO(ret = lyd_dup_r(child, dup, 1, NULL, options, NULL), error);
+                LY_CHECK_GOTO(ret = lyd_dup_r(child, trg_ctx, dup, 1, NULL, options, NULL), error);
             }
         }
-        LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), orig->name.name, 0, &opaq->name.name), error);
-        LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), orig->name.prefix, 0, &opaq->name.prefix), error);
-        LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), orig->name.module_ns, 0, &opaq->name.module_ns), error);
-        LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), orig->value, 0, &opaq->value), error);
+        LY_CHECK_GOTO(ret = lydict_insert(trg_ctx, orig->name.name, 0, &opaq->name.name), error);
+        LY_CHECK_GOTO(ret = lydict_insert(trg_ctx, orig->name.prefix, 0, &opaq->name.prefix), error);
+        LY_CHECK_GOTO(ret = lydict_insert(trg_ctx, orig->name.module_ns, 0, &opaq->name.module_ns), error);
+        LY_CHECK_GOTO(ret = lydict_insert(trg_ctx, orig->value, 0, &opaq->value), error);
         opaq->hints = orig->hints;
         opaq->format = orig->format;
         if (orig->val_prefix_data) {
-            ret = ly_dup_prefix_data(LYD_CTX(node), opaq->format, orig->val_prefix_data, &opaq->val_prefix_data);
+            ret = ly_dup_prefix_data(trg_ctx, opaq->format, orig->val_prefix_data, &opaq->val_prefix_data);
             LY_CHECK_GOTO(ret, error);
         }
     } else if (dup->schema->nodetype & LYD_NODE_TERM) {
@@ -3497,8 +3569,17 @@
         struct lyd_node_term *orig = (struct lyd_node_term *)node;
 
         term->hash = orig->hash;
-        LY_CHECK_ERR_GOTO(orig->value.realtype->plugin->duplicate(LYD_CTX(node), &orig->value, &term->value),
-                LOGERR(LYD_CTX(node), LY_EINT, "Value duplication failed."); ret = LY_EINT, error);
+        if (trg_ctx == LYD_CTX(node)) {
+            ret = orig->value.realtype->plugin->duplicate(trg_ctx, &orig->value, &term->value);
+            LY_CHECK_ERR_GOTO(ret, LOGERR(trg_ctx, ret, "Value duplication failed."), error);
+        } else {
+            /* store canonical value in the target context */
+            val_can = lyd_get_value(node);
+            type = ((struct lysc_node_leaf *)term->schema)->type;
+            ret = lyd_value_store(trg_ctx, &term->value, type, val_can, strlen(val_can), NULL, LY_VALUE_CANON, NULL,
+                    LYD_HINT_DATA, term->schema, NULL);
+            LY_CHECK_GOTO(ret, error);
+        }
     } else if (dup->schema->nodetype & LYD_NODE_INNER) {
         struct lyd_node_inner *orig = (struct lyd_node_inner *)node;
         struct lyd_node *child;
@@ -3506,7 +3587,7 @@
         if (options & LYD_DUP_RECURSIVE) {
             /* duplicate all the children */
             LY_LIST_FOR(orig->child, child) {
-                LY_CHECK_GOTO(ret = lyd_dup_r(child, dup, 1, NULL, options, NULL), error);
+                LY_CHECK_GOTO(ret = lyd_dup_r(child, trg_ctx, dup, 1, NULL, options, NULL), error);
             }
         } else if ((dup->schema->nodetype == LYS_LIST) && !(dup->schema->flags & LYS_KEYLESS)) {
             /* always duplicate keys of a list */
@@ -3522,7 +3603,7 @@
                      * but there can be also some non-key nodes */
                     continue;
                 }
-                LY_CHECK_GOTO(ret = lyd_dup_r(child, dup, 1, NULL, options, NULL), error);
+                LY_CHECK_GOTO(ret = lyd_dup_r(child, trg_ctx, dup, 1, NULL, options, NULL), error);
                 child = child->next;
             }
         }
@@ -3550,6 +3631,7 @@
  * @brief Get a parent node to connect duplicated subtree to.
  *
  * @param[in] node Node (subtree) to duplicate.
+ * @param[in] trg_ctx Target context for duplicated nodes.
  * @param[in] parent Initial parent to connect to.
  * @param[in] options Bitmask of options flags, see @ref dupoptions.
  * @param[out] dup_parent First duplicated parent node, if any.
@@ -3557,8 +3639,8 @@
  * @return LY_ERR value.
  */
 static LY_ERR
-lyd_dup_get_local_parent(const struct lyd_node *node, const struct lyd_node_inner *parent, uint32_t options,
-        struct lyd_node **dup_parent, struct lyd_node_inner **local_parent)
+lyd_dup_get_local_parent(const struct lyd_node *node, const struct ly_ctx *trg_ctx, const struct lyd_node_inner *parent,
+        uint32_t options, struct lyd_node **dup_parent, struct lyd_node_inner **local_parent)
 {
     const struct lyd_node_inner *orig_parent, *iter;
     ly_bool repeat = 1;
@@ -3573,7 +3655,7 @@
             repeat = 0;
         } else {
             iter = NULL;
-            LY_CHECK_RET(lyd_dup_r((struct lyd_node *)orig_parent, NULL, 0, (struct lyd_node **)&iter, options,
+            LY_CHECK_RET(lyd_dup_r((struct lyd_node *)orig_parent, trg_ctx, NULL, 0, (struct lyd_node **)&iter, options,
                     (struct lyd_node **)&iter));
         }
         if (!*local_parent) {
@@ -3598,7 +3680,7 @@
 
     if (repeat && parent) {
         /* given parent and created parents chain actually do not interconnect */
-        LOGERR(LYD_CTX(node), LY_EINVAL,
+        LOGERR(trg_ctx, LY_EINVAL,
                 "Invalid argument parent (%s()) - does not interconnect with the created node's parents chain.", __func__);
         return LY_EINVAL;
     }
@@ -3607,8 +3689,8 @@
 }
 
 static LY_ERR
-lyd_dup(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t options, ly_bool nosiblings,
-        struct lyd_node **dup)
+lyd_dup(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node_inner *parent, uint32_t options,
+        ly_bool nosiblings, struct lyd_node **dup)
 {
     LY_ERR rc;
     const struct lyd_node *orig;          /* original node to be duplicated */
@@ -3616,10 +3698,10 @@
     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) */
 
-    LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
+    assert(node && trg_ctx && (!parent || (LYD_CTX(parent) == trg_ctx)));
 
     if (options & LYD_DUP_WITH_PARENTS) {
-        LY_CHECK_GOTO(rc = lyd_dup_get_local_parent(node, parent, options & (LYD_DUP_WITH_FLAGS | LYD_DUP_NO_META),
+        LY_CHECK_GOTO(rc = lyd_dup_get_local_parent(node, trg_ctx, parent, options & (LYD_DUP_WITH_FLAGS | LYD_DUP_NO_META),
                 &top, &local_parent), error);
     } else {
         local_parent = parent;
@@ -3630,16 +3712,17 @@
             if (local_parent) {
                 /* the key must already exist in the parent */
                 rc = lyd_find_sibling_schema(local_parent->child, orig->schema, first ? NULL : &first);
-                LY_CHECK_ERR_GOTO(rc, LOGINT(LYD_CTX(node)), error);
+                LY_CHECK_ERR_GOTO(rc, LOGINT(trg_ctx), error);
             } else {
                 assert(!(options & LYD_DUP_WITH_PARENTS));
                 /* duplicating a single key, okay, I suppose... */
-                rc = lyd_dup_r(orig, NULL, 0, &first, options, first ? NULL : &first);
+                rc = lyd_dup_r(orig, trg_ctx, NULL, 0, &first, options, first ? NULL : &first);
                 LY_CHECK_GOTO(rc, error);
             }
         } else {
             /* if there is no local parent, it will be inserted into first */
-            rc = lyd_dup_r(orig, local_parent ? &local_parent->node : NULL, 0, &first, options, first ? NULL : &first);
+            rc = lyd_dup_r(orig, trg_ctx, local_parent ? &local_parent->node : NULL, 0, &first, options,
+                    first ? NULL : &first);
             LY_CHECK_GOTO(rc, error);
         }
         if (nosiblings) {
@@ -3664,13 +3747,43 @@
 LIBYANG_API_DEF LY_ERR
 lyd_dup_single(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t options, struct lyd_node **dup)
 {
-    return lyd_dup(node, parent, options, 1, dup);
+    LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
+    if (node && parent && (LYD_CTX(node) != LYD_CTX(parent))) {
+        LOGERR(NULL, LY_EINVAL, "Different contexts used in node duplication.");
+        return LY_EINVAL;
+    }
+
+    return lyd_dup(node, LYD_CTX(node), parent, options, 1, dup);
+}
+
+LIBYANG_API_DEF LY_ERR
+lyd_dup_single_to_ctx(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node_inner *parent,
+        uint32_t options, struct lyd_node **dup)
+{
+    LY_CHECK_ARG_RET(trg_ctx, node, trg_ctx, LY_EINVAL);
+
+    return lyd_dup(node, trg_ctx, parent, options, 1, dup);
 }
 
 LIBYANG_API_DEF LY_ERR
 lyd_dup_siblings(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t options, struct lyd_node **dup)
 {
-    return lyd_dup(node, parent, options, 0, dup);
+    LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
+    if (node && parent && (LYD_CTX(node) != LYD_CTX(parent))) {
+        LOGERR(NULL, LY_EINVAL, "Different contexts used in node duplication.");
+        return LY_EINVAL;
+    }
+
+    return lyd_dup(node, LYD_CTX(node), parent, options, 0, dup);
+}
+
+LIBYANG_API_DEF LY_ERR
+lyd_dup_siblings_to_ctx(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node_inner *parent,
+        uint32_t options, struct lyd_node **dup)
+{
+    LY_CHECK_ARG_RET(trg_ctx, node, trg_ctx, LY_EINVAL);
+
+    return lyd_dup(node, trg_ctx, parent, options, 0, dup);
 }
 
 LIBYANG_API_DEF LY_ERR
@@ -4461,24 +4574,24 @@
 }
 
 LIBYANG_API_DEF LY_ERR
-lyd_find_xpath3(const struct lyd_node *ctx_node, const struct lyd_node *tree, const char *xpath,
-        const struct lyxp_var *vars, struct ly_set **set)
+lyd_find_xpath4(const struct lyd_node *ctx_node, const struct lyd_node *tree, const char *xpath, LY_VALUE_FORMAT format,
+        void *prefix_data, const struct lyxp_var *vars, struct ly_set **set)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyxp_set xp_set = {0};
     struct lyxp_expr *exp = NULL;
     uint32_t i;
 
-    LY_CHECK_ARG_RET(NULL, tree, xpath, set, LY_EINVAL);
+    LY_CHECK_ARG_RET(NULL, tree, xpath, format, set, LY_EINVAL);
 
     *set = NULL;
 
-    /* compile expression */
+    /* parse expression */
     ret = lyxp_expr_parse((struct ly_ctx *)LYD_CTX(tree), xpath, 0, 1, &exp);
     LY_CHECK_GOTO(ret, cleanup);
 
     /* evaluate expression */
-    ret = lyxp_eval(LYD_CTX(tree), exp, NULL, LY_VALUE_JSON, NULL, ctx_node, tree, vars, &xp_set, LYXP_IGNORE_WHEN);
+    ret = lyxp_eval(LYD_CTX(tree), exp, NULL, format, prefix_data, ctx_node, tree, vars, &xp_set, LYXP_IGNORE_WHEN);
     LY_CHECK_GOTO(ret, cleanup);
 
     /* allocate return set */
@@ -4511,11 +4624,20 @@
 }
 
 LIBYANG_API_DEF LY_ERR
+lyd_find_xpath3(const struct lyd_node *ctx_node, const struct lyd_node *tree, const char *xpath,
+        const struct lyxp_var *vars, struct ly_set **set)
+{
+    LY_CHECK_ARG_RET(NULL, tree, xpath, set, LY_EINVAL);
+
+    return lyd_find_xpath4(ctx_node, tree, xpath, LY_VALUE_JSON, NULL, vars, set);
+}
+
+LIBYANG_API_DEF LY_ERR
 lyd_find_xpath2(const struct lyd_node *ctx_node, const char *xpath, const struct lyxp_var *vars, struct ly_set **set)
 {
     LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
 
-    return lyd_find_xpath3(ctx_node, ctx_node, xpath, vars, set);
+    return lyd_find_xpath4(ctx_node, ctx_node, xpath, LY_VALUE_JSON, NULL, vars, set);
 }
 
 LIBYANG_API_DEF LY_ERR
@@ -4523,7 +4645,7 @@
 {
     LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
 
-    return lyd_find_xpath3(ctx_node, ctx_node, xpath, NULL, set);
+    return lyd_find_xpath4(ctx_node, ctx_node, xpath, LY_VALUE_JSON, NULL, NULL, set);
 }
 
 LIBYANG_API_DEF LY_ERR
diff --git a/src/tree_data.h b/src/tree_data.h
index 24b9458..65a9bda 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -680,6 +680,16 @@
 };
 
 /**
+ * @brief Special lyd_value structure for ietf-yang-types xpath1.0 values.
+ */
+struct lyd_value_xpath10 {
+    struct lyxp_expr *exp;
+    const struct ly_ctx *ctx;
+    void *prefix_data;
+    LY_VALUE_FORMAT format;
+};
+
+/**
  * @brief Metadata structure.
  *
  * The structure provides information about metadata of a data element. Such attributes must map to
@@ -722,7 +732,7 @@
     struct ly_opaq_name name;       /**< attribute name with module information */
     const char *value;              /**< attribute value */
     uint32_t hints;                 /**< additional information about from the data source, see the [hints list](@ref lydhints) */
-    LY_VALUE_FORMAT format;        /**< format of the attribute and any prefixes, ::LY_VALUE_XML or ::LY_VALUE_JSON */
+    LY_VALUE_FORMAT format;         /**< format of the attribute and any prefixes, ::LY_VALUE_XML or ::LY_VALUE_JSON */
     void *val_prefix_data;          /**< format-specific prefix data */
 };
 
@@ -753,9 +763,10 @@
  *
  */
 
-#define LYD_DEFAULT      0x01        /**< default (implicit) node */
-#define LYD_WHEN_TRUE    0x02        /**< all when conditions of this node were evaluated to true */
-#define LYD_NEW          0x04        /**< node was created after the last validation, is needed for the next validation */
+#define LYD_DEFAULT     0x01        /**< default (implicit) node */
+#define LYD_WHEN_TRUE   0x02        /**< all when conditions of this node were evaluated to true */
+#define LYD_NEW         0x04        /**< node was created after the last validation, is needed for the next validation */
+#define LYD_EXT         0x08        /**< node is the first sibling parsed as extension instance data */
 
 /** @} */
 
@@ -1908,32 +1919,63 @@
 /** @} dupoptions */
 
 /**
- * @brief Create a copy of the specified data tree \p node. Schema references are kept the same.
+ * @brief Create a copy of the specified data tree @p node. 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] parent Optional parent node where to connect the duplicated node(s). If set in combination with
+ * ::LYD_DUP_WITH_PARENTS, the missing parents' chain is duplicated and connected with @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.
+ * node(s) (when ::LYD_DUP_WITH_PARENTS used), the first duplicated node is still returned.
  * @return LY_ERR value.
  */
-LIBYANG_API_DECL LY_ERR lyd_dup_single(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t options, struct lyd_node **dup);
+LIBYANG_API_DECL LY_ERR lyd_dup_single(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t 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.
+ * @brief Create a copy of the specified data tree @p node. Schema references are assigned from @p trg_ctx.
  *
  * @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] trg_ctx Target context for duplicated nodes.
+ * @param[in] parent Optional parent node where to connect the duplicated node(s). If set in combination with
+ * ::LYD_DUP_WITH_PARENTS, the missing parents' chain is duplicated and connected with @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.
+ * node(s) (when ::LYD_DUP_WITH_PARENTS used), the first duplicated node is still returned.
  * @return LY_ERR value.
  */
-LIBYANG_API_DECL LY_ERR lyd_dup_siblings(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t options, struct lyd_node **dup);
+LIBYANG_API_DECL LY_ERR lyd_dup_single_to_ctx(const struct lyd_node *node, const struct ly_ctx *trg_ctx,
+        struct lyd_node_inner *parent, uint32_t 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 missing parents' chain is duplicated and connected with @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.
+ */
+LIBYANG_API_DECL LY_ERR lyd_dup_siblings(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t options,
+        struct lyd_node **dup);
+
+/**
+ * @brief Create a copy of the specified data tree @p node with any following siblings. Schema references are assigned
+ * from @p trg_ctx.
+ *
+ * @param[in] node Data tree node to be duplicated.
+ * @param[in] trg_ctx Target context for duplicated nodes.
+ * @param[in] parent Optional parent node where to connect the duplicated node(s). If set in combination with
+ * ::LYD_DUP_WITH_PARENTS, the missing parents' chain is duplicated and connected with @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.
+ */
+LIBYANG_API_DECL LY_ERR lyd_dup_siblings_to_ctx(const struct lyd_node *node, const struct ly_ctx *trg_ctx,
+        struct lyd_node_inner *parent, uint32_t options, struct lyd_node **dup);
 
 /**
  * @brief Create a copy of the metadata.
@@ -2265,7 +2307,8 @@
  * @return Found metadata,
  * @return NULL if not found.
  */
-LIBYANG_API_DECL struct lyd_meta *lyd_find_meta(const struct lyd_meta *first, const struct lys_module *module, const char *name);
+LIBYANG_API_DECL struct lyd_meta *lyd_find_meta(const struct lyd_meta *first, const struct lys_module *module,
+        const char *name);
 
 /**
  * @brief Search in the given siblings (NOT recursively) for the first target instance with the same value.
@@ -2278,7 +2321,8 @@
  * @return LY_ENOTFOUND if not found, @p match set to NULL.
  * @return LY_ERR value if another error occurred.
  */
-LIBYANG_API_DECL LY_ERR lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match);
+LIBYANG_API_DECL LY_ERR lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target,
+        struct lyd_node **match);
 
 /**
  * @brief Search in the given siblings for the first schema instance.
@@ -2304,8 +2348,8 @@
  * @return LY_EINVAL if @p schema is a key-less list.
  * @return LY_ERR value if another error occurred.
  */
-LIBYANG_API_DECL LY_ERR lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *schema, const char *key_or_value,
-        size_t val_len, struct lyd_node **match);
+LIBYANG_API_DECL LY_ERR lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *schema,
+        const char *key_or_value, size_t val_len, struct lyd_node **match);
 
 /**
  * @brief Search the given siblings for all the exact same instances of a specific node instance. Accepts only nodes
@@ -2318,7 +2362,8 @@
  * @return LY_ENOTFOUND if not found, empty @p set returned.
  * @return LY_ERR value if another error occurred.
  */
-LIBYANG_API_DECL LY_ERR lyd_find_sibling_dup_inst_set(const struct lyd_node *siblings, const struct lyd_node *target, struct ly_set **set);
+LIBYANG_API_DECL LY_ERR lyd_find_sibling_dup_inst_set(const struct lyd_node *siblings, const struct lyd_node *target,
+        struct ly_set **set);
 
 /**
  * @brief Search the given siblings for an opaque node with a specific name.
@@ -2361,7 +2406,7 @@
  * (unless they are defined in top-level). Other predicates can still follow the aforementioned ones.
  *
  * @param[in] ctx_node XPath context node.
- * @param[in] xpath [XPath](@ref howtoXPath) to select.
+ * @param[in] xpath [XPath](@ref howtoXPath) to select in JSON format.
  * @param[out] set Set of found data nodes. In case the result is a number, a string, or a boolean,
  * the returned set is empty.
  * @return LY_SUCCESS on success, @p set is returned.
@@ -2372,10 +2417,10 @@
 /**
  * @brief Search in the given data for instances of nodes matching the provided XPath.
  *
- * It is just lyd_find_xpath() with @p vars added.
+ * It is just ::lyd_find_xpath() with @p vars added.
  *
  * @param[in] ctx_node XPath context node.
- * @param[in] xpath [XPath](@ref howtoXPath) to select.
+ * @param[in] xpath [XPath](@ref howtoXPath) to select in JSON format.
  * @param[in] vars [Sized array](@ref sizedarrays) of XPath variables.
  * @param[out] set Set of found data nodes. In case the result is a number, a string, or a boolean,
  * the returned set is empty.
@@ -2388,11 +2433,11 @@
 /**
  * @brief Search in the given data for instances of nodes matching the provided XPath.
  *
- * It is just lyd_find_xpath2() with @p tree added so that @p ctx_node may be the root.
+ * It is just ::lyd_find_xpath2() with @p tree added so that @p ctx_node may be the root.
  *
  * @param[in] ctx_node XPath context node, NULL for the root node.
  * @param[in] tree Data tree to evaluate on.
- * @param[in] xpath [XPath](@ref howtoXPath) to select.
+ * @param[in] xpath [XPath](@ref howtoXPath) to select in JSON format.
  * @param[in] vars [Sized array](@ref sizedarrays) of XPath variables.
  * @param[out] set Set of found data nodes. In case the result is a number, a string, or a boolean,
  * the returned set is empty.
@@ -2403,6 +2448,25 @@
         const struct lyxp_var *vars, struct ly_set **set);
 
 /**
+ * @brief Search in the given data for instances of nodes matching the provided XPath.
+ *
+ * It is just ::lyd_find_xpath3() with @p format and @p prefix_data added for special use-cases.
+ *
+ * @param[in] ctx_node XPath context node, NULL for the root node.
+ * @param[in] tree Data tree to evaluate on.
+ * @param[in] xpath [XPath](@ref howtoXPath) to select with prefix in @p format.
+ * @param[in] format Format of any prefixes in @p xpath.
+ * @param[in] prefix_data Format-specific prefix data.
+ * @param[in] vars [Sized array](@ref sizedarrays) of XPath variables.
+ * @param[out] set Set of found data nodes. In case the result is a number, a string, or a boolean,
+ * the returned set is empty.
+ * @return LY_SUCCESS on success, @p set is returned.
+ * @return LY_ERR value if an error occurred.
+ */
+LIBYANG_API_DECL LY_ERR lyd_find_xpath4(const struct lyd_node *ctx_node, const struct lyd_node *tree, const char *xpath,
+        LY_VALUE_FORMAT format, void *prefix_data, const struct lyxp_var *vars, struct ly_set **set);
+
+/**
  * @brief Evaluate an XPath on data and return the result converted to boolean.
  *
  * Optimizations similar as in ::lyd_find_xpath().
diff --git a/src/tree_data_helpers.c b/src/tree_data_helpers.c
index 84a6a7a..f1b453d 100644
--- a/src/tree_data_helpers.c
+++ b/src/tree_data_helpers.c
@@ -401,8 +401,7 @@
 }
 
 void
-lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *node_when, struct ly_set *node_exts, struct lyd_meta **meta,
-        uint32_t parse_opts)
+lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *node_when, struct lyd_meta **meta, uint32_t parse_opts)
 {
     struct lyd_meta *meta2, *prev_meta = NULL;
 
@@ -412,7 +411,6 @@
             LY_CHECK_RET(ly_set_add(node_when, node, 1, NULL), );
         }
     }
-    LY_CHECK_RET(lysc_node_ext_tovalidate(node_exts, node), );
 
     LY_LIST_FOR(*meta, meta2) {
         if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults") &&
@@ -634,6 +632,7 @@
 
     switch (format) {
     case LY_VALUE_XML:
+    case LY_VALUE_STR_NS:
         ns_list = prefix_data;
         for (i = 0; i < ns_list->count; ++i) {
             free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
@@ -689,6 +688,7 @@
         }
         break;
     case LY_VALUE_XML:
+    case LY_VALUE_STR_NS:
         /* copy all the namespaces */
         LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
         *prefix_data_p = ns_list;
@@ -775,15 +775,16 @@
         }
         break;
     case LY_VALUE_XML:
+    case LY_VALUE_STR_NS:
         /* copy all referenced namespaces as prefix - namespace pairs */
         if (!*prefix_data_p) {
             /* new prefix data */
             LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
-            *format_p = LY_VALUE_XML;
+            *format_p = format;
             *prefix_data_p = ns_list;
         } else {
             /* reuse prefix data */
-            assert(*format_p == LY_VALUE_XML);
+            assert(*format_p == format);
             ns_list = *prefix_data_p;
         }
 
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index f6d8694..90de1f8 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -129,12 +129,10 @@
  *
  * @param[in] node Node to use.
  * @param[in,out] node_when Set of nodes with unresolved when.
- * @param[in,out] node_exts Set of nodes and their extension instances if they have own validation callback.
  * @param[in,out] meta Node metadata, may be removed from.
  * @param[in] parse_opts Parse options.
  */
-void lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *node_when, struct ly_set *node_exts,
-        struct lyd_meta **meta, uint32_t parse_opts);
+void lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *node_when, struct lyd_meta **meta, uint32_t parse_opts);
 
 /**
  * @brief Get schema node of a data node. Useful especially for opaque nodes.
@@ -316,15 +314,14 @@
  * @param[in] sparent Schema parent of the siblings, NULL if schema of @p parent can be used.
  * @param[in] mod Module of the default values, NULL for nested siblings.
  * @param[in] node_when Optional set to add nodes with "when" conditions into.
- * @param[in] node_exts Optional set to add nodes and extension instances having own validation plugin callback into it.
  * @param[in] node_types Optional set to add nodes with unresolved types into.
  * @param[in] impl_opts Implicit options (@ref implicitoptions).
  * @param[in,out] diff Validation diff.
  * @return LY_ERR value.
  */
 LY_ERR lyd_new_implicit_r(struct lyd_node *parent, struct lyd_node **first, const struct lysc_node *sparent,
-        const struct lys_module *mod, struct ly_set *node_when, struct ly_set *node_exts, struct ly_set *node_types,
-        uint32_t impl_opts, struct lyd_node **diff);
+        const struct lys_module *mod, struct ly_set *node_when, struct ly_set *node_types, uint32_t impl_opts,
+        struct lyd_node **diff);
 
 /**
  * @brief Find the next node, before which to insert the new node.
@@ -369,6 +366,7 @@
  * @param[in] format Input format of @p value.
  * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
  * @param[in] hints [Value hints](@ref lydvalhints) from the parser regarding the value type.
+ * @param[in] ctx_node Value context node, may be NULL for metadata.
  * @param[in] clear_dflt Whether to clear dflt flag starting from @p parent, recursively all NP containers.
  * @param[out] incomplete Whether the value needs to be resolved.
  * @return LY_SUCCESS on success.
@@ -377,7 +375,7 @@
  */
 LY_ERR lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod, const char *name,
         size_t name_len, const char *value, size_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format,
-        void *prefix_data, uint32_t hints, ly_bool clear_dflt, ly_bool *incomplete);
+        void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, ly_bool clear_dflt, ly_bool *incomplete);
 
 /**
  * @brief Insert an attribute (last) into a parent
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 076fa37..0b92e67 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -471,6 +471,7 @@
             }
         }
     }
+
     return NULL;
 }
 
diff --git a/src/validation.c b/src/validation.c
index b2b05bb..5699c8d 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -258,64 +258,31 @@
     return ret;
 }
 
-struct node_ext {
-    struct lyd_node *node;
-    struct lysc_ext_instance *ext;
-};
-
-static LY_ERR
-node_ext_tovalidate_add(struct ly_set *node_exts, struct lysc_ext_instance *exts, struct lyd_node *node)
-{
-    LY_ERR ret = LY_SUCCESS;
-    struct lysc_ext_instance *ext;
-    struct node_ext *rec;
-
-    LY_ARRAY_FOR(exts, struct lysc_ext_instance, ext) {
-        if (ext->def->plugin && ext->def->plugin->validate) {
-            rec = malloc(sizeof *rec);
-            LY_CHECK_ERR_RET(!rec, LOGMEM(LYD_CTX(node)), LY_EMEM);
-            rec->ext = ext;
-            rec->node = node;
-
-            ret = ly_set_add(node_exts, rec, 1, NULL);
-            if (ret) {
-                free(rec);
-                break;
-            }
-        }
-    }
-
-    return ret;
-}
-
-LY_ERR
-lysc_node_ext_tovalidate(struct ly_set *node_exts, struct lyd_node *node)
-{
-    const struct lysc_node *schema = node->schema;
-
-    if (!schema) {
-        /* nothing to do */
-        return LY_SUCCESS;
-    }
-
-    /* node's extensions */
-    LY_CHECK_RET(node_ext_tovalidate_add(node_exts, schema->exts, node));
-
-    if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
-        /* type's extensions */
-        LY_CHECK_RET(node_ext_tovalidate_add(node_exts, ((struct lysc_node_leaf *)schema)->type->exts, node));
-    }
-
-    return LY_SUCCESS;
-}
-
 LY_ERR
 lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, struct ly_set *node_when, uint32_t when_xp_opts,
-        struct ly_set *node_exts, struct ly_set *node_types, struct ly_set *meta_types, struct lyd_node **diff)
+        struct ly_set *node_types, struct ly_set *meta_types, struct ly_set *ext_val, uint32_t val_opts,
+        struct lyd_node **diff)
 {
     LY_ERR ret = LY_SUCCESS;
     uint32_t i;
 
+    if (ext_val && ext_val->count) {
+        /* first validate parsed extension data */
+        i = ext_val->count;
+        do {
+            --i;
+
+            struct lyd_ctx_ext_val *ext_v = ext_val->objs[i];
+
+            /* validate extension data */
+            ret = ext_v->ext->def->plugin->validate(ext_v->ext, ext_v->sibling, val_opts);
+            LY_CHECK_RET(ret);
+
+            /* remove this item from the set */
+            ly_set_rm_index(node_types, i, free);
+        } while (i);
+    }
+
     if (node_when) {
         /* evaluate all when conditions */
         uint32_t prev_count;
@@ -329,23 +296,6 @@
         assert(!node_when->count);
     }
 
-    if (node_exts && node_exts->count) {
-        i = node_exts->count;
-        do {
-            --i;
-
-            struct node_ext *item = node_exts->objs[i];
-
-            LOG_LOCSET(item->node->schema, item->node, NULL, NULL);
-            ret = item->ext->def->plugin->validate(item->ext, item->node);
-            LOG_LOCBACK(item->node->schema ? 1 : 0, 1, 0, 0);
-            LY_CHECK_RET(ret);
-
-            /* remove this node from the set */
-            ly_set_rm_index(node_exts, i, free);
-        } while (i);
-    }
-
     if (node_types && node_types->count) {
         /* finish incompletely validated terminal values (traverse from the end for efficient set removal) */
         i = node_types->count;
@@ -1459,26 +1409,83 @@
 }
 
 /**
+ * @brief Validate extension instance data by storing it in its unres set.
+ *
+ * @param[in] sibling First sibling with ::LYD_EXT flag, all the following ones are expected to have it, too.
+ * @param[in,out] ext_val Set with parsed extension instance data to validate.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyd_validate_nested_ext(struct lyd_node *sibling, struct ly_set *ext_val)
+{
+    struct lyd_node *node;
+    struct lyd_ctx_ext_val *ext_v;
+    struct lysc_ext_instance *nested_exts, *ext = NULL;
+    LY_ARRAY_COUNT_TYPE u;
+
+    /* check of basic assumptions */
+    if (!sibling->parent || !sibling->parent->schema) {
+        LOGINT_RET(LYD_CTX(sibling));
+    }
+    LY_LIST_FOR(sibling, node) {
+        if (!(node->flags & LYD_EXT)) {
+            LOGINT_RET(LYD_CTX(sibling));
+        }
+    }
+
+    /* try to find the extension instance */
+    nested_exts = sibling->parent->schema->exts;
+    LY_ARRAY_FOR(nested_exts, u) {
+        if (nested_exts[u].def->plugin->validate) {
+            if (ext) {
+                /* more extension instances with validate callback */
+                LOGINT_RET(LYD_CTX(sibling));
+            }
+            ext = &nested_exts[u];
+        }
+    }
+    if (!ext) {
+        /* no extension instance with validate callback */
+        LOGINT_RET(LYD_CTX(sibling));
+    }
+
+    /* store for validation */
+    ext_v = malloc(sizeof *ext_v);
+    LY_CHECK_ERR_RET(!ext_v, LOGMEM(LYD_CTX(sibling)), LY_EMEM);
+    ext_v->ext = ext;
+    ext_v->sibling = sibling;
+    LY_CHECK_RET(ly_set_add(ext_val, ext_v, 1, NULL));
+
+    return LY_SUCCESS;
+}
+
+/**
  * @brief Validate the whole data subtree.
  *
  * @param[in] root Subtree root.
  * @param[in,out] node_when Set for nodes with when conditions.
- * @param[in,out] node_exts Set for nodes and extension instances with validation plugin callback.
  * @param[in,out] node_types Set for unres node types.
  * @param[in,out] meta_types Set for unres metadata types.
+ * @param[in,out] ext_val Set for parsed extension data to validate.
  * @param[in] impl_opts Implicit options, see @ref implicitoptions.
  * @param[in,out] diff Validation diff.
  * @return LY_ERR value.
  */
 static LY_ERR
-lyd_validate_subtree(struct lyd_node *root, struct ly_set *node_when, struct ly_set *node_exts, struct ly_set *node_types,
-        struct ly_set *meta_types, uint32_t impl_opts, struct lyd_node **diff)
+lyd_validate_subtree(struct lyd_node *root, struct ly_set *node_when, struct ly_set *node_types,
+        struct ly_set *meta_types, struct ly_set *ext_val, uint32_t impl_opts, struct lyd_node **diff)
 {
     const struct lyd_meta *meta;
     struct lyd_node *node;
 
     LYD_TREE_DFS_BEGIN(root, node) {
+        if (node->flags & LYD_EXT) {
+            /* validate using the extension instance callback */
+            return lyd_validate_nested_ext(node, ext_val);
+        }
+
         if (!node->schema) {
+            /* do not validate opaque nodes */
             goto next_node;
         }
 
@@ -1497,14 +1504,13 @@
             LY_CHECK_RET(lyd_validate_new(lyd_node_child_p(node), node->schema, NULL, diff));
 
             /* add nested defaults */
-            LY_CHECK_RET(lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, NULL, NULL, NULL, impl_opts, diff));
+            LY_CHECK_RET(lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, NULL, NULL, impl_opts, diff));
         }
 
         if (lysc_has_when(node->schema)) {
             /* when evaluation */
             LY_CHECK_RET(ly_set_add(node_when, (void *)node, 1, NULL));
         }
-        LY_CHECK_RET(lysc_node_ext_tovalidate(node_exts, node));
 
 next_node:
         LYD_TREE_DFS_END(root, node);
@@ -1515,24 +1521,24 @@
 
 LY_ERR
 lyd_validate(struct lyd_node **tree, const struct lys_module *module, const struct ly_ctx *ctx, uint32_t val_opts,
-        ly_bool validate_subtree, struct ly_set *node_when_p, struct ly_set *node_exts_p,
-        struct ly_set *node_types_p, struct ly_set *meta_types_p, struct lyd_node **diff)
+        ly_bool validate_subtree, struct ly_set *node_when_p, struct ly_set *node_types_p, struct ly_set *meta_types_p,
+        struct ly_set *ext_val_p, struct lyd_node **diff)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyd_node *first, *next, **first2, *iter;
     const struct lys_module *mod;
-    struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, node_exts = {0};
+    struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, ext_val = {0};
     uint32_t i = 0;
 
     assert(tree && ctx);
-    assert((node_when_p && node_exts_p && node_types_p && meta_types_p) ||
-            (!node_when_p && !node_exts_p && !node_types_p && !meta_types_p));
+    assert((node_when_p && node_types_p && meta_types_p && ext_val_p) ||
+            (!node_when_p && !node_types_p && !meta_types_p && !ext_val_p));
 
     if (!node_when_p) {
         node_when_p = &node_when;
-        node_exts_p = &node_exts;
         node_types_p = &node_types;
         meta_types_p = &meta_types;
+        ext_val_p = &ext_val;
     }
 
     next = *tree;
@@ -1558,7 +1564,7 @@
 
         /* add all top-level defaults for this module, if going to validate subtree, do not add into unres sets
          * (lyd_validate_subtree() adds all the nodes in that case) */
-        ret = lyd_new_implicit_r(NULL, first2, NULL, mod, validate_subtree ? NULL : node_when_p, validate_subtree ? NULL : node_exts_p,
+        ret = lyd_new_implicit_r(NULL, first2, NULL, mod, validate_subtree ? NULL : node_when_p,
                 validate_subtree ? NULL : node_types_p, (val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, diff);
         LY_CHECK_GOTO(ret, cleanup);
 
@@ -1578,14 +1584,14 @@
                     break;
                 }
 
-                ret = lyd_validate_subtree(iter, node_when_p, node_exts_p, node_types_p, meta_types_p,
+                ret = lyd_validate_subtree(iter, node_when_p, node_types_p, meta_types_p, ext_val_p,
                         (val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, diff);
                 LY_CHECK_GOTO(ret, cleanup);
             }
         }
 
         /* finish incompletely validated terminal values/attributes and when conditions */
-        ret = lyd_validate_unres(first2, mod, node_when_p, 0, node_exts_p, node_types_p, meta_types_p, diff);
+        ret = lyd_validate_unres(first2, mod, node_when_p, 0, node_types_p, meta_types_p, ext_val_p, val_opts, diff);
         LY_CHECK_GOTO(ret, cleanup);
 
         /* perform final validation that assumes the data tree is final */
@@ -1595,9 +1601,9 @@
 
 cleanup:
     ly_set_erase(&node_when, NULL);
-    ly_set_erase(&node_exts, NULL);
     ly_set_erase(&node_types, NULL);
     ly_set_erase(&meta_types, NULL);
+    ly_set_erase(&ext_val, free);
     return ret;
 }
 
@@ -1700,31 +1706,31 @@
  * @param[in] int_opts Internal parser options.
  * @param[in] validate_subtree Whether subtree was already validated (as part of data parsing) or not (separate validation).
  * @param[in] node_when_p Set of nodes with when conditions, if NULL a local set is used.
- * @param[in] node_exts Set of nodes with extension instances with validation plugin callback, if NULL a local set is used.
  * @param[in] node_types_p Set of unres node types, if NULL a local set is used.
  * @param[in] meta_types_p Set of unres metadata types, if NULL a local set is used.
+ * @param[in] ext_val_p Set of parsed extension data to validate, if NULL a local set is used.
  * @param[out] diff Optional diff with any changes made by the validation.
  * @return LY_SUCCESS on success.
  * @return LY_ERR error on error.
  */
 static LY_ERR
 _lyd_validate_op(struct lyd_node *op_tree, struct lyd_node *op_node, const struct lyd_node *dep_tree,
-        uint32_t int_opts, ly_bool validate_subtree, struct ly_set *node_when_p, struct ly_set *node_exts_p,
-        struct ly_set *node_types_p, struct ly_set *meta_types_p, struct lyd_node **diff)
+        uint32_t int_opts, ly_bool validate_subtree, struct ly_set *node_when_p, struct ly_set *node_types_p,
+        struct ly_set *meta_types_p, struct ly_set *ext_val_p, struct lyd_node **diff)
 {
     LY_ERR rc = LY_SUCCESS;
     struct lyd_node *tree_sibling, *tree_parent, *op_subtree, *op_parent, *child;
-    struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, node_exts = {0};
+    struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, ext_val = {0};
 
     assert(op_tree && op_node);
-    assert((node_when_p && node_exts_p && node_types_p && meta_types_p) ||
-            (!node_when_p && !node_exts_p && !node_types_p && !meta_types_p));
+    assert((node_when_p && node_types_p && meta_types_p && ext_val_p) ||
+            (!node_when_p && !node_types_p && !meta_types_p && !ext_val_p));
 
     if (!node_when_p) {
         node_when_p = &node_when;
-        node_exts_p = &node_exts;
         node_types_p = &node_types;
         meta_types_p = &meta_types;
+        ext_val_p = &ext_val;
     }
 
     /* merge op_tree into dep_tree */
@@ -1740,28 +1746,28 @@
 
     if (int_opts & LYD_INTOPT_REPLY) {
         /* add output children defaults */
-        rc = lyd_new_implicit_r(op_node, lyd_node_child_p(op_node), NULL, NULL, node_when_p, node_exts_p, node_types_p,
+        rc = lyd_new_implicit_r(op_node, lyd_node_child_p(op_node), NULL, NULL, node_when_p, node_types_p,
                 LYD_IMPLICIT_OUTPUT, diff);
         LY_CHECK_GOTO(rc, cleanup);
 
         if (validate_subtree) {
             /* skip validating the operation itself, go to children directly */
             LY_LIST_FOR(lyd_child(op_node), child) {
-                rc = lyd_validate_subtree(child, node_when_p, node_exts_p, node_types_p, meta_types_p, 0, diff);
+                rc = lyd_validate_subtree(child, node_when_p, node_types_p, meta_types_p, ext_val_p, 0, diff);
                 LY_CHECK_GOTO(rc, cleanup);
             }
         }
     } else {
         if (validate_subtree) {
             /* prevalidate whole operation subtree */
-            rc = lyd_validate_subtree(op_node, node_when_p, node_exts_p, node_types_p, meta_types_p, 0, diff);
+            rc = lyd_validate_subtree(op_node, node_when_p, node_types_p, meta_types_p, ext_val_p, 0, diff);
             LY_CHECK_GOTO(rc, cleanup);
         }
     }
 
     /* finish incompletely validated terminal values/attributes and when conditions on the full tree */
-    LY_CHECK_GOTO(rc = lyd_validate_unres((struct lyd_node **)&dep_tree, NULL,
-            node_when_p, 0, node_exts_p, node_types_p, meta_types_p, diff), cleanup);
+    LY_CHECK_GOTO(rc = lyd_validate_unres((struct lyd_node **)&dep_tree, NULL, node_when_p, 0, node_types_p,
+            meta_types_p, ext_val_p, 0, diff), cleanup);
 
     /* perform final validation of the operation/notification */
     lyd_validate_obsolete(op_node);
@@ -1779,9 +1785,9 @@
     }
 
     ly_set_erase(&node_when, NULL);
-    ly_set_erase(&node_exts, NULL);
     ly_set_erase(&node_types, NULL);
     ly_set_erase(&meta_types, NULL);
+    ly_set_erase(&ext_val, free);
     return rc;
 }
 
diff --git a/src/validation.h b/src/validation.h
index b8b1a98..abf7332 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -27,15 +27,6 @@
 struct lysc_node;
 
 /**
- * @brief Add information about the node's extensions having their own validation callback into an unres set.
- *
- * @param[in,out] node_exts Unres set for holding information for validating extension instances.
- * @param[in] node Data node to be examined.
- * @return LY_ERR values.
- */
-LY_ERR lysc_node_ext_tovalidate(struct ly_set *node_exts, struct lyd_node *node);
-
-/**
  * @brief Add new changes into a diff. They are always merged.
  *
  * @param[in] node Node/subtree to add.
@@ -56,15 +47,16 @@
  * the first top-level sibling.
  * @param[in] node_when Set with nodes with "when" conditions, can be NULL.
  * @param[in] when_xp_opts Additional XPath options to use for evaluating "when".
- * @param[in] node_exts Set with nodes with extension instances with validation plugin callback, can be NULL.
  * @param[in] node_types Set with nodes with unresolved types, can be NULL
  * @param[in] meta_types Set with metadata with unresolved types, can be NULL.
+ * @param[in] ext_val Set with extension data to validate, can be NULL.
+ * @param[in] val_opts Validation options, see @ref datavalidationoptions.
  * @param[in,out] diff Validation diff.
  * @return LY_ERR value.
  */
 LY_ERR lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, struct ly_set *node_when,
-        uint32_t when_xp_opts, struct ly_set *node_exts, struct ly_set *node_types, struct ly_set *meta_types,
-        struct lyd_node **diff);
+        uint32_t when_xp_opts, struct ly_set *node_types, struct ly_set *meta_types, struct ly_set *ext_val,
+        uint32_t val_opts, struct lyd_node **diff);
 
 /**
  * @brief Validate new siblings. Specifically, check duplicated instances, autodelete default values and cases.
@@ -89,14 +81,14 @@
  * @param[in] val_opts Validation options, see @ref datavalidationoptions.
  * @param[in] validate_subtree Whether subtree was already validated (as part of data parsing) or not (separate validation).
  * @param[in] node_when_p Set of nodes with when conditions, if NULL a local set is used.
- * @param[in] node_exts_p Set with nodes with extension instances with validation plugin callback, if NULL a local set is used.
  * @param[in] node_types_p Set of unres node types, if NULL a local set is used.
  * @param[in] meta_types_p Set of unres metadata types, if NULL a local set is used.
+ * @param[in] ext_val_p Set of unres extension data to validate, if NULL a local set is used.
  * @param[out] diff Generated validation diff, not generated if NULL.
  * @return LY_ERR value.
  */
 LY_ERR lyd_validate(struct lyd_node **tree, const struct lys_module *module, const struct ly_ctx *ctx, uint32_t val_opts,
-        ly_bool validate_subtree, struct ly_set *node_when_p, struct ly_set *node_exts_p,
-        struct ly_set *node_types_p, struct ly_set *meta_types_p, struct lyd_node **diff);
+        ly_bool validate_subtree, struct ly_set *node_when_p, struct ly_set *node_types_p, struct ly_set *meta_types_p,
+        struct ly_set *ext_val_p, struct lyd_node **diff);
 
 #endif /* LY_VALIDATION_H_ */
diff --git a/src/xml.c b/src/xml.c
index 49704d6..663d3e3 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -181,11 +181,6 @@
     return LY_SUCCESS;
 }
 
-/**
- * @brief Remove all the namespaces defined in the element recently closed (removed from the xmlctx->elements).
- *
- * @param[in] xmlctx XML context to work with.
- */
 void
 lyxml_ns_rm(struct lyxml_ctx *xmlctx)
 {
diff --git a/src/xml.h b/src/xml.h
index edf9512..125271f 100644
--- a/src/xml.h
+++ b/src/xml.h
@@ -133,6 +133,13 @@
 LY_ERR lyxml_ctx_peek(struct lyxml_ctx *xmlctx, enum LYXML_PARSER_STATUS *next);
 
 /**
+ * @brief Remove all the namespaces defined in the element recently closed (removed from the xmlctx->elements).
+ *
+ * @param[in] xmlctx XML context to work with.
+ */
+void lyxml_ns_rm(struct lyxml_ctx *xmlctx);
+
+/**
  * @brief Get a namespace record for the given prefix in the current context.
  *
  * @param[in] ns_set Set with namespaces from the XML context.
diff --git a/src/xpath.c b/src/xpath.c
index 8afebb3..64b9ef8 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -343,8 +343,8 @@
  * @return LY_ERR
  */
 static LY_ERR
-cast_string_recursive(const struct lyd_node *node, ly_bool fake_cont, enum lyxp_node_type root_type, uint16_t indent, char **str,
-        uint16_t *used, uint16_t *size)
+cast_string_recursive(const struct lyd_node *node, ly_bool fake_cont, enum lyxp_node_type root_type, uint16_t indent,
+        char **str, uint16_t *used, uint16_t *size)
 {
     char *buf, *line, *ptr = NULL;
     const char *value_str;
@@ -415,7 +415,8 @@
 
             if (any->value_type == LYD_ANYDATA_LYB) {
                 /* try to parse it into a data tree */
-                if (lyd_parse_data_mem((struct ly_ctx *)LYD_CTX(node), any->value.mem, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree) == LY_SUCCESS) {
+                if (lyd_parse_data_mem((struct ly_ctx *)LYD_CTX(node), any->value.mem, LYD_LYB,
+                        LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree) == LY_SUCCESS) {
                     /* successfully parsed */
                     free(any->value.mem);
                     any->value.tree = tree;
@@ -1242,7 +1243,8 @@
 }
 
 LY_ERR
-lyxp_set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type, uint32_t *index_p)
+lyxp_set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type,
+        uint32_t *index_p)
 {
     uint32_t index;
 
@@ -5368,6 +5370,7 @@
         case LY_VALUE_CANON:
         case LY_VALUE_JSON:
         case LY_VALUE_LYB:
+        case LY_VALUE_STR_NS:
             /* inherit parent (context node) module */
             if (ctx_scnode) {
                 mod = ctx_scnode->module;
@@ -5481,6 +5484,7 @@
             break;
         case LY_VALUE_JSON:
         case LY_VALUE_LYB:
+        case LY_VALUE_STR_NS:
             /* inherit module of the context node, if any */
             if (ctx_scnode) {
                 moveto_mod = ctx_scnode->module;
@@ -5591,7 +5595,7 @@
 moveto_node_hash(struct lyxp_set *set, const struct lysc_node *scnode, const struct ly_path_predicate *predicates,
         uint32_t options)
 {
-    LY_ERR ret = LY_SUCCESS;
+    LY_ERR ret = LY_SUCCESS, r;
     uint32_t i;
     const struct lyd_node *siblings;
     struct lyxp_set result;
@@ -5644,10 +5648,11 @@
 
         /* find the node using hashes */
         if (inst) {
-            lyd_find_sibling_first(siblings, inst, &sub);
+            r = lyd_find_sibling_first(siblings, inst, &sub);
         } else {
-            lyd_find_sibling_val(siblings, scnode, NULL, 0, &sub);
+            r = lyd_find_sibling_val(siblings, scnode, NULL, 0, &sub);
         }
+        LY_CHECK_ERR_GOTO(r && (r != LY_ENOTFOUND), ret = r, cleanup);
 
         /* when check */
         if (!(options & LYXP_IGNORE_WHEN) && sub && lysc_has_when(sub->schema) && !(sub->flags & LYD_WHEN_TRUE)) {
@@ -8696,11 +8701,12 @@
         const struct lyxp_var *vars, struct lyxp_set *set, uint32_t options)
 {
     uint16_t tok_idx = 0;
+    const struct lysc_node *snode;
     LY_ERR rc;
 
     LY_CHECK_ARG_RET(ctx, ctx, exp, set, LY_EINVAL);
     if (!cur_mod && ((format == LY_VALUE_SCHEMA) || (format == LY_VALUE_SCHEMA_RESOLVED))) {
-        LOGARG(NULL, "Current module must be set if schema format is used.");
+        LOGERR(ctx, LY_EINVAL, "Current module must be set if schema format is used.");
         return LY_EINVAL;
     }
 
@@ -8710,6 +8716,14 @@
             tree = lyd_parent(tree);
         }
         tree = lyd_first_sibling(tree);
+
+        for (snode = tree->schema->parent; snode && (snode->nodetype & (LYS_CASE | LYS_CHOICE)); snode = snode->parent) {}
+        if (snode) {
+            /* unable to evaluate absolute paths */
+            LOGERR(ctx, LY_EINVAL, "Data node \"%s\" has no parent but is not instance of a top-level schema node.",
+                    LYD_NAME(tree));
+            return LY_EINVAL;
+        }
     }
 
     /* prepare set for evaluation */