libyang NEW callback for adding schemas into ctx for data
diff --git a/src/common.c b/src/common.c
index dc0e1a4..d61d6aa 100644
--- a/src/common.c
+++ b/src/common.c
@@ -28,6 +28,7 @@
 #include "common.h"
 #include "tree_internal.h"
 #include "xpath.h"
+#include "context.h"
 #include "libyang.h"
 
 /* libyang errno */
@@ -522,7 +523,7 @@
 }
 
 const char *
-transform_xml2json(struct ly_ctx *ctx, const char *expr, struct lyxml_elem *xml, int log)
+transform_xml2json(struct ly_ctx *ctx, const char *expr, struct lyxml_elem *xml, int use_ctx_data_clb, int log)
 {
     const char *end, *cur_expr, *ptr;
     char *out, *prefix;
@@ -578,6 +579,13 @@
                 goto error;
             }
             mod = ly_ctx_get_module_by_ns(ctx, ns->value, NULL);
+            if (use_ctx_data_clb && ctx->data_clb) {
+                if (!mod) {
+                    mod = ctx->data_clb(ctx, NULL, ns->value, 0, ctx->data_clb_data);
+                } else if (!mod->implemented) {
+                    mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
+                }
+            }
             if (!mod) {
                 if (log) {
                     LOGVAL(LYE_XML_INVAL, LY_VLOG_XML, xml, "module namespace");
diff --git a/src/common.h b/src/common.h
index ffae1ac..ecdac85 100644
--- a/src/common.h
+++ b/src/common.h
@@ -338,11 +338,12 @@
  * @param[in] ctx libyang context to use.
  * @param[in] expr XML expression.
  * @param[in] xml XML element with the expression.
+ * @param[in] use_ctx_data_clb Whether to use data_clb in \p ctx if an unknown module namespace is found.
  * @param[in] log Whether to log errors or not.
  *
  * @return Transformed JSON expression in the dictionary, NULL on error.
  */
-const char *transform_xml2json(struct ly_ctx *ctx, const char *expr, struct lyxml_elem *xml, int log);
+const char *transform_xml2json(struct ly_ctx *ctx, const char *expr, struct lyxml_elem *xml, int use_ctx_data_clb, int log);
 
 /**
  * @brief Transform expression from the schema format (prefixes of imports) to
diff --git a/src/context.c b/src/context.c
index 3eeb381..7990d90 100644
--- a/src/context.c
+++ b/src/context.c
@@ -357,14 +357,14 @@
 }
 
 API void
-ly_ctx_set_module_clb(struct ly_ctx *ctx, ly_module_clb clb, void *user_data)
+ly_ctx_set_imp_module_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data)
 {
-    ctx->module_clb = clb;
-    ctx->module_clb_data = user_data;
+    ctx->imp_clb = clb;
+    ctx->imp_clb_data = user_data;
 }
 
-API ly_module_clb
-ly_ctx_get_module_clb(const struct ly_ctx *ctx, void **user_data)
+API ly_module_imp_clb
+ly_ctx_get_imp_module_clb(const struct ly_ctx *ctx, void **user_data)
 {
     if (!ctx) {
         ly_errno = LY_EINVAL;
@@ -372,9 +372,25 @@
     }
 
     if (user_data) {
-        *user_data = ctx->module_clb_data;
+        *user_data = ctx->imp_clb_data;
     }
-    return ctx->module_clb;
+    return ctx->imp_clb;
+}
+
+API void
+ly_ctx_set_data_module_clb(struct ly_ctx *ctx, ly_module_data_clb clb, void *user_data)
+{
+    ctx->data_clb = clb;
+    ctx->data_clb_data = user_data;
+}
+
+API ly_module_data_clb
+ly_ctx_get_data_module_clb(const struct ly_ctx *ctx, void **user_data)
+{
+    if (user_data) {
+        *user_data = ctx->data_clb_data;
+    }
+    return ctx->data_clb;
 }
 
 const struct lys_module *
@@ -433,12 +449,12 @@
         }
     }
 
-    if (ctx->module_clb) {
+    if (ctx->imp_clb) {
         if (module) {
             mod = lys_main_module(module);
-            module_data = ctx->module_clb(mod->name, (mod->rev_size ? mod->rev[0].date : NULL), name, revision, ctx->module_clb_data, &format, &module_data_free);
+            module_data = ctx->imp_clb(mod->name, (mod->rev_size ? mod->rev[0].date : NULL), name, revision, ctx->imp_clb_data, &format, &module_data_free);
         } else {
-            module_data = ctx->module_clb(name, revision, NULL, NULL, ctx->module_clb_data, &format, &module_data_free);
+            module_data = ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data, &format, &module_data_free);
         }
         if (!module_data) {
             if (module || revision) {
diff --git a/src/context.h b/src/context.h
index a75afe2..a463d6c 100644
--- a/src/context.h
+++ b/src/context.h
@@ -3,7 +3,7 @@
  * @author Radek Krejci <rkrejci@cesnet.cz>
  * @brief internal context structures and functions
  *
- * Copyright (c) 2015 CESNET, z.s.p.o.
+ * Copyright (c) 2015 - 2017 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.
@@ -33,8 +33,10 @@
 struct ly_ctx {
     struct dict_table dict;
     struct ly_modules_list models;
-    ly_module_clb module_clb;
-    void *module_clb_data;
+    ly_module_imp_clb imp_clb;
+    void *imp_clb_data;
+    ly_module_data_clb data_clb;
+    void *data_clb_data;
 };
 
 #endif /* LY_CONTEXT_H_ */
diff --git a/src/libyang.h.in b/src/libyang.h.in
index c9ba096..ab27f61 100644
--- a/src/libyang.h.in
+++ b/src/libyang.h.in
@@ -99,14 +99,16 @@
  * the module is not found, libyang tries to find the (sub)module also in current working working directory.
  * Note, that in this case only the current directory without any other subdirectory is examinde. This
  * automatic searching can be completely avoided when the caller sets module searching callback
- * (#ly_module_clb) via ly_ctx_set_module_clb().
+ * (#ly_module_imp_clb) via ly_ctx_set_module_imp_clb().
  *
  * Schemas are added into the context using [parser functions](@ref howtoschemasparsers) - \b lys_parse_*().
- * In case of schemas, also ly_ctx_load_module() can be used - in that case the #ly_module_clb or automatic
+ * In case of schemas, also ly_ctx_load_module() can be used - in that case the #ly_module_imp_clb or automatic
  * search in search dir and in the current working directory is used.
  *
  * Similarly, data trees can be parsed by \b lyd_parse_*() functions. Note, that functions for schemas have \b lys_
- * prefix while functions for instance data have \b lyd_ prefix.
+ * prefix while functions for instance data have \b lyd_ prefix. If during data parsing a schema is required and
+ * not found in the context, a callback is called, which should add this schema into the context. You can set it
+ * using ly_ctx_set_module_data_clb() (more in @ref howtodataparsers and @ref howtodatavalidation).
  *
  * Context can hold multiple revisions of the same schema, but only one of them can be implemented. The schema is not
  * implemented in case it is automatically loaded as import for another module and it is not referenced in such
@@ -144,8 +146,10 @@
  * - ly_ctx_new()
  * - ly_ctx_set_searchdir()
  * - ly_ctx_get_searchdir()
- * - ly_ctx_set_module_clb()
- * - ly_ctx_get_module_clb()
+ * - ly_ctx_set_module_imp_clb()
+ * - ly_ctx_get_module_imp_clb()
+ * - ly_ctx_set_module_data_clb()
+ * - ly_ctx_get_module_data_clb()
  * - ly_ctx_load_module()
  * - ly_ctx_info()
  * - ly_ctx_get_module_iter()
@@ -255,7 +259,7 @@
  *
  * Other schemas can be added to the context manually as described in [context page](@ref howtocontext) by the functions
  * listed below. Besides the schema parser functions, it is also possible to use ly_ctx_load_module() which tries to
- * find the required schema automatically - using #ly_module_clb or automatic search in working directory and in the
+ * find the required schema automatically - using #ly_module_imp_clb or automatic search in working directory and in the
  * context's searchpath.
  *
  * Functions List
@@ -263,7 +267,7 @@
  * - lys_parse_mem()
  * - lys_parse_fd()
  * - lys_parse_path()
- * - ly_ctx_set_module_clb()
+ * - ly_ctx_set_module_imp_clb()
  * - ly_ctx_load_module()
  */
 
@@ -456,6 +460,10 @@
  * In contrast to the schema parser, data parser also accepts empty input data if such an empty data tree is valid
  * according to the schemas in the libyang context.
  *
+ * If a node from a schema, which is not present in the context, is parsed, a callback set by ly_ctx_set_module_data_clb()
+ * is called and this way the application is given the opportunity to add this schema into the context before the
+ * parsing would fail.
+ *
  * In case of XML input data, there is one additional way to parse input data. Besides parsing the data from a string
  * in memory or a file, caller is able to build an XML tree using [libyang XML parser](@ref howtoxml) and then use
  * this tree (or a part of it) as input to the lyd_parse_xml() function.
@@ -536,6 +544,13 @@
  * change is done on the data tree (via a combination of \b lyd_change_*(), \b lyd_insert*(), \b lyd_new*(),
  * lyd_unlink() and lyd_free() functions).
  *
+ * Part of data validation is resolving leafrefs and instance-identifiers. Leafrefs are resolved only when a change occured
+ * in the data tree that could have broken the link. However, as instance-identifiers can point to any node whatsoever
+ * without an import, it would not be effective to store metadata as in the case of leafrefs. That is why they are resolved
+ * during every validation. Also, for the same reason, it can easily happen that when parsing/validating data with
+ * an instance-identifier, it will target a remote node, whose schema is not currently present in the context. To handle
+ * this case, a callback should be set using ly_ctx_set_module_data_clb(), which can load the schema when required.
+ *
  * Must And When Conditions Accessible Tree
  * ----------------------------------------
  *
@@ -961,8 +976,8 @@
  * @param[out] free_module_data Callback for freeing the returned module data. If not set, the data will be left untouched.
  * @return Requested module data or NULL if the callback is not able to provide the requested schema content for any reason.
  */
-typedef char *(*ly_module_clb)(const char *mod_name, const char *mod_rev, const char *submod_name, const char *sub_rev,
-                               void *user_data, LYS_INFORMAT *format, void (**free_module_data)(void *model_data));
+typedef char *(*ly_module_imp_clb)(const char *mod_name, const char *mod_rev, const char *submod_name, const char *sub_rev,
+                                   void *user_data, LYS_INFORMAT *format, void (**free_module_data)(void *model_data));
 
 /**
  * @brief Set missing include or import module callback. It is meant to be used when the models
@@ -970,19 +985,56 @@
  * not be required in other cases.
  *
  * @param[in] ctx Context that will use this callback.
- * @param[in] clb Callback responsible for returning a missing model.
+ * @param[in] clb Callback responsible for returning the missing model.
  * @param[in] user_data Arbitrary data that will always be passed to the callback \p clb.
  */
-void ly_ctx_set_module_clb(struct ly_ctx *ctx, ly_module_clb clb, void *user_data);
+void ly_ctx_set_module_imp_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data);
 
 /**
- * @brief Get the custom callback for missing module retrieval.
+ * @brief Get the custom callback for missing import/include module retrieval.
+ *
+ * @param[in] ctx Context to read from.
+ * @param[in] user_data Optional pointer for getting the user-supplied callback data.
+ * @return Callback or NULL if not set.
+ */
+ly_module_imp_clb ly_ctx_get_module_imp_clb(const struct ly_ctx *ctx, void **user_data);
+
+/**
+ * @brief Callback for retrieving missing modules in the context, for which some data was found.
+ *
+ * Either \p name or \p ns is ALWAYS set, but both can also be set.
+ *
+ * @param[in,out] ctx Context with the missing module.
+ * @param[in] name Missing module name.
+ * @param[in] ns Missing module namespace.
+ * @param[in] options Bitmask of LY_MODCLB_* values or 0.
+ * @param[in] user_data User-supplied callback data.
+ * @return Newly added or modified module, NULL on failure.
+ */
+typedef const struct lys_module *(*ly_module_data_clb)(struct ly_ctx *ctx, const char *name, const char *ns,
+                                                       int options, void *user_data);
+
+/* Module is in the context, but is not implemented, so to continue with the data operation, it must be implemented. */
+#define LY_MODCLB_NOT_IMPLEMENTED 0x01
+
+/**
+ * @brief Set the missing data module callback. It will be called when some data is parsed or searched for and their module
+ * is not found in the context or is not implemented.
+ *
+ * @param[in] ctx Context that will use this callback.
+ * @param[in] clb Callback responsible for returning the missing model.
+ * @param[in] user_data Arbitrary data that will always be passed to the callback \p clb.
+ */
+void ly_ctx_set_module_data_clb(struct ly_ctx *ctx, ly_module_data_clb clb, void *user_data);
+
+/**
+ * @brief Get the missing data module calback.
  *
  * @param[in] ctx Context to read from.
  * @param[in] user_data Optional pointer for getting the user-supplied callbck data.
- * @return Custom user missing module callback or NULL if not set.
+ * @return Callback or NULL if not set.
  */
-ly_module_clb ly_ctx_get_module_clb(const struct ly_ctx *ctx, void **user_data);
+ly_module_data_clb ly_ctx_get_module_data_clb(const struct ly_ctx *ctx, void **user_data);
 
 /**
  * @brief Get pointer to the schema tree of the module of the specified namespace
diff --git a/src/parser.c b/src/parser.c
index faa5c03..df3c545 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -1380,7 +1380,7 @@
 
         if (xml) {
             /* first, convert value into the json format */
-            value = transform_xml2json(type->parent->module->ctx, value, xml, 0);
+            value = transform_xml2json(type->parent->module->ctx, value, xml, 0, 0);
             if (!value) {
                 /* invalid identityref format */
                 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, *value_, leaf->schema->name);
@@ -1447,7 +1447,7 @@
 
         if (xml) {
             /* first, convert value into the json format */
-            value = transform_xml2json(type->parent->module->ctx, value, xml, 0);
+            value = transform_xml2json(type->parent->module->ctx, value, xml, 1, 0);
             if (!value) {
                 /* invalid instance-identifier format */
                 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, *value_, leaf->schema->name);
@@ -1667,7 +1667,7 @@
              * the type without resolving it -> we return the union type (resolve it with resolve_union()) */
             if (xml) {
                 /* in case it should resolve into a instance-identifier, we can only do the JSON conversion here */
-                leaf->value.string = transform_xml2json(type->parent->module->ctx, value, xml, 0);
+                leaf->value.string = transform_xml2json(type->parent->module->ctx, value, xml, 1, 0);
                 if (!leaf->value.string) {
                     /* invalid instance-identifier format */
                     LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, *value_, leaf->schema->name);
diff --git a/src/parser_json.c b/src/parser_json.c
index 9dad8fb..82362b6 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -831,61 +831,69 @@
         /* starting in root */
         /* get the proper schema */
         module = ly_ctx_get_module(ctx, prefix, NULL);
-        if (module) {
+        if (ctx->data_clb) {
+            if (!module) {
+                module = ctx->data_clb(ctx, prefix, NULL, 0, ctx->data_clb_data);
+            } else if (!module->implemented) {
+                module = ctx->data_clb(ctx, module->name, module->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
+            }
+        }
+        if (module && module->implemented) {
             /* get the proper schema node */
             while ((schema = (struct lys_node *)lys_getnext(schema, NULL, module, 0))) {
                 if (!strcmp(schema->name, name)) {
                     break;
                 }
             }
-        } else {
-            LOGVAL(LYE_INELEM, LY_VLOG_NONE, NULL, name);
-            goto error;
         }
     } else {
-        /* parsing some internal node, we start with parent's schema pointer */
         if (prefix) {
-            /* get the proper schema */
+            /* get the proper module to give the chance to load/implement it */
             module = ly_ctx_get_module(ctx, prefix, NULL);
-            if (!module) {
-                LOGVAL(LYE_INELEM, LY_VLOG_LYD, (*parent), name);
-                goto error;
+            if (ctx->data_clb) {
+                if (!module) {
+                    module = ctx->data_clb(ctx, prefix, NULL, 0, ctx->data_clb_data);
+                } else if (!module->implemented) {
+                    module = ctx->data_clb(ctx, module->name, module->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
+                }
             }
         }
 
         /* go through RPC's input/output following the options' data type */
         if ((*parent)->schema->nodetype == LYS_RPC) {
-            while ((schema = (struct lys_node *)lys_getnext(schema, (*parent)->schema, module, LYS_GETNEXT_WITHINOUT))) {
+            while ((schema = (struct lys_node *)lys_getnext(schema, (*parent)->schema, NULL, LYS_GETNEXT_WITHINOUT))) {
                 if ((options & LYD_OPT_RPC) && (schema->nodetype == LYS_INPUT)) {
                     break;
                 } else if ((options & LYD_OPT_RPCREPLY) && (schema->nodetype == LYS_OUTPUT)) {
                     break;
                 }
             }
-            if (!schema) {
-                LOGVAL(LYE_INELEM, LY_VLOG_LYD, (*parent), name);
-                goto error;
-            }
             schema_parent = schema;
             schema = NULL;
         }
 
         if (schema_parent) {
-            while ((schema = (struct lys_node *)lys_getnext(schema, schema_parent, module, 0))) {
-                if (!strcmp(schema->name, name)) {
+            while ((schema = (struct lys_node *)lys_getnext(schema, schema_parent, NULL, 0))) {
+                if (!strcmp(schema->name, name)
+                        && ((prefix && !strcmp(lys_node_module(schema)->name, prefix))
+                        || (!prefix && (lys_node_module(schema) == lys_node_module(schema_parent))))) {
                     break;
                 }
             }
         } else {
-            while ((schema = (struct lys_node *)lys_getnext(schema, (*parent)->schema, module, 0))) {
-                if (!strcmp(schema->name, name)) {
+            while ((schema = (struct lys_node *)lys_getnext(schema, (*parent)->schema, NULL, 0))) {
+                if (!strcmp(schema->name, name)
+                        && ((prefix && !strcmp(lys_node_module(schema)->name, prefix))
+                        || (!prefix && (lys_node_module(schema) == lyd_node_module(*parent))))) {
                     break;
                 }
             }
         }
     }
-    if (!schema || !lys_node_module(schema)->implemented) {
-        LOGVAL(LYE_INELEM, LY_VLOG_LYD, (*parent), name);
+
+    module = lys_node_module(schema);
+    if (!module || !module->implemented || module->disabled) {
+        LOGVAL(LYE_INELEM, (*parent ? LY_VLOG_LYD : LY_VLOG_NONE), (*parent), name);
         goto error;
     }
 
@@ -898,7 +906,7 @@
         }
 
 attr_repeat:
-        r = json_parse_attr(schema->module, &attr, &data[len]);
+        r = json_parse_attr((struct lys_module *)module, &attr, &data[len]);
         if (!r) {
             LOGPATH(LY_VLOG_LYD, (*parent));
             goto error;
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 0d8541c..657ae10 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -105,6 +105,7 @@
                struct lyd_node *prev, int options, struct unres_data *unres, struct lyd_node **result,
                struct lyd_node **act_notif)
 {
+    const struct lys_module *mod = NULL;
     struct lyd_node *diter, *dlast;
     struct lys_node *schema = NULL, *target;
     struct lys_node_augment *aug;
@@ -130,61 +131,62 @@
 
     /* find schema node */
     if (!parent) {
-        /* starting in root */
-        for (i = 0; i < ctx->models.used; i++) {
-            /* skip just imported modules, data can be coupled only with the implemented modules,
-             * also skip the disabled modules */
-            if (!ctx->models.list[i]->implemented || ctx->models.list[i]->disabled) {
-                continue;
+        mod = ly_ctx_get_module_by_ns(ctx, xml->ns->value, NULL);
+        if (ctx->data_clb) {
+            if (!mod) {
+                mod = ctx->data_clb(ctx, NULL, xml->ns->value, 0, ctx->data_clb_data);
+            } else if (!mod->implemented) {
+                mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
             }
-            /* match data model based on namespace */
-            if (ly_strequal(ctx->models.list[i]->ns, xml->ns->value, 1)) {
-                /* get the proper schema node */
-                schema = xml_data_search_schemanode(xml, ctx->models.list[i]->data, options);
-                if (!schema) {
-                    /* it still can be the specific case of this module containing an augment of another module
-                     * top-level choice or top-level choice's case, bleh */
-                    for (j = 0; j < ctx->models.list[i]->augment_size; ++j) {
-                        aug = &ctx->models.list[i]->augment[j];
-                        target = aug->target;
-                        if (target->nodetype & (LYS_CHOICE | LYS_CASE)) {
-                            /* 1) okay, the target is choice or case */
-                            while (target && (target->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES))) {
-                                target = lys_parent(target);
-                            }
-                            /* 2) now, the data node will be top-level, there are only non-data schema nodes */
-                            if (!target) {
-                                while ((schema = (struct lys_node *)lys_getnext(schema, (struct lys_node *)aug, NULL, 0))) {
-                                    /* 3) alright, even the name matches, we found our schema node */
-                                    if (ly_strequal(schema->name, xml->name, 1)) {
-                                        break;
-                                    }
+        }
+
+        /* get the proper schema node */
+        if (mod && mod->implemented && !mod->disabled) {
+            schema = xml_data_search_schemanode(xml, mod->data, options);
+            if (!schema) {
+                /* it still can be the specific case of this module containing an augment of another module
+                * top-level choice or top-level choice's case, bleh */
+                for (j = 0; j < mod->augment_size; ++j) {
+                    aug = &mod->augment[j];
+                    target = aug->target;
+                    if (target->nodetype & (LYS_CHOICE | LYS_CASE)) {
+                        /* 1) okay, the target is choice or case */
+                        while (target && (target->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES))) {
+                            target = lys_parent(target);
+                        }
+                        /* 2) now, the data node will be top-level, there are only non-data schema nodes */
+                        if (!target) {
+                            while ((schema = (struct lys_node *)lys_getnext(schema, (struct lys_node *)aug, NULL, 0))) {
+                                /* 3) alright, even the name matches, we found our schema node */
+                                if (ly_strequal(schema->name, xml->name, 1)) {
+                                    break;
                                 }
                             }
                         }
+                    }
 
-                        if (schema) {
-                            break;
-                        }
+                    if (schema) {
+                        break;
                     }
                 }
-                break;
             }
         }
     } else {
         /* parsing some internal node, we start with parent's schema pointer */
         schema = xml_data_search_schemanode(xml, parent->schema->child, options);
-    }
-    if (!schema) {
-        if ((options & LYD_OPT_STRICT) || ly_ctx_get_module_by_ns(ctx, xml->ns->value, NULL)) {
-            LOGVAL(LYE_INELEM, LY_VLOG_LYD, parent, xml->name);
-            return -1;
-        } else {
-            return 0;
+
+        if (schema) {
+            if (!lys_node_module(schema)->implemented && ctx->data_clb) {
+                mod = ctx->data_clb(ctx, lys_node_module(schema)->name, lys_node_module(schema)->ns,
+                                    LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
+            }
         }
-    } else if (!lys_node_module(schema)->implemented) {
+    }
+
+    mod = lys_node_module(schema);
+    if (!mod || !mod->implemented || mod->disabled) {
         if (options & LYD_OPT_STRICT) {
-            LOGVAL(LYE_INELEM, LY_VLOG_LYD, parent, xml->name);
+            LOGVAL(LYE_INELEM, (parent ? LY_VLOG_LYD : LY_VLOG_NONE), parent, xml->name);
             return -1;
         } else {
             return 0;
@@ -446,7 +448,7 @@
         dattr->next = NULL;
         dattr->name = attr->name;
         if (flag && ly_strequal(attr->name, "select", 0)) {
-            dattr->value = transform_xml2json(ctx, attr->value, xml, 1);
+            dattr->value = transform_xml2json(ctx, attr->value, xml, 0, 1);
             if (!dattr->value) {
                 free(dattr);
                 goto error;
diff --git a/src/resolve.c b/src/resolve.c
index ac40f9d..22964a0 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -6795,8 +6795,19 @@
             goto error;
         }
         mod = ly_ctx_get_module(ctx, str, NULL);
+        if (ctx->data_clb) {
+            if (!mod) {
+                mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
+            } else if (!mod->implemented) {
+                mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
+            }
+        }
         free(str);
 
+        if (!mod || !mod->implemented || mod->disabled) {
+            break;
+        }
+
         if (resolve_data(mod, name, name_len, data, &node_match)) {
             /* no instance exists */
             break;
diff --git a/src/tree_data.c b/src/tree_data.c
index 1eb5759..0a76413 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -6276,6 +6276,10 @@
 API struct lys_module *
 lyd_node_module(const struct lyd_node *node)
 {
+    if (!node) {
+        return NULL;
+    }
+
     return node->schema->module->type ? ((struct lys_submodule *)node->schema->module)->belongsto : node->schema->module;
 }
 
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 469b560..7217aba 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -3078,12 +3078,20 @@
 API struct lys_module *
 lys_node_module(const struct lys_node *node)
 {
+    if (!node) {
+        return NULL;
+    }
+
     return node->module->type ? ((struct lys_submodule *)node->module)->belongsto : node->module;
 }
 
 API struct lys_module *
 lys_main_module(const struct lys_module *module)
 {
+    if (!module) {
+        return NULL;
+    }
+
     return (module->type ? ((struct lys_submodule *)module)->belongsto : (struct lys_module *)module);
 }
 
diff --git a/tests/conformance/test_sec7_18_3_1.c b/tests/conformance/test_sec7_18_3_1.c
index ce619a5..66611c6 100644
--- a/tests/conformance/test_sec7_18_3_1.c
+++ b/tests/conformance/test_sec7_18_3_1.c
@@ -95,7 +95,7 @@
 
         for (j = 0; j < TEST_DATA_FILE_COUNT; ++j) {
             sprintf(buf, TESTS_DIR "/conformance/" TEST_DIR "/data%d.xml", j + 1);
-            st->node = lyd_parse_path(st->ctx, buf, LYD_XML, LYD_OPT_CONFIG | LYD_OPT_NOAUTODEL);
+            st->node = lyd_parse_path(st->ctx, buf, LYD_XML, LYD_OPT_CONFIG | LYD_OPT_NOAUTODEL | LYD_OPT_STRICT);
             if (data_files_fail[j]) {
                 assert_ptr_equal(st->node, NULL);
             } else {
diff --git a/tests/conformance/test_sec7_9_2.c b/tests/conformance/test_sec7_9_2.c
index 56c21d3..5cab646 100644
--- a/tests/conformance/test_sec7_9_2.c
+++ b/tests/conformance/test_sec7_9_2.c
@@ -94,7 +94,7 @@
 
         for (j = 0; j < TEST_DATA_FILE_COUNT; ++j) {
             sprintf(buf, TESTS_DIR "/conformance/" TEST_DIR "/data%d.xml", j + 1);
-            st->node = lyd_parse_path(st->ctx, buf, LYD_XML, LYD_OPT_CONFIG | LYD_OPT_NOAUTODEL);
+            st->node = lyd_parse_path(st->ctx, buf, LYD_XML, LYD_OPT_CONFIG | LYD_OPT_NOAUTODEL | LYD_OPT_STRICT);
             if (data_files_fail[j]) {
                 assert_ptr_equal(st->node, NULL);
             } else {