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 {