schema mount UPDATE support for creating nested data
Not just parsing it directly.
diff --git a/src/parser_json.c b/src/parser_json.c
index c967063..7b780ba 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -183,80 +183,6 @@
}
/**
- * @brief Try to parse data with a parent based on an extension instance.
- *
- * @param[in] lydctx JSON 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
-lydjson_nested_ext(struct lyd_json_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;
- uint32_t quot_count;
-
- /* backup current input */
- in_bck = *lydctx->jsonctx->in;
-
- /* go back in the input for extension parsing */
- in_start = *lydctx->jsonctx->in;
- assert(lyjson_ctx_status(lydctx->jsonctx, 0) == LYJSON_OBJECT);
- quot_count = 0;
- do {
- --in_start.current;
- if ((in_start.current[0] == '\"') && (in_start.current[-1] != '\\')) {
- ++quot_count;
- }
- if (in_start.current == in_start.start) {
- /* invalid JSON */
- return LY_ENOT;
- }
- } while (quot_count < 2);
-
- /* 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_JSON, &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->jsonctx->ctx), LY_EMEM);
- ext_val->ext = &nested_exts[u];
- ext_val->sibling = lyd_child_no_keys(parent);
- LY_CHECK_RET(ly_set_add(&lydctx->ext_val, ext_val, 1, NULL));
- }
-
- /* adjust the jsonctx accordingly */
- *lydctx->jsonctx->in = in_ext;
- LYJSON_STATUS_PUSH_RET(lydctx->jsonctx, LYJSON_OBJECT_CLOSED);
- LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, NULL));
- 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->jsonctx->in = in_bck;
- return LY_ENOT;
-}
-
-/**
* @brief Skip the currently open JSON object/array
* @param[in] jsonctx JSON context with the input data to skip.
* @return LY_ERR value.
@@ -303,27 +229,28 @@
* @param[in] name Requested node's name.
* @param[in] name_len Length of the @p name.
* @param[in] parent Parent of the node being processed, can be NULL in case of top-level.
- * @param[out] snode_p Found schema node corresponding to the input parameters. If NULL, parse as an opaque node.
+ * @param[out] snode Found schema node corresponding to the input parameters. If NULL, parse as an opaque node.
+ * @param[out] ext Extension instance that provided @p snode, if any.
* @return LY_SUCCES on success.
* @return LY_ENOT if the whole object was parsed (skipped or as an extension).
* @return LY_ERR on error.
*/
static LY_ERR
lydjson_get_snode(struct lyd_json_ctx *lydctx, ly_bool is_attr, const char *prefix, size_t prefix_len, const char *name,
- size_t name_len, struct lyd_node *parent, const struct lysc_node **snode_p)
+ size_t name_len, struct lyd_node *parent, const struct lysc_node **snode, struct lysc_ext_instance **ext)
{
LY_ERR ret = LY_SUCCESS, r;
struct lys_module *mod = NULL;
uint32_t getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
- /* init return value */
- *snode_p = NULL;
+ *snode = NULL;
+ *ext = NULL;
LOG_LOCSET(NULL, parent, NULL, NULL);
- /* get the element module */
+ /* get the element module, prefer parent context because of extensions */
if (prefix_len) {
- mod = ly_ctx_get_module_implemented2(lydctx->jsonctx->ctx, prefix, prefix_len);
+ mod = ly_ctx_get_module_implemented2(parent ? LYD_CTX(parent) : lydctx->jsonctx->ctx, prefix, prefix_len);
} else if (parent) {
if (parent->schema) {
mod = parent->schema->module;
@@ -336,13 +263,9 @@
}
if (!mod) {
/* check for extension data */
- r = lydjson_nested_ext(lydctx, parent);
- if (!r) {
- /* successfully parsed */
- ret = LY_ENOT;
- goto cleanup;
- } else if (r != LY_ENOT) {
- /* error */
+ r = ly_nested_ext_schema(parent, NULL, prefix, prefix_len, LY_VALUE_JSON, NULL, name, name_len, snode, ext);
+ if (r != LY_ENOT) {
+ /* success or error */
ret = r;
goto cleanup;
}
@@ -366,19 +289,15 @@
/* get the schema node */
if (mod && (!parent || parent->schema)) {
if (!parent && lydctx->ext) {
- *snode_p = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
+ *snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
} else {
- *snode_p = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
+ *snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
}
- if (!*snode_p) {
+ if (!*snode) {
/* check for extension data */
- r = lydjson_nested_ext(lydctx, parent);
- if (!r) {
- /* successfully parsed */
- ret = LY_ENOT;
- goto cleanup;
- } else if (r != LY_ENOT) {
- /* error */
+ r = ly_nested_ext_schema(parent, NULL, prefix, prefix_len, LY_VALUE_JSON, NULL, name, name_len, snode, ext);
+ if (r != LY_ENOT) {
+ /* success or error */
ret = r;
goto cleanup;
}
@@ -413,7 +332,7 @@
}
} else {
/* check that schema node is valid and can be used */
- ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, *snode_p);
+ ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, *snode);
}
}
@@ -634,6 +553,7 @@
{
LY_ERR ret = LY_SUCCESS;
struct lyd_node *node, *attr, *next, *meta_iter;
+ struct lysc_ext_instance *ext;
uint64_t instance = 0;
const char *prev = NULL;
uint32_t log_location_items = 0;
@@ -704,8 +624,7 @@
lydjson_parse_name(meta_container->name.name, strlen(meta_container->name.name), &name, &name_len,
&prefix, &prefix_len, &is_attr);
assert(is_attr);
- ret = lydjson_get_snode(lydctx, is_attr, prefix, prefix_len, name, name_len, lyd_parent(*first_p), &snode);
- assert(ret == LY_SUCCESS);
+ lydjson_get_snode(lydctx, is_attr, prefix, prefix_len, name, name_len, lyd_parent(*first_p), &snode, &ext);
if (snode != node->schema) {
continue;
@@ -742,10 +661,10 @@
goto cleanup;
}
}
- /* add/correct flags */
- lyd_parse_set_data_flags(node, &lydctx->node_when, &node->meta, lydctx->parse_opts);
- /* done */
+ /* add/correct flags */
+ ret = lyd_parse_set_data_flags(node, &node->meta, (struct lyd_ctx *)lydctx, ext);
+ LY_CHECK_GOTO(ret, cleanup);
break;
}
}
@@ -929,7 +848,8 @@
LY_CHECK_GOTO(ret, cleanup);
/* add/correct flags */
- lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_opts);
+ ret = lyd_parse_set_data_flags(node, &meta, (struct lyd_ctx *)lydctx, NULL);
+ LY_CHECK_GOTO(ret, cleanup);
} else {
/* create attribute */
const char *module_name;
@@ -982,13 +902,19 @@
* @param[in,out] first_p Pointer to the first sibling node in case of top-level.
* @param[in,out] node_p pointer to the new node to insert, after the insert is done, pointer is set to NULL.
* @param[in] last If set, always insert at the end.
+ * @param[in] ext Extension instance of @p node_p, if any.
*/
static void
-lydjson_maintain_children(struct lyd_node *parent, struct lyd_node **first_p, struct lyd_node **node_p, ly_bool last)
+lydjson_maintain_children(struct lyd_node *parent, struct lyd_node **first_p, struct lyd_node **node_p, ly_bool last,
+ struct lysc_ext_instance *ext)
{
if (*node_p) {
/* insert, keep first pointer correct */
- lyd_insert_node(parent, first_p, *node_p, last);
+ if (ext) {
+ lyd_insert_ext(parent, *node_p);
+ } else {
+ lyd_insert_node(parent, first_p, *node_p, last);
+ }
if (first_p) {
if (parent) {
*first_p = lyd_child(parent);
@@ -1116,7 +1042,7 @@
/* continue with the next instance */
assert(node_p);
- lydjson_maintain_children(parent, first_p, node_p, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
+ lydjson_maintain_children(parent, first_p, node_p, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0, NULL);
LY_CHECK_RET(lydjson_create_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status_inner_p, node_p));
}
@@ -1250,6 +1176,7 @@
* @param[in] lydctx JSON data parser context. When the function returns, the context is in the same state
* as before calling, despite it is necessary to process input data for checking.
* @param[in] snode Schema node corresponding to the member currently being processed in the context.
+ * @param[in] ext Extension instance of @p snode, if any.
* @param[in,out] status JSON parser status, is updated.
* @param[out] node Parsed data (or opaque) node.
* @return LY_SUCCESS if a node was successfully parsed,
@@ -1257,8 +1184,8 @@
* @return LY_ERR on other errors.
*/
static LY_ERR
-lydjson_parse_any(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, enum LYJSON_PARSER_STATUS *status,
- struct lyd_node **node)
+lydjson_parse_any(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, struct lysc_ext_instance *ext,
+ enum LYJSON_PARSER_STATUS *status, struct lyd_node **node)
{
LY_ERR r;
uint32_t prev_parse_opts, prev_int_opts;
@@ -1294,7 +1221,7 @@
* process data as opaq nodes */
prev_parse_opts = lydctx->parse_opts;
lydctx->parse_opts &= ~LYD_PARSE_STRICT;
- lydctx->parse_opts |= LYD_PARSE_OPAQ;
+ lydctx->parse_opts |= LYD_PARSE_OPAQ | (ext ? LYD_PARSE_ONLY : 0);
prev_int_opts = lydctx->int_opts;
lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
@@ -1382,6 +1309,7 @@
* @param[in] parent Data parent of the subtree, must be set if @p first is not.
* @param[in,out] first_p Pointer to the variable holding the first top-level sibling, must be set if @p parent is not.
* @param[in] snode Schema node corresponding to the member currently being processed in the context.
+ * @param[in] ext Extension instance of @p snode, if any.
* @param[in] name Parsed JSON node name.
* @param[in] name_len Lenght of @p name.
* @param[in] prefix Parsed JSON node prefix.
@@ -1394,11 +1322,12 @@
*/
static LY_ERR
lydjson_parse_instance(struct lyd_json_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p,
- const struct lysc_node *snode, const char *name, size_t name_len, const char *prefix, size_t prefix_len,
- enum LYJSON_PARSER_STATUS *status, struct lyd_node **node)
+ const struct lysc_node *snode, struct lysc_ext_instance *ext, const char *name, size_t name_len,
+ const char *prefix, size_t prefix_len, enum LYJSON_PARSER_STATUS *status, struct lyd_node **node)
{
LY_ERR ret;
uint32_t type_hints = 0;
+ uint32_t prev_parse_opts;
ret = lydjson_data_check_opaq(lydctx, snode, &type_hints);
if (ret == LY_SUCCESS) {
@@ -1429,6 +1358,12 @@
LOG_LOCSET(snode, *node, NULL, NULL);
+ prev_parse_opts = lydctx->parse_opts;
+ if (ext) {
+ /* only parse these extension data and validate afterwards */
+ lydctx->parse_opts |= LYD_PARSE_ONLY;
+ }
+
/* process children */
while ((*status != LYJSON_OBJECT_CLOSED) && (*status != LYJSON_OBJECT_EMPTY)) {
ret = lydjson_subtree_r(lydctx, *node, lyd_node_child_p(*node), NULL);
@@ -1436,6 +1371,9 @@
*status = lyjson_ctx_status(lydctx->jsonctx, 0);
}
+ /* restore options */
+ lydctx->parse_opts = prev_parse_opts;
+
/* finish linking metadata */
ret = lydjson_metadata_finish(lydctx, lyd_node_child_p(*node));
LY_CHECK_ERR_RET(ret, LOG_LOCBACK(1, 1, 0, 0), ret);
@@ -1460,11 +1398,11 @@
LOG_LOCBACK(1, 1, 0, 0);
} else {
/* create any node */
- LY_CHECK_RET(lydjson_parse_any(lydctx, snode, status, node));
+ LY_CHECK_RET(lydjson_parse_any(lydctx, snode, ext, status, node));
}
/* add/correct flags */
- lyd_parse_set_data_flags(*node, &lydctx->node_when, &(*node)->meta, lydctx->parse_opts);
+ lyd_parse_set_data_flags(*node, &(*node)->meta, (struct lyd_ctx *)lydctx, ext);
} else if (ret == LY_ENOT) {
/* parse it again as an opaq node */
ret = lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status, status, first_p, node);
@@ -1498,6 +1436,7 @@
size_t name_len, prefix_len = 0;
ly_bool is_meta = 0, parse_subtree;
const struct lysc_node *snode = NULL;
+ struct lysc_ext_instance *ext;
struct lyd_node *node = NULL, *attr_node = NULL;
const struct ly_ctx *ctx = lydctx->jsonctx->ctx;
char *value = NULL;
@@ -1515,7 +1454,7 @@
if (!is_meta || name_len || prefix_len) {
/* get the schema node */
- r = lydjson_get_snode(lydctx, is_meta, prefix, prefix_len, name, name_len, parent, &snode);
+ r = lydjson_get_snode(lydctx, is_meta, prefix, prefix_len, name, name_len, parent, &snode, &ext);
if (r == LY_ENOT) {
/* data parsed */
goto cleanup;
@@ -1582,15 +1521,14 @@
/* process all the values/objects */
do {
- lydjson_maintain_children(parent, first_p, &node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
-
- ret = lydjson_parse_instance(lydctx, parent, first_p, snode, name, name_len, prefix, prefix_len,
+ ret = lydjson_parse_instance(lydctx, parent, first_p, snode, ext, name, name_len, prefix, prefix_len,
&status, &node);
if (ret == LY_ENOT) {
goto representation_error;
} else if (ret) {
goto cleanup;
}
+ lydjson_maintain_children(parent, first_p, &node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0, ext);
/* move after the item(s) */
LY_CHECK_GOTO(ret = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
@@ -1615,7 +1553,8 @@
}
/* process the value/object */
- ret = lydjson_parse_instance(lydctx, parent, first_p, snode, name, name_len, prefix, prefix_len, &status, &node);
+ ret = lydjson_parse_instance(lydctx, parent, first_p, snode, ext, name, name_len, prefix, prefix_len,
+ &status, &node);
if (ret == LY_ENOT) {
goto representation_error;
} else if (ret) {
@@ -1631,7 +1570,7 @@
}
/* finally connect the parsed node */
- lydjson_maintain_children(parent, first_p, &node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
+ lydjson_maintain_children(parent, first_p, &node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0, ext);
/* rememeber a successfully parsed node */
if (parsed) {
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 74bdf6e..fc7f3d8 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -1,9 +1,10 @@
/**
* @file parser_xml.c
* @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
* @brief XML data parser for libyang
*
- * 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.
@@ -410,184 +411,77 @@
}
/**
- * @brief Try to parse data with a parent based on an extension instance.
+ * @brief Get schema node for the current element.
*
* @param[in] lydctx XML data parser context.
- * @param[in,out] parent Parent node where the children are inserted.
+ * @param[in] parent Parsed parent data node, if any.
+ * @param[in] prefix Element prefix, if any.
+ * @param[in] prefix_len Length of @p prefix.
+ * @param[in] name Element name.
+ * @param[in] name_len Length of @p name.
+ * @param[out] snode Found schema node, NULL if no suitable was found.
+ * @param[out] ext Extension instance that provided @p snode, if any.
* @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)
+lydxml_subtree_snode(struct lyd_xml_ctx *lydctx, const struct lyd_node *parent, const char *prefix, size_t prefix_len,
+ const char *name, size_t name_len, const struct lysc_node **snode, struct lysc_ext_instance **ext)
{
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) {
- if (!nested_exts[u].def->plugin->parse) {
- /* not an extension with parsed data */
- continue;
- }
-
- /* 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_no_keys(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.
- * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
- * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
- * this may point to a previously existing node.
- * @param[in,out] parsed Optional set to add all the parsed siblings into.
- * @return LY_ERR value.
- */
-static LY_ERR
-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;
- const char *prefix, *name;
- size_t prefix_len, name_len;
struct lyxml_ctx *xmlctx;
const struct ly_ctx *ctx;
const struct lyxml_ns *ns;
- struct lyd_meta *meta = NULL;
- struct lyd_attr *attr = NULL;
- const struct lysc_node *snode;
struct lys_module *mod;
- uint32_t prev_parse_opts, prev_int_opts;
- struct lyd_node *node = NULL, *anchor;
- void *val_prefix_data = NULL;
- LY_VALUE_FORMAT format;
uint32_t getnext_opts;
- ly_bool parse_subtree;
- char *val;
-
- assert(parent || first_p);
xmlctx = lydctx->xmlctx;
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;
+ *snode = NULL;
+ *ext = NULL;
- assert(xmlctx->status == LYXML_ELEMENT);
-
- /* remember element prefix and name */
- prefix = xmlctx->prefix;
- prefix_len = xmlctx->prefix_len;
- name = xmlctx->name;
- name_len = xmlctx->name_len;
-
- /* get the element module */
+ /* get current namespace */
ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
if (!ns) {
LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
- ret = LY_EVALID;
- goto error;
+ return LY_EVALID;
}
- mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
+
+ /* get the element module, use parent context if possible because of extensions */
+ mod = ly_ctx_get_module_implemented_ns(parent ? LYD_CTX(parent) : ctx, ns->uri);
if (!mod) {
/* check for extension data */
- r = lydxml_nested_ext(lydctx, parent);
- if (!r) {
- /* successfully parsed */
+ r = ly_nested_ext_schema(parent, NULL, prefix, prefix_len, LY_VALUE_XML, &lydctx->xmlctx->ns, name, name_len,
+ snode, ext);
+ if (r != LY_ENOT) {
+ /* success or error */
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;
- goto error;
+ return LY_EVALID;
}
- if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
- /* skip element with children */
- LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
- return LY_SUCCESS;
- }
+ return LY_SUCCESS;
}
- /* parser next */
- LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
-
/* get the schema node */
- snode = NULL;
if (mod) {
if (!parent && lydctx->ext) {
- snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
+ *snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
} else {
- snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
+ *snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
}
- if (!snode) {
+ if (!*snode) {
/* check for extension data */
- r = lydxml_nested_ext(lydctx, parent);
- if (!r) {
- /* successfully parsed */
+ r = ly_nested_ext_schema(parent, NULL, prefix, prefix_len, LY_VALUE_XML, &lydctx->xmlctx->ns, name,
+ name_len, snode, ext);
+ if (r != LY_ENOT) {
+ /* success or error */
return r;
- } else if (r != LY_ENOT) {
- /* error */
- ret = r;
- goto error;
}
/* unknown data node */
@@ -607,22 +501,81 @@
LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
(int)name_len, name, mod->name);
}
- ret = LY_EVALID;
- goto error;
- } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
- LOGVRB("Skipping parsing of unknown node \"%.*s\".", name_len, name);
-
- /* skip element with children */
- LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
- return LY_SUCCESS;
+ return LY_EVALID;
}
+ return LY_SUCCESS;
} else {
/* check that schema node is valid and can be used */
- LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
- LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
+ LY_CHECK_RET(lyd_parser_check_schema((struct lyd_ctx *)lydctx, *snode));
+ LY_CHECK_RET(lydxml_data_check_opaq(lydctx, snode));
}
}
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse XML subtree.
+ *
+ * @param[in] lydctx XML YANG data parser context.
+ * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
+ * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
+ * this may point to a previously existing node.
+ * @param[in,out] parsed Optional set to add all the parsed siblings into.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+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;
+ const char *prefix, *name;
+ size_t prefix_len, name_len;
+ struct lyxml_ctx *xmlctx;
+ const struct ly_ctx *ctx;
+ const struct lyxml_ns *ns;
+ struct lyd_meta *meta = NULL;
+ struct lyd_attr *attr = NULL;
+ const struct lysc_node *snode;
+ struct lysc_ext_instance *ext;
+ uint32_t prev_parse_opts, orig_parse_opts, prev_int_opts;
+ struct lyd_node *node = NULL, *anchor;
+ void *val_prefix_data = NULL;
+ LY_VALUE_FORMAT format;
+ ly_bool parse_subtree;
+ char *val;
+
+ assert(parent || first_p);
+
+ xmlctx = lydctx->xmlctx;
+ ctx = xmlctx->ctx;
+
+ parse_subtree = lydctx->parse_opts & LYD_PARSE_SUBTREE ? 1 : 0;
+ /* all descendants should be parsed */
+ lydctx->parse_opts &= ~LYD_PARSE_SUBTREE;
+ orig_parse_opts = lydctx->parse_opts;
+
+ assert(xmlctx->status == LYXML_ELEMENT);
+
+ /* remember element prefix and name */
+ prefix = xmlctx->prefix;
+ prefix_len = xmlctx->prefix_len;
+ name = xmlctx->name;
+ name_len = xmlctx->name_len;
+
+ /* parser next */
+ LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
+
+ /* get the schema node */
+ LY_CHECK_GOTO(ret = lydxml_subtree_snode(lydctx, parent, prefix, prefix_len, name, name_len, &snode, &ext), error);
+
+ if (!snode && !(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
+ LOGVRB("Skipping parsing of unknown node \"%.*s\".", name_len, name);
+
+ /* skip element with children */
+ LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
+ return LY_SUCCESS;
+ }
+
/* create metadata/attributes */
if (xmlctx->status == LYXML_ATTRIBUTE) {
if (snode) {
@@ -720,12 +673,21 @@
/* parser next */
LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
+ prev_parse_opts = lydctx->parse_opts;
+ if (ext) {
+ /* only parse these extension data and validate afterwards */
+ lydctx->parse_opts |= LYD_PARSE_ONLY;
+ }
+
/* process children */
while (xmlctx->status == LYXML_ELEMENT) {
ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
LY_CHECK_GOTO(ret, error);
}
+ /* restore options */
+ lydctx->parse_opts = prev_parse_opts;
+
if (snode->nodetype == LYS_LIST) {
/* check all keys exist */
LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
@@ -773,7 +735,7 @@
/* update options so that generic data can be parsed */
prev_parse_opts = lydctx->parse_opts;
lydctx->parse_opts &= ~LYD_PARSE_STRICT;
- lydctx->parse_opts |= LYD_PARSE_OPAQ;
+ lydctx->parse_opts |= LYD_PARSE_OPAQ | (ext ? LYD_PARSE_ONLY : 0);
prev_int_opts = lydctx->int_opts;
lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
@@ -801,7 +763,7 @@
/* add/correct flags */
if (snode) {
- lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_opts);
+ LY_CHECK_GOTO(ret = lyd_parse_set_data_flags(node, &meta, (struct lyd_ctx *)lydctx, ext), error);
}
/* parser next */
@@ -818,7 +780,11 @@
}
/* insert, keep first pointer correct */
- lyd_insert_node(parent, first_p, node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
+ if (ext) {
+ LY_CHECK_GOTO(ret = lyd_insert_ext(parent, node), error);
+ } else {
+ lyd_insert_node(parent, first_p, node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
+ }
while (!parent && (*first_p)->prev->next) {
*first_p = (*first_p)->prev;
}
@@ -828,10 +794,12 @@
ly_set_add(parsed, node, 1, NULL);
}
+ lydctx->parse_opts = orig_parse_opts;
LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
return LY_SUCCESS;
error:
+ lydctx->parse_opts = orig_parse_opts;
LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
lyd_free_meta_siblings(meta);
lyd_free_attr_siblings(ctx, attr);
diff --git a/src/path.c b/src/path.c
index 932a039..f53768b 100644
--- a/src/path.c
+++ b/src/path.c
@@ -374,33 +374,42 @@
}
/**
- * @brief Parse prefix from a NameTest, if any, and node name, and return expected module of the node.
+ * @brief Parse NameTest and get the corresponding schema node.
*
* @param[in] ctx libyang context.
* @param[in] cur_node Optional current (original context) node.
* @param[in] cur_mod Current module of the path (where the path is "instantiated"). Needed for ::LY_VALUE_SCHEMA
* and ::LY_VALUE_SCHEMA_RESOLVED.
- * @param[in] prev_ctx_node Previous context node. Needed for ::LY_VALUE_JSON.
+ * @param[in] prev_ctx_node Previous context node.
* @param[in] expr Parsed path.
* @param[in] tok_idx Index in @p expr.
* @param[in] format Format of the path.
* @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
- * @param[out] mod Resolved module.
- * @param[out] name Parsed node name.
- * @param[out] name_len Length of @p name.
+ * @param[in] top_ext Optional top-level extension to use for searching the schema node.
+ * @param[in] getnext_opts Options to be used for ::lys_getnext() calls.
+ * @param[out] snode Resolved schema node.
+ * @param[out] ext Optional extension instance of @p snode, if any.
* @return LY_ERR value.
*/
static LY_ERR
-ly_path_compile_prefix(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
+ly_path_compile_snode(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint16_t tok_idx, LY_VALUE_FORMAT format,
- void *prefix_data, const struct lys_module **mod, const char **name, size_t *name_len)
+ void *prefix_data, const struct lysc_ext_instance *top_ext, uint32_t getnext_opts, const struct lysc_node **snode,
+ struct lysc_ext_instance **ext)
{
LY_ERR ret;
- const char *pref;
- size_t len;
+ const struct lys_module *mod = NULL;
+ struct lysc_ext_instance *e = NULL;
+ const char *pref, *name;
+ size_t len, name_len;
assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
+ *snode = NULL;
+ if (ext) {
+ *ext = NULL;
+ }
+
/* get prefix */
if ((pref = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]))) {
len = pref - (expr->expr + expr->tok_pos[tok_idx]);
@@ -409,18 +418,37 @@
len = 0;
}
- /* find next node module */
+ /* set name */
+ if (pref) {
+ name = pref + len + 1;
+ name_len = expr->tok_len[tok_idx] - len - 1;
+ } else {
+ name = expr->expr + expr->tok_pos[tok_idx];
+ name_len = expr->tok_len[tok_idx];
+ }
+
+ /* find node module */
if (pref) {
LOG_LOCSET(cur_node, NULL, NULL, NULL);
- *mod = ly_resolve_prefix(ctx, pref, len, format, prefix_data);
- if (!*mod) {
+ mod = ly_resolve_prefix(ctx, pref, len, format, prefix_data);
+ if ((!mod || !mod->implemented) && prev_ctx_node) {
+ /* check for nested ext data */
+ ret = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
+ if (!ret) {
+ goto success;
+ } else if (ret != LY_ENOT) {
+ goto error;
+ }
+ }
+
+ if (!mod) {
LOGVAL(ctx, LYVE_XPATH, "No module connected with the prefix \"%.*s\" found (prefix format %s).",
(int)len, pref, ly_format2str(format));
ret = LY_EVALID;
goto error;
- } else if (!(*mod)->implemented) {
- LOGVAL(ctx, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
+ } else if (!mod->implemented) {
+ LOGVAL(ctx, LYVE_XPATH, "Not implemented module \"%s\" in path.", mod->name);
ret = LY_EVALID;
goto error;
}
@@ -434,7 +462,7 @@
LOGINT_RET(ctx);
}
/* use current module */
- *mod = cur_mod;
+ mod = cur_mod;
break;
case LY_VALUE_JSON:
case LY_VALUE_LYB:
@@ -442,7 +470,7 @@
LOGINT_RET(ctx);
}
/* inherit module of the previous node */
- *mod = prev_ctx_node->module;
+ mod = prev_ctx_node->module;
break;
case LY_VALUE_CANON:
case LY_VALUE_XML:
@@ -452,15 +480,25 @@
}
}
- /* set name */
- if (pref) {
- *name = pref + len + 1;
- *name_len = expr->tok_len[tok_idx] - len - 1;
+ /* find schema node */
+ if (!prev_ctx_node && top_ext) {
+ *snode = lysc_ext_find_node(top_ext, mod, name, name_len, 0, getnext_opts);
} else {
- *name = expr->expr + expr->tok_pos[tok_idx];
- *name_len = expr->tok_len[tok_idx];
+ *snode = lys_find_child(prev_ctx_node, mod, name, name_len, 0, getnext_opts);
+ if (!(*snode) && prev_ctx_node) {
+ ret = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
+ LY_CHECK_RET(ret && (ret != LY_ENOT), ret);
+ }
+ }
+ if (!(*snode)) {
+ LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
+ return LY_ENOTFOUND;
}
+success:
+ if (ext) {
+ *ext = e;
+ }
return LY_SUCCESS;
error:
@@ -476,9 +514,8 @@
LY_ERR ret = LY_SUCCESS;
struct ly_path_predicate *p;
const struct lysc_node *key;
- const struct lys_module *mod = NULL;
- const char *name, *val;
- size_t name_len, val_len, key_count;
+ const char *val;
+ size_t val_len, key_count;
assert(ctx && ctx_node);
@@ -506,14 +543,9 @@
do {
/* NameTest, find the key */
- LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, format, prefix_data,
- &mod, &name, &name_len));
- key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
- if (!key) {
- LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
- ret = LY_ENOTFOUND;
- goto cleanup;
- } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
+ LY_CHECK_RET(ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, format, prefix_data,
+ NULL, 0, &key, NULL));
+ if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.", lys_nodetype2str(key->nodetype),
key->name);
ret = LY_EVALID;
@@ -638,7 +670,7 @@
LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
/* syntax was already checked */
- p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&name, LY_BASE_DEC);
+ p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&val, LY_BASE_DEC);
++(*tok_idx);
/* ']' */
@@ -668,9 +700,6 @@
{
LY_ERR ret = LY_SUCCESS;
const struct lysc_node *key, *node, *node2;
- const struct lys_module *mod;
- const char *name;
- size_t name_len;
struct ly_ctx *ctx = cur_node->module->ctx;
LOG_LOCSET(cur_node, NULL, NULL, NULL);
@@ -694,15 +723,10 @@
do {
/* NameTest, find the key */
- ret = ly_path_compile_prefix(ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx, format, prefix_data,
- &mod, &name, &name_len);
+ ret = ly_path_compile_snode(ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx, format, prefix_data,
+ NULL, 0, &key, NULL);
LY_CHECK_GOTO(ret, cleanup);
- key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
- if (!key) {
- LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
- ret = LY_EVALID;
- goto cleanup;
- } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
+ if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
lys_nodetype2str(key->nodetype), key->name);
ret = LY_EVALID;
@@ -757,14 +781,8 @@
/* NameTest */
assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
- LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_node->module, node, expr, *tok_idx, format,
- prefix_data, &mod, &name, &name_len));
- node2 = lys_find_child(node, mod, name, name_len, 0, 0);
- if (!node2) {
- LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
- ret = LY_EVALID;
- goto cleanup;
- }
+ LY_CHECK_RET(ly_path_compile_snode(ctx, cur_node, cur_node->module, node, expr, *tok_idx, format,
+ prefix_data, NULL, 0, &node2, NULL));
node = node2;
++(*tok_idx);
} while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
@@ -789,7 +807,7 @@
cleanup:
LOG_LOCBACK(1, 0, 0, 0);
- return ret;
+ return (ret == LY_ENOTFOUND) ? LY_EVALID : ret;
}
/**
@@ -799,7 +817,7 @@
* @param[in] cur_mod Current module of the path (where it was "instantiated"), ignored of @p lref. Used for nodes
* without a prefix for ::LY_VALUE_SCHEMA and ::LY_VALUE_SCHEMA_RESOLVED format.
* @param[in] ctx_node Optional context node, mandatory of @p lref.
- * @param[in] ext Extension instance containing the definition of the data being created. It is used to find the top-level
+ * @param[in] top_ext Extension instance containing the definition of the data being created. It is used to find the top-level
* node inside the extension instance instead of a module. Note that this is the case not only if the @p ctx_node is NULL,
* but also if the relative path starting in @p ctx_node reaches the document root via double dots.
* @param[in] expr Parsed path.
@@ -816,17 +834,15 @@
*/
static LY_ERR
_ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
- const struct lysc_ext_instance *ext, const struct lyxp_expr *expr, ly_bool lref, uint8_t oper, uint8_t target,
+ const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, ly_bool lref, uint8_t oper, uint8_t target,
ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
{
LY_ERR ret = LY_SUCCESS;
uint16_t tok_idx = 0;
- const struct lys_module *mod = NULL;
const struct lysc_node *node2, *cur_node, *op;
struct ly_path *p = NULL;
+ struct lysc_ext_instance *ext = NULL;
uint32_t getnext_opts;
- const char *name;
- size_t name_len;
assert(ctx);
assert(!lref || ctx_node);
@@ -895,19 +911,12 @@
/* NameTest */
LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, expr, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, cleanup);
- /* get module and node name */
- LY_CHECK_GOTO(ret = ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, format, prefix_data,
- &mod, &name, &name_len), cleanup);
+ /* get schema node */
+ LY_CHECK_GOTO(ret = ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, format, prefix_data,
+ top_ext, getnext_opts, &node2, &ext), cleanup);
++tok_idx;
-
- /* find the next node */
- if (!ctx_node && ext) {
- node2 = lysc_ext_find_node(ext, mod, name, name_len, 0, getnext_opts);
- } else {
- node2 = lys_find_child(ctx_node, mod, name, name_len, 0, getnext_opts);
- }
- if (!node2 || (op && (node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
- LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
+ if ((op && (node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
+ LOGVAL(ctx, LYVE_XPATH, "Not found node \"%s\" in path.", node2->name);
ret = LY_EVALID;
goto cleanup;
}
@@ -916,6 +925,7 @@
/* new path segment */
LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
p->node = ctx_node;
+ p->ext = ext;
/* compile any predicates */
if (lref) {
@@ -948,24 +958,24 @@
*path = NULL;
}
LOG_LOCBACK(1, 0, 0, 0);
- return ret;
+ return (ret == LY_ENOTFOUND) ? LY_EVALID : ret;
}
LY_ERR
ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
- const struct lysc_ext_instance *ext, const struct lyxp_expr *expr, uint8_t oper, uint8_t target,
+ const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, uint8_t oper, uint8_t target,
ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
{
- return _ly_path_compile(ctx, cur_mod, ctx_node, ext, expr, 0, oper, target, limit_access_tree, format, prefix_data,
- path);
+ return _ly_path_compile(ctx, cur_mod, ctx_node, top_ext, expr, 0, oper, target, limit_access_tree, format,
+ prefix_data, path);
}
LY_ERR
-ly_path_compile_leafref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const struct lysc_ext_instance *ext,
+ly_path_compile_leafref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const struct lysc_ext_instance *top_ext,
const struct lyxp_expr *expr, uint8_t oper, uint8_t target, LY_VALUE_FORMAT format, void *prefix_data,
struct ly_path **path)
{
- return _ly_path_compile(ctx, ctx_node->module, ctx_node, ext, expr, 1, oper, target, 1, format, prefix_data, path);
+ return _ly_path_compile(ctx, ctx_node->module, ctx_node, top_ext, expr, 1, oper, target, 1, format, prefix_data, path);
}
LY_ERR
diff --git a/src/path.h b/src/path.h
index d3dca9e..c079274 100644
--- a/src/path.h
+++ b/src/path.h
@@ -58,8 +58,9 @@
const struct lysc_node *node; /**< Schema node representing the path segment, first node has special meaning:
- is a top-level node - path is absolute,
- is inner node - path is relative */
- struct ly_path_predicate *predicates; /**< [Sized array](@ref sizedarrays) of the path segment's predicates */
- enum ly_path_pred_type pred_type; /**< Predicate type (see YANG ABNF) */
+ const struct lysc_ext_instance *ext; /**< Extension instance of @p node, if any */
+ struct ly_path_predicate *predicates; /**< [Sized array](@ref sizedarrays) of the path segment's predicates */
+ enum ly_path_pred_type pred_type; /**< Predicate type (see YANG ABNF) */
};
/**
@@ -147,7 +148,7 @@
* @param[in] cur_mod Current module of the path (where it was "instantiated"). Used for nodes in schema-nodeid
* without a prefix for ::LY_VALUE_SCHEMA and ::LY_VALUE_SCHEMA_RESOLVED format.
* @param[in] ctx_node Optional context node.
- * @param[in] ext Extension instance containing the definition of the data being created. It is used to find the top-level
+ * @param[in] top_ext Extension instance containing the definition of the data being created. It is used to find the top-level
* node inside the extension instance instead of a module. Note that this is the case not only if the @p ctx_node is NULL,
* but also if the relative path starting in @p ctx_node reaches the document root via double dots.
* @param[in] expr Parsed path.
@@ -160,7 +161,7 @@
* @return LY_ERR value.
*/
LY_ERR ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
- const struct lysc_ext_instance *ext, const struct lyxp_expr *expr, uint8_t oper, uint8_t target,
+ const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, uint8_t oper, uint8_t target,
ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path);
/**
@@ -168,7 +169,7 @@
*
* @param[in] ctx libyang context.
* @param[in] ctx_node Context node.
- * @param[in] ext Extension instance containing the definition of the data being created. It is used to find the top-level
+ * @param[in] top_ext Extension instance containing the definition of the data being created. It is used to find the top-level
* node inside the extension instance instead of a module. Note that this is the case not only if the @p ctx_node is NULL,
* but also if the relative path starting in @p ctx_node reaches the document root via double dots.
* @param[in] expr Parsed path.
@@ -180,7 +181,7 @@
* @return LY_ERR value.
*/
LY_ERR ly_path_compile_leafref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node,
- const struct lysc_ext_instance *ext, const struct lyxp_expr *expr, uint8_t oper, uint8_t target,
+ const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, uint8_t oper, uint8_t target,
LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path);
/**
diff --git a/src/plugins_exts.h b/src/plugins_exts.h
index f521d7d..d8016eb 100644
--- a/src/plugins_exts.h
+++ b/src/plugins_exts.h
@@ -100,7 +100,7 @@
/**
* @brief Extensions API version
*/
-#define LYPLG_EXT_API_VERSION 2
+#define LYPLG_EXT_API_VERSION 3
/**
* @brief Macro to define plugin information in external plugins
@@ -159,22 +159,26 @@
typedef void (*lyplg_ext_free_clb)(struct ly_ctx *ctx, struct lysc_ext_instance *ext);
/**
- * @brief Callback for parsing YANG instance data described by an extension instance.
+ * @brief Callback for getting a schema node for a new YANG instance data described by an extension instance.
+ * Needed only if the extension instance supports some nested standard YANG data.
*
- * 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] 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.
+ * @param[in] parent Parsed parent data node. Set if @p sparent is NULL.
+ * @param[in] sparent Schema parent node. Set if @p parent is NULL.
+ * @param[in] prefix Element prefix, if any.
+ * @param[in] prefix_len Length of @p prefix.
+ * @param[in] format Format of @p prefix.
+ * @param[in] prefix_data Format-specific prefix data.
+ * @param[in] name Element name.
+ * @param[in] name_len Length of @p name.
+ * @param[out] snode Schema node to use for parsing the node.
* @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_parse_clb)(struct ly_in *in, LYD_FORMAT format, struct lysc_ext_instance *ext,
- struct lyd_node *parent, uint32_t parse_opts);
+typedef LY_ERR (*lyplg_ext_data_snode_clb)(struct lysc_ext_instance *ext, const struct lyd_node *parent,
+ const struct lysc_node *sparent, const char *prefix, size_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data,
+ const char *name, size_t name_len, const struct lysc_node **snode);
/**
* @brief Callback for validating parsed YANG instance data described by an extension instance.
@@ -200,7 +204,7 @@
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_snode_clb snode; /**< callback to get schema node for nested YANG data */
lyplg_ext_data_validate_clb validate; /**< callback to validate parsed data instances according to the extension
definition */
};
diff --git a/src/plugins_exts/metadata.c b/src/plugins_exts/metadata.c
index bc70694..eebb434 100644
--- a/src/plugins_exts/metadata.c
+++ b/src/plugins_exts/metadata.c
@@ -163,7 +163,7 @@
.plugin.compile = &annotation_compile,
.plugin.sprinter = &annotation_schema_printer,
.plugin.free = annotation_free,
- .plugin.parse = NULL,
+ .plugin.snode = NULL,
.plugin.validate = NULL
},
{0} /* terminating zeroed record */
diff --git a/src/plugins_exts/nacm.c b/src/plugins_exts/nacm.c
index d8e1ca8..aa0d0e8 100644
--- a/src/plugins_exts/nacm.c
+++ b/src/plugins_exts/nacm.c
@@ -160,7 +160,7 @@
.plugin.compile = &nacm_compile,
.plugin.sprinter = NULL,
.plugin.free = NULL,
- .plugin.parse = NULL,
+ .plugin.snode = NULL,
.plugin.validate = NULL
}, {
.module = "ietf-netconf-acm",
@@ -171,7 +171,7 @@
.plugin.compile = &nacm_compile,
.plugin.sprinter = NULL,
.plugin.free = NULL,
- .plugin.parse = NULL,
+ .plugin.snode = NULL,
.plugin.validate = NULL
}, {
.module = "ietf-netconf-acm",
@@ -182,7 +182,7 @@
.plugin.compile = &nacm_compile,
.plugin.sprinter = NULL,
.plugin.free = NULL,
- .plugin.parse = NULL,
+ .plugin.snode = NULL,
.plugin.validate = NULL
}, {
.module = "ietf-netconf-acm",
@@ -193,7 +193,7 @@
.plugin.compile = &nacm_compile,
.plugin.sprinter = NULL,
.plugin.free = NULL,
- .plugin.parse = NULL,
+ .plugin.snode = 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 a3a582f..8c4dfa9 100644
--- a/src/plugins_exts/schema_mount.c
+++ b/src/plugins_exts/schema_mount.c
@@ -24,6 +24,7 @@
#include "libyang.h"
#include "log.h"
#include "plugins_exts.h"
+#include "plugins_types.h"
#include "tree_data.h"
#include "tree_schema.h"
@@ -510,62 +511,32 @@
}
/**
- * @brief Parse callback for schema mount.
- * Check if data if valid for schema mount and inserts it to the parent.
+ * @brief Snode callback for schema mount.
+ * Check if data are valid for schema mount and returns their schema node.
*/
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)
+schema_mount_snode(struct lysc_ext_instance *ext, const struct lyd_node *parent, const struct lysc_node *sparent,
+ const char *prefix, size_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data, const char *name, size_t name_len,
+ const struct lysc_node **snode)
{
- LY_ERR ret = LY_SUCCESS, r;
+ LY_ERR r;
+ const struct lys_module *mod;
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;
+ /* get the module */
+ mod = lyplg_type_identity_module(ext_ctx, parent ? parent->schema : sparent, prefix, prefix_len, format, prefix_data);
+ if (!mod) {
+ return LY_ENOT;
}
-cleanup:
- ly_log_options(old_log_opts);
- if (ret) {
- lyd_free_siblings(first);
- }
- return ret;
+ /* get the top-level schema node */
+ *snode = lys_find_child(NULL, mod, name, name_len, 0, 0);
+ return *snode ? LY_SUCCESS : LY_ENOT;
}
/**
@@ -818,7 +789,7 @@
.plugin.compile = &schema_mount_compile,
.plugin.sprinter = NULL,
.plugin.free = &schema_mount_free,
- .plugin.parse = &schema_mount_parse,
+ .plugin.snode = &schema_mount_snode,
.plugin.validate = &schema_mount_validate
},
{0} /* terminating zeroed item */
diff --git a/src/plugins_exts/yangdata.c b/src/plugins_exts/yangdata.c
index 55a03e3..b2e6f62 100644
--- a/src/plugins_exts/yangdata.c
+++ b/src/plugins_exts/yangdata.c
@@ -174,7 +174,7 @@
.plugin.compile = &yangdata_compile,
.plugin.sprinter = &yangdata_schema_printer,
.plugin.free = yangdata_free,
- .plugin.parse = NULL,
+ .plugin.snode = NULL,
.plugin.validate = NULL
},
{0} /* terminating zeroed record */
diff --git a/src/tree_data.c b/src/tree_data.c
index b12580a..0bf1e2d 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -885,8 +885,10 @@
lyd_new_inner(struct lyd_node *parent, const struct lys_module *module, const char *name, ly_bool output,
struct lyd_node **node)
{
+ LY_ERR r;
struct lyd_node *ret = NULL;
const struct lysc_node *schema;
+ struct lysc_ext_instance *ext = NULL;
const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
@@ -898,9 +900,18 @@
schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0,
LYS_CONTAINER | LYS_NOTIF | LYS_RPC | LYS_ACTION, output ? LYS_GETNEXT_OUTPUT : 0);
- LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Inner node (not a list) \"%s\" not found.", name), LY_ENOTFOUND);
+ if (!schema && parent) {
+ r = ly_nested_ext_schema(parent, NULL, module->name, strlen(module->name), LY_VALUE_JSON, NULL, name,
+ strlen(name), &schema, &ext);
+ LY_CHECK_RET(r && (r != LY_ENOT), r);
+ }
+ LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Inner node (container, notif, RPC, or action) \"%s\" not found.",
+ name), LY_ENOTFOUND);
LY_CHECK_RET(lyd_create_inner(schema, &ret));
+ if (ext) {
+ ret->flags |= LYD_EXT;
+ }
if (parent) {
lyd_insert_node(parent, NULL, ret, 0);
}
@@ -958,10 +969,11 @@
{
struct lyd_node *ret = NULL, *key;
const struct lysc_node *schema, *key_s;
+ struct lysc_ext_instance *ext = NULL;
const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
const void *key_val;
uint32_t key_len;
- LY_ERR rc = LY_SUCCESS;
+ LY_ERR r, rc = LY_SUCCESS;
LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
@@ -971,6 +983,11 @@
}
schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, output ? LYS_GETNEXT_OUTPUT : 0);
+ if (!schema && parent) {
+ r = ly_nested_ext_schema(parent, NULL, module->name, strlen(module->name), LY_VALUE_JSON, NULL, name,
+ strlen(name), &schema, &ext);
+ LY_CHECK_RET(r && (r != LY_ENOT), r);
+ }
LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), LY_ENOTFOUND);
/* create list inner node */
@@ -991,6 +1008,9 @@
lyd_insert_node(ret, NULL, key, 1);
}
+ if (ext) {
+ ret->flags |= LYD_EXT;
+ }
if (parent) {
lyd_insert_node(parent, NULL, ret, 0);
}
@@ -1101,8 +1121,10 @@
lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *keys,
ly_bool output, struct lyd_node **node)
{
+ LY_ERR r;
struct lyd_node *ret = NULL;
const struct lysc_node *schema;
+ struct lysc_ext_instance *ext = NULL;
const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
@@ -1117,6 +1139,11 @@
/* find schema node */
schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, output ? LYS_GETNEXT_OUTPUT : 0);
+ if (!schema && parent) {
+ r = ly_nested_ext_schema(parent, NULL, module->name, strlen(module->name), LY_VALUE_JSON, NULL, name, strlen(name),
+ &schema, &ext);
+ LY_CHECK_RET(r && (r != LY_ENOT), r);
+ }
LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), LY_ENOTFOUND);
if ((schema->flags & LYS_KEYLESS) && !keys[0]) {
@@ -1126,6 +1153,9 @@
/* create the list node */
LY_CHECK_RET(lyd_create_list2(schema, keys, strlen(keys), &ret));
}
+ if (ext) {
+ ret->flags |= LYD_EXT;
+ }
if (parent) {
lyd_insert_node(parent, NULL, ret, 0);
}
@@ -1154,9 +1184,10 @@
_lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name, const void *value,
size_t value_len, LY_VALUE_FORMAT format, ly_bool output, struct lyd_node **node)
{
- LY_ERR rc;
+ LY_ERR r;
struct lyd_node *ret = NULL;
const struct lysc_node *schema;
+ struct lysc_ext_instance *ext = NULL;
const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
@@ -1167,10 +1198,17 @@
}
schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_TERM, output ? LYS_GETNEXT_OUTPUT : 0);
+ if (!schema && parent) {
+ r = ly_nested_ext_schema(parent, NULL, module->name, strlen(module->name), LY_VALUE_JSON, NULL, name,
+ strlen(name), &schema, &ext);
+ LY_CHECK_RET(r && (r != LY_ENOT), r);
+ }
LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Term node \"%s\" not found.", name), LY_ENOTFOUND);
- rc = lyd_create_term(schema, value, value_len, NULL, format, NULL, LYD_HINT_DATA, NULL, &ret);
- LY_CHECK_RET(rc);
+ LY_CHECK_RET(lyd_create_term(schema, value, value_len, NULL, format, NULL, LYD_HINT_DATA, NULL, &ret));
+ if (ext) {
+ ret->flags |= LYD_EXT;
+ }
if (parent) {
lyd_insert_node(parent, NULL, ret, 0);
}
@@ -1234,8 +1272,10 @@
lyd_new_any(struct lyd_node *parent, const struct lys_module *module, const char *name, const void *value,
ly_bool use_value, LYD_ANYDATA_VALUETYPE value_type, ly_bool output, struct lyd_node **node)
{
+ LY_ERR r;
struct lyd_node *ret = NULL;
const struct lysc_node *schema;
+ struct lysc_ext_instance *ext = NULL;
const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
@@ -1246,9 +1286,17 @@
}
schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_ANY, output ? LYS_GETNEXT_OUTPUT : 0);
+ if (!schema && parent) {
+ r = ly_nested_ext_schema(parent, NULL, module->name, strlen(module->name), LY_VALUE_JSON, NULL, name,
+ strlen(name), &schema, &ext);
+ LY_CHECK_RET(r && (r != LY_ENOT), r);
+ }
LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Any node \"%s\" not found.", name), LY_ENOTFOUND);
LY_CHECK_RET(lyd_create_any(schema, value, value_type, use_value, &ret));
+ if (ext) {
+ ret->flags |= LYD_EXT;
+ }
if (parent) {
lyd_insert_node(parent, NULL, ret, 0);
}
@@ -2030,6 +2078,9 @@
goto cleanup;
}
+ if (p[path_idx].ext) {
+ node->flags |= LYD_EXT;
+ }
if (cur_parent) {
/* connect to the parent */
lyd_insert_node(cur_parent, NULL, node, 0);
diff --git a/src/tree_data_helpers.c b/src/tree_data_helpers.c
index c5a0e2a..fd773ab 100644
--- a/src/tree_data_helpers.c
+++ b/src/tree_data_helpers.c
@@ -3,7 +3,7 @@
* @author Radek Krejci <rkrejci@cesnet.cz>
* @brief Parsing and validation helper functions for data trees
*
- * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
+ * Copyright (c) 2015 - 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.
@@ -29,6 +29,7 @@
#include "log.h"
#include "lyb.h"
#include "parser_data.h"
+#include "plugins_exts.h"
#include "printer_data.h"
#include "set.h"
#include "tree.h"
@@ -400,15 +401,17 @@
return LY_SUCCESS;
}
-void
-lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *node_when, struct lyd_meta **meta, uint32_t parse_opts)
+LY_ERR
+lyd_parse_set_data_flags(struct lyd_node *node, struct lyd_meta **meta, struct lyd_ctx *lydctx,
+ struct lysc_ext_instance *ext)
{
struct lyd_meta *meta2, *prev_meta = NULL;
+ struct lyd_ctx_ext_val *ext_val;
if (lysc_has_when(node->schema)) {
- if (!(parse_opts & LYD_PARSE_ONLY)) {
+ if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
/* remember we need to evaluate this node's when */
- LY_CHECK_RET(ly_set_add(node_when, node, 1, NULL), );
+ LY_CHECK_RET(ly_set_add(&lydctx->node_when, node, 1, NULL));
}
}
@@ -430,6 +433,22 @@
prev_meta = meta2;
}
+
+ if (ext) {
+ /* parsed for an extension */
+ node->flags |= LYD_EXT;
+
+ if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
+ /* rememeber for validation */
+ ext_val = malloc(sizeof *ext_val);
+ LY_CHECK_ERR_RET(!ext_val, LOGMEM(LYD_CTX(node)), LY_EMEM);
+ ext_val->ext = ext;
+ ext_val->sibling = node;
+ LY_CHECK_RET(ly_set_add(&lydctx->ext_val, ext_val, 1, NULL));
+ }
+ }
+
+ return LY_SUCCESS;
}
/**
@@ -771,6 +790,46 @@
}
}
+LY_ERR
+ly_nested_ext_schema(const struct lyd_node *parent, const struct lysc_node *sparent, const char *prefix,
+ size_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data, const char *name, size_t name_len,
+ const struct lysc_node **snode, struct lysc_ext_instance **ext)
+{
+ LY_ERR r;
+ LY_ARRAY_COUNT_TYPE u;
+ struct lysc_ext_instance *nested_exts = NULL;
+ lyplg_ext_data_snode_clb ext_snode_cb;
+
+ /* check if there are any nested extension instances */
+ if (parent && parent->schema) {
+ nested_exts = parent->schema->exts;
+ } else if (sparent) {
+ nested_exts = sparent->exts;
+ }
+ LY_ARRAY_FOR(nested_exts, u) {
+ ext_snode_cb = nested_exts[u].def->plugin->snode;
+ if (!ext_snode_cb) {
+ /* not an extension with nested data */
+ continue;
+ }
+
+ /* try to get the schema node */
+ r = ext_snode_cb(&nested_exts[u], parent, sparent, prefix, prefix_len, format, prefix_data, name, name_len, snode);
+ if (!r) {
+ /* data successfully created, remember the ext instance */
+ *ext = &nested_exts[u];
+ return LY_SUCCESS;
+ } else if (r != LY_ENOT) {
+ /* fatal error */
+ return r;
+ }
+ /* data was not from this module, continue */
+ }
+
+ /* no extensions or none matched */
+ return LY_ENOT;
+}
+
void
ly_free_prefix_data(LY_VALUE_FORMAT format, void *prefix_data)
{
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index 3cf45c6..f95c2d8 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -22,6 +22,7 @@
#include <stddef.h>
struct ly_path_predicate;
+struct lyd_ctx;
struct lysc_module;
#define LY_XML_SUFFIX ".xml"
@@ -128,11 +129,13 @@
* @brief Set data flags for a newly parsed node.
*
* @param[in] node Node to use.
- * @param[in,out] node_when Set of nodes with unresolved when.
* @param[in,out] meta Node metadata, may be removed from.
- * @param[in] parse_opts Parse options.
+ * @param[in] lydctx Data parsing context.
+ * @param[in] ext Extension instance if @p node was parsed for one.
+ * @return LY_ERR value.
*/
-void lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *node_when, struct lyd_meta **meta, uint32_t parse_opts);
+LY_ERR lyd_parse_set_data_flags(struct lyd_node *node, struct lyd_meta **meta, struct lyd_ctx *lydctx,
+ struct lysc_ext_instance *ext);
/**
* @brief Get schema node of a data node. Useful especially for opaque nodes.
@@ -153,6 +156,27 @@
void lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod);
/**
+ * @brief Try to get schema node for data with a parent based on an extension instance.
+ *
+ * @param[in] parent Parsed parent data node. Set if @p sparent is NULL.
+ * @param[in] sparent Schema parent node. Set if @p sparent is NULL.
+ * @param[in] prefix Element prefix, if any.
+ * @param[in] prefix_len Length of @p prefix.
+ * @param[in] format Format of @p prefix.
+ * @param[in] prefix_data Format-specific data.
+ * @param[in] name Element name.
+ * @param[in] name_len Length of @p name.
+ * @param[out] snode Found schema node, NULL if no suitable was found.
+ * @param[out] ext Extension instance that provided @p snode.
+ * @return LY_SUCCESS on success;
+ * @return LY_ENOT if no extension instance parsed the data;
+ * @return LY_ERR on error.
+ */
+LY_ERR ly_nested_ext_schema(const struct lyd_node *parent, const struct lysc_node *sparent, const char *prefix,
+ size_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data, const char *name, size_t name_len,
+ const struct lysc_node **snode, struct lysc_ext_instance **ext);
+
+/**
* @brief Free stored prefix data.
*
* @param[in] format Format of the prefixes.
diff --git a/src/validation.c b/src/validation.c
index 8004b44..c2c33d4 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -279,7 +279,7 @@
LY_CHECK_RET(ret);
/* remove this item from the set */
- ly_set_rm_index(node_types, i, free);
+ ly_set_rm_index(ext_val, i, free);
} while (i);
}