data FEATURE support extension's data parsing
Make the data parsers to support parsing data corresponding to a
separate schema tree specified in an extension instance.
diff --git a/src/lyb.h b/src/lyb.h
index 85ad901..30e89fd 100644
--- a/src/lyb.h
+++ b/src/lyb.h
@@ -54,6 +54,7 @@
* Note that the structure maps to the lyd_ctx which is common for all the data parsers
*/
struct lyd_lyb_ctx {
+ const struct lysc_ext_instance *ext; /**< extension instance possibly changing document root context of the data being parsed */
union {
struct {
uint32_t parse_opts; /**< various @ref dataparseroptions. */
diff --git a/src/parser_data.h b/src/parser_data.h
index 7dc3e00..16b5c0a 100644
--- a/src/parser_data.h
+++ b/src/parser_data.h
@@ -58,8 +58,11 @@
* example the *:operational* datastore is not necessarily valid and results of the NETCONF's \<get\> or \<get-config\>
* oprations used with filters will be incomplete (and thus invalid). This can be allowed using ::LYD_PARSE_ONLY,
* the ::LYD_PARSE_NO_STATE should be used for the data returned by \<get-config\> operation.
+ * - ::lyd_parse_ext_data() is used for parsing configuration data trees defined inside extension instances, such as
+ * instances of yang-data extension specified in [RFC 8040](http://tools.ietf.org/html/rfc8040).
* - ::lyd_parse_op() is used for parsing RPCs/actions, replies, and notifications. Even NETCONF rpc, rpc-reply, and
- * notification messages are supported.
+ * notification messages are supported.
+ * - ::lyd_parse_ext_op() is used for parsing RPCs/actions, replies, and notifications defined inside extension instances.
*
* Further information regarding the processing input instance data can be found on the following pages.
* - @subpage howtoDataValidation
@@ -71,7 +74,9 @@
* - ::lyd_parse_data_mem()
* - ::lyd_parse_data_fd()
* - ::lyd_parse_data_path()
+ * - ::lyd_parse_ext_data()
* - ::lyd_parse_op()
+ * - ::lyd_parse_ext_op()
*/
/**
@@ -252,6 +257,26 @@
uint32_t validate_options, struct lyd_node **tree);
/**
+ * @brief Parse (and validate) data from the input handler as a YANG data tree following the schema tree of the given
+ * extension instance.
+ *
+ * Note that the data being parsed are limited only to the schema tree specified by the given extension, it does not allow
+ * to mix them with the standard data from any module.
+ *
+ * @param[in] ext Extension instance providing the specific schema tree to match with the data being parsed.
+ * @param[in] parent Optional parent to connect the parsed nodes to.
+ * @param[in] in The input handle to provide the dumped data in the specified @p format to parse (and validate).
+ * @param[in] format Format of the input data to be parsed. Can be 0 to try to detect format from the input handler.
+ * @param[in] parse_options Options for parser, see @ref dataparseroptions.
+ * @param[in] validate_options Options for the validation phase, see @ref datavalidationoptions.
+ * @param[out] tree Full parsed data tree, note that NULL can be a valid tree. If @p parent is set, set to NULL.
+ * @return LY_SUCCESS in case of successful parsing (and validation).
+ * @return LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
+ */
+LY_ERR lyd_parse_ext_data(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
+ uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree);
+
+/**
* @ingroup datatree
* @defgroup datatype Data operation type
*
@@ -323,6 +348,47 @@
enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op);
/**
+ * @brief Parse YANG data into an operation data tree following only the specification from the given extension instance.
+ *
+ * At least one of @p parent, @p tree, or @p op must always be set.
+ *
+ * Specific @p data_type values have different parameter meaning as follows:
+ * - ::LYD_TYPE_RPC_NETCONF:
+ * - @p parent - must be NULL, the whole RPC is expected;
+ * - @p format - must be ::LYD_XML, NETCONF supports only this format;
+ * - @p tree - must be provided, all the NETCONF-specific XML envelopes will be returned here as
+ * a separate opaque data tree, even if the function fails, this may be returned;
+ * - @p op - must be provided, the RPC/action data tree itself will be returned here, pointing to the operation;
+ *
+ * - ::LYD_TYPE_NOTIF_NETCONF:
+ * - @p parent - must be NULL, the whole notification is expected;
+ * - @p format - must be ::LYD_XML, NETCONF supports only this format;
+ * - @p tree - must be provided, all the NETCONF-specific XML envelopes will be returned here as
+ * a separate opaque data tree, even if the function fails, this may be returned;
+ * - @p op - must be provided, the notification data tree itself will be returned here, pointing to the operation;
+ *
+ * - ::LYD_TYPE_REPLY_NETCONF:
+ * - @p parent - must be set, pointing to the invoked RPC operation (RPC or action) node;
+ * - @p format - must be ::LYD_XML, NETCONF supports only this format;
+ * - @p tree - must be provided, all the NETCONF-specific XML envelopes will be returned here as
+ * a separate opaque data tree, even if the function fails, this may be returned;
+ * - @p op - must be NULL, the reply is appended to the RPC;
+ * Note that there are 3 kinds of NETCONF replies - ok, error, and data. Only data reply appends any nodes to the RPC.
+ *
+ * @param[in] ext Extension instance providing the specific schema tree to match with the data being parsed.
+ * @param[in] parent Optional parent to connect the parsed nodes to.
+ * @param[in] in Input handle to read the input from.
+ * @param[in] format Expected format of the data in @p in.
+ * @param[in] data_type Expected operation to parse (@ref datatype).
+ * @param[out] tree Optional full parsed data tree. If @p parent is set, set to NULL.
+ * @param[out] op Optional parsed operation node.
+ * @return LY_ERR value.
+ * @return LY_ENOT if @p data_type is a NETCONF message and the root XML element is not the expected one.
+ */
+LY_ERR lyd_parse_ext_op(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
+ enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op);
+
+/**
* @brief Fully validate a data tree.
*
* @param[in,out] tree Data tree to recursively validate. May be changed by validation.
diff --git a/src/parser_internal.h b/src/parser_internal.h
index 282938e..98a1147 100644
--- a/src/parser_internal.h
+++ b/src/parser_internal.h
@@ -43,6 +43,7 @@
* @brief Internal (common) context for YANG data parsers.
*/
struct lyd_ctx {
+ const struct lysc_ext_instance *ext; /**< extension instance possibly changing document root context of the data being parsed */
uint32_t parse_opts; /**< various @ref dataparseroptions. */
uint32_t val_opts; /**< various @ref datavalidationoptions. */
uint32_t int_opts; /**< internal parser options */
@@ -123,6 +124,7 @@
* @brief Parse XML string as a YANG data tree.
*
* @param[in] ctx libyang context.
+ * @param[in] ext Optional extenion instance to parse data following the schema tree specified in the extension instance
* @param[in] parent Parent to connect the parsed nodes to, if any.
* @param[in,out] first_p Pointer to the first top-level parsed node, used only if @p parent is NULL.
* @param[in] in Input structure.
@@ -135,14 +137,15 @@
* @param[out] lydctx_p Data parser context to finish validation.
* @return LY_ERR value.
*/
-LY_ERR lyd_parse_xml(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
- uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type, struct lyd_node **envp, struct ly_set *parsed,
- struct lyd_ctx **lydctx_p);
+LY_ERR lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+ struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
+ struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p);
/**
* @brief Parse JSON string as a YANG data tree.
*
* @param[in] ctx libyang context.
+ * @param[in] ext Optional extenion instance to parse data following the schema tree specified in the extension instance
* @param[in] parent Parent to connect the parsed nodes to, if any.
* @param[in,out] first_p Pointer to the first top-level parsed node, used only if @p parent is NULL.
* @param[in] in Input structure.
@@ -153,13 +156,15 @@
* @param[out] lydctx_p Data parser context to finish validation.
* @return LY_ERR value.
*/
-LY_ERR lyd_parse_json(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
- uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type, struct ly_set *parsed, struct lyd_ctx **lydctx_p);
+LY_ERR lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+ struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
+ struct ly_set *parsed, struct lyd_ctx **lydctx_p);
/**
* @brief Parse binary LYB data as a YANG data tree.
*
* @param[in] ctx libyang context.
+ * @param[in] ext Optional extenion instance to parse data following the schema tree specified in the extension instance
* @param[in] parent Parent to connect the parsed nodes to, if any.
* @param[in,out] first_p Pointer to the first top-level parsed node, used only if @p parent is NULL.
* @param[in] in Input structure.
@@ -170,8 +175,9 @@
* @param[out] lydctx_p Data parser context to finish validation.
* @return LY_ERR value.
*/
-LY_ERR lyd_parse_lyb(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
- uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type, struct ly_set *parsed, struct lyd_ctx **lydctx_p);
+LY_ERR lyd_parse_lyb(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+ struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
+ struct ly_set *parsed, struct lyd_ctx **lydctx_p);
/**
* @brief Search all the parents for an operation node, check validity based on internal parser flags.
diff --git a/src/parser_json.c b/src/parser_json.c
index 37b7e68..d64745e 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -26,6 +26,7 @@
#include "json.h"
#include "log.h"
#include "parser_internal.h"
+#include "plugins_exts.h"
#include "set.h"
#include "tree.h"
#include "tree_data.h"
@@ -40,6 +41,7 @@
* Note that the structure maps to the lyd_ctx which is common for all the data parsers
*/
struct lyd_json_ctx {
+ const struct lysc_ext_instance *ext; /**< extension instance possibly changing document root context of the data being parsed */
uint32_t parse_opts; /**< various @ref dataparseroptions. */
uint32_t val_opts; /**< various @ref datavalidationoptions. */
uint32_t int_opts; /**< internal data parser options */
@@ -227,11 +229,25 @@
/* get the schema node */
if (mod && (!parent || parent->schema)) {
- *snode_p = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
+ if (!parent && lydctx->ext) {
+ *snode_p = lys_find_ext_instance_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);
+ }
if (!*snode_p) {
if (lydctx->parse_opts & LYD_PARSE_STRICT) {
- LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
- name_len, name, mod->name);
+ if (lydctx->ext) {
+ if (lydctx->ext->argument) {
+ LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
+ name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
+ } else {
+ LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
+ name_len, name, lydctx->ext->def->name);
+ }
+ } else {
+ LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
+ name_len, name, mod->name);
+ }
ret = LY_EVALID;
goto cleanup;
} else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
@@ -1369,8 +1385,9 @@
}
LY_ERR
-lyd_parse_json(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
- uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
+lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+ struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
+ struct ly_set *parsed, struct lyd_ctx **lydctx_p)
{
LY_ERR rc = LY_SUCCESS;
struct lyd_json_ctx *lydctx = NULL;
@@ -1401,6 +1418,7 @@
goto cleanup;
}
lydctx->int_opts = int_opts;
+ lydctx->ext = ext;
/* find the operation node if it exists already */
LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index 05f410c..7707dd0 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -641,7 +641,15 @@
/* find our node with matching hashes */
sibling = NULL;
- while ((sibling = lys_getnext(sibling, sparent, mod ? mod->compiled : NULL, getnext_opts))) {
+ while (1) {
+ if (!sparent && lybctx->ext) {
+ sibling = lys_getnext_ext(sibling, sparent, lybctx->ext, getnext_opts);
+ } else {
+ sibling = lys_getnext(sibling, sparent, mod ? mod->compiled : NULL, getnext_opts);
+ }
+ if (!sibling) {
+ break;
+ }
/* skip schema nodes from models not present during printing */
if (lyb_has_schema_model(sibling, lybctx->lybctx->models) &&
lyb_is_schema_hash_match((struct lysc_node *)sibling, hash, i + 1)) {
@@ -651,7 +659,10 @@
}
if (!sibling && (lybctx->parse_opts & LYD_PARSE_STRICT)) {
- if (mod) {
+ if (lybctx->ext) {
+ LOGVAL(lybctx->lybctx->ctx, LYVE_REFERENCE, "Failed to find matching hash for a node from \"%s\" extension instance node.",
+ lybctx->ext->def->name);
+ } else if (mod) {
LOGVAL(lybctx->lybctx->ctx, LYVE_REFERENCE, "Failed to find matching hash for a top-level node"
" from \"%s\".", mod->name);
} else {
@@ -1018,8 +1029,9 @@
}
LY_ERR
-lyd_parse_lyb(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
- uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
+lyd_parse_lyb(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+ struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
+ struct ly_set *parsed, struct lyd_ctx **lydctx_p)
{
LY_ERR rc = LY_SUCCESS;
struct lyd_lyb_ctx *lybctx;
@@ -1058,6 +1070,7 @@
goto cleanup;
}
lybctx->int_opts = int_opts;
+ lybctx->ext = ext;
/* find the operation node if it exists already */
LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lybctx->op_node), cleanup);
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 158bb6b..d01fdcd 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -23,6 +23,7 @@
#include "log.h"
#include "parser_data.h"
#include "parser_internal.h"
+#include "plugins_exts.h"
#include "set.h"
#include "tree_data.h"
#include "tree_data_internal.h"
@@ -36,6 +37,7 @@
* Note that the structure maps to the lyd_ctx which is common for all the data parsers
*/
struct lyd_xml_ctx {
+ const struct lysc_ext_instance *ext; /**< extension instance possibly changing document root context of the data being parsed */
uint32_t parse_opts; /**< various @ref dataparseroptions. */
uint32_t val_opts; /**< various @ref datavalidationoptions. */
uint32_t int_opts; /**< internal data parser options */
@@ -429,12 +431,24 @@
/* get the schema node */
snode = NULL;
if (mod && (!parent || parent->schema)) {
- snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
+ if (!parent && lydctx->ext) {
+ snode = lys_find_ext_instance_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);
+ }
if (!snode) {
if (lydctx->parse_opts & LYD_PARSE_STRICT) {
if (parent) {
LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.", name_len, name,
parent->schema->name);
+ } else if (lydctx->ext) {
+ if (lydctx->ext->argument) {
+ LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.", name_len, name,
+ lydctx->ext->argument, lydctx->ext->def->name);
+ } else {
+ LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.", name_len, name,
+ lydctx->ext->def->name);
+ }
} else {
LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.", name_len, name,
mod->name);
@@ -1284,9 +1298,9 @@
}
LY_ERR
-lyd_parse_xml(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
- uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type, struct lyd_node **envp, struct ly_set *parsed,
- struct lyd_ctx **lydctx_p)
+lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+ struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
+ struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
{
LY_ERR rc = LY_SUCCESS;
struct lyd_xml_ctx *lydctx;
@@ -1304,6 +1318,7 @@
lydctx->parse_opts = parse_opts;
lydctx->val_opts = val_opts;
lydctx->free = lyd_xml_ctx_free;
+ lydctx->ext = ext;
switch (data_type) {
case LYD_TYPE_DATA_YANG:
diff --git a/src/plugins_exts.h b/src/plugins_exts.h
index 3daf42d..9ad46a2 100644
--- a/src/plugins_exts.h
+++ b/src/plugins_exts.h
@@ -157,6 +157,9 @@
LY_ERR lysc_ext_substmt(const struct lysc_ext_instance *ext, enum ly_stmt substmt,
void **instance_p, enum ly_stmt_cardinality *cardinality_p);
+const struct lysc_node *lys_find_ext_instance_node(const struct lysc_ext_instance *ext, const struct lys_module *module,
+ const char *name, size_t name_len, uint16_t nodetype, uint32_t options);
+
/**
* @brief Update path in the compile context, which is used for logging where the compilation failed.
*
diff --git a/src/tree_data.c b/src/tree_data.c
index 246b6c7..60831e1 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -299,6 +299,7 @@
* @brief Parse YANG data into a data tree.
*
* @param[in] ctx libyang context.
+ * @param[in] ext Optional extenion instance to parse data following the schema tree specified in the extension instance
* @param[in] parent Parent to connect the parsed nodes to, if any.
* @param[in,out] first_p Pointer to the first top-level parsed node, used only if @p parent is NULL.
* @param[in] in Input handle to read the input from.
@@ -309,8 +310,8 @@
* @return LY_ERR value.
*/
static LY_ERR
-lyd_parse(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
- LYD_FORMAT format, uint32_t parse_opts, uint32_t val_opts, struct lyd_node **op)
+lyd_parse(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent, struct lyd_node **first_p,
+ struct ly_in *in, LYD_FORMAT format, uint32_t parse_opts, uint32_t val_opts, struct lyd_node **op)
{
LY_ERR rc = LY_SUCCESS;
struct lyd_ctx *lydctx = NULL;
@@ -331,13 +332,13 @@
/* parse the data */
switch (format) {
case LYD_XML:
- rc = lyd_parse_xml(ctx, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, NULL, &parsed, &lydctx);
+ rc = lyd_parse_xml(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, NULL, &parsed, &lydctx);
break;
case LYD_JSON:
- rc = lyd_parse_json(ctx, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed, &lydctx);
+ rc = lyd_parse_json(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed, &lydctx);
break;
case LYD_LYB:
- rc = lyd_parse_lyb(ctx, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed, &lydctx);
+ rc = lyd_parse_lyb(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed, &lydctx);
break;
case LYD_UNKNOWN:
LOGARG(ctx, format);
@@ -386,6 +387,19 @@
}
API LY_ERR
+lyd_parse_ext_data(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
+ uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree)
+{
+ const struct ly_ctx *ctx = ext ? ext->module->ctx : NULL;
+
+ LY_CHECK_ARG_RET(ctx, ext, in, parent || tree, LY_EINVAL);
+ LY_CHECK_ARG_RET(ctx, !(parse_options & ~LYD_PARSE_OPTS_MASK), LY_EINVAL);
+ LY_CHECK_ARG_RET(ctx, !(validate_options & ~LYD_VALIDATE_OPTS_MASK), LY_EINVAL);
+
+ return lyd_parse(ctx, ext, parent, tree, in, format, parse_options, validate_options, NULL);
+}
+
+API LY_ERR
lyd_parse_data(const struct ly_ctx *ctx, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree)
{
@@ -393,7 +407,7 @@
LY_CHECK_ARG_RET(ctx, !(parse_options & ~LYD_PARSE_OPTS_MASK), LY_EINVAL);
LY_CHECK_ARG_RET(ctx, !(validate_options & ~LYD_VALIDATE_OPTS_MASK), LY_EINVAL);
- return lyd_parse(ctx, parent, tree, in, format, parse_options, validate_options, NULL);
+ return lyd_parse(ctx, NULL, parent, tree, in, format, parse_options, validate_options, NULL);
}
API LY_ERR
@@ -438,9 +452,49 @@
return ret;
}
-API LY_ERR
-lyd_parse_op(const struct ly_ctx *ctx, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
- enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op)
+/**
+ * @brief Parse YANG data into an operation data tree, in case the extension instance is specified, keep the searching
+ * for schema nodes locked inside the extension instance.
+ *
+ * At least one of @p parent, @p tree, or @p op must always be set.
+ *
+ * Specific @p data_type values have different parameter meaning as follows:
+ * - ::LYD_TYPE_RPC_NETCONF:
+ * - @p parent - must be NULL, the whole RPC is expected;
+ * - @p format - must be ::LYD_XML, NETCONF supports only this format;
+ * - @p tree - must be provided, all the NETCONF-specific XML envelopes will be returned here as
+ * a separate opaque data tree, even if the function fails, this may be returned;
+ * - @p op - must be provided, the RPC/action data tree itself will be returned here, pointing to the operation;
+ *
+ * - ::LYD_TYPE_NOTIF_NETCONF:
+ * - @p parent - must be NULL, the whole notification is expected;
+ * - @p format - must be ::LYD_XML, NETCONF supports only this format;
+ * - @p tree - must be provided, all the NETCONF-specific XML envelopes will be returned here as
+ * a separate opaque data tree, even if the function fails, this may be returned;
+ * - @p op - must be provided, the notification data tree itself will be returned here, pointing to the operation;
+ *
+ * - ::LYD_TYPE_REPLY_NETCONF:
+ * - @p parent - must be set, pointing to the invoked RPC operation (RPC or action) node;
+ * - @p format - must be ::LYD_XML, NETCONF supports only this format;
+ * - @p tree - must be provided, all the NETCONF-specific XML envelopes will be returned here as
+ * a separate opaque data tree, even if the function fails, this may be returned;
+ * - @p op - must be NULL, the reply is appended to the RPC;
+ * Note that there are 3 kinds of NETCONF replies - ok, error, and data. Only data reply appends any nodes to the RPC.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] ext Extension instance providing the specific schema tree to match with the data being parsed.
+ * @param[in] parent Optional parent to connect the parsed nodes to.
+ * @param[in] in Input handle to read the input from.
+ * @param[in] format Expected format of the data in @p in.
+ * @param[in] data_type Expected operation to parse (@ref datatype).
+ * @param[out] tree Optional full parsed data tree. If @p parent is set, set to NULL.
+ * @param[out] op Optional parsed operation node.
+ * @return LY_ERR value.
+ * @return LY_ENOT if @p data_type is a NETCONF message and the root XML element is not the expected one.
+ */
+static LY_ERR
+lyd_parse_op_(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+ struct ly_in *in, LYD_FORMAT format, enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op)
{
LY_ERR rc = LY_SUCCESS;
struct lyd_ctx *lydctx = NULL;
@@ -448,7 +502,6 @@
struct lyd_node *first = NULL, *envp = NULL;
uint32_t i, parse_opts, val_opts;
- LY_CHECK_ARG_RET(ctx, ctx || parent, in, data_type, parent || tree || op, LY_EINVAL);
if (!ctx) {
ctx = LYD_CTX(parent);
}
@@ -477,7 +530,7 @@
/* parse the data */
switch (format) {
case LYD_XML:
- rc = lyd_parse_xml(ctx, parent, &first, in, parse_opts, val_opts, data_type, &envp, &parsed, &lydctx);
+ rc = lyd_parse_xml(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &envp, &parsed, &lydctx);
if (rc && envp) {
/* special situation when the envelopes were parsed successfully */
if (tree) {
@@ -488,10 +541,10 @@
}
break;
case LYD_JSON:
- rc = lyd_parse_json(ctx, parent, &first, in, parse_opts, val_opts, data_type, &parsed, &lydctx);
+ rc = lyd_parse_json(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &parsed, &lydctx);
break;
case LYD_LYB:
- rc = lyd_parse_lyb(ctx, parent, &first, in, parse_opts, val_opts, data_type, &parsed, &lydctx);
+ rc = lyd_parse_lyb(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &parsed, &lydctx);
break;
case LYD_UNKNOWN:
LOGARG(ctx, format);
@@ -538,6 +591,26 @@
return rc;
}
+API LY_ERR
+lyd_parse_op(const struct ly_ctx *ctx, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
+ enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op)
+{
+ LY_CHECK_ARG_RET(ctx, ctx || parent, in, data_type, parent || tree || op, LY_EINVAL);
+
+ return lyd_parse_op_(ctx, NULL, parent, in, format, data_type, tree, op);
+}
+
+API LY_ERR
+lyd_parse_ext_op(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
+ enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op)
+{
+ const struct ly_ctx *ctx = ext ? ext->module->ctx : NULL;
+
+ LY_CHECK_ARG_RET(ctx, ext, in, data_type, parent || tree || op, LY_EINVAL);
+
+ return lyd_parse_op_(ctx, ext, parent, in, format, data_type, tree, op);
+}
+
LY_ERR
lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_len, ly_bool *dynamic,
LY_PREFIX_FORMAT format, void *prefix_data, uint32_t hints, ly_bool *incomplete, struct lyd_node **node)
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 9a6e3ff..4470fbe 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -400,6 +400,39 @@
return lys_getnext_(last, parent, NULL, ext, options);
}
+const struct lysc_node *
+lys_find_ext_instance_node(const struct lysc_ext_instance *ext, const struct lys_module *module, const char *name, size_t name_len,
+ uint16_t nodetype, uint32_t options)
+{
+ const struct lysc_node *node = NULL;
+
+ LY_CHECK_ARG_RET(NULL, ext, name, NULL);
+ if (!nodetype) {
+ nodetype = LYS_NODETYPE_MASK;
+ }
+
+ if (module && (module != ext->module)) {
+ return NULL;
+ }
+
+ while ((node = lys_getnext_ext(node, NULL, ext, options))) {
+ if (!(node->nodetype & nodetype)) {
+ continue;
+ }
+
+ if (name_len) {
+ if (!ly_strncmp(node->name, name, name_len)) {
+ return node;
+ }
+ } else {
+ if (!strcmp(node->name, name)) {
+ return node;
+ }
+ }
+ }
+ return NULL;
+}
+
API const struct lysc_node *
lys_find_child(const struct lysc_node *parent, const struct lys_module *module, const char *name, size_t name_len,
uint16_t nodetype, uint32_t options)