parser UPDATE anydata is an inner node
diff --git a/src/parser_common.c b/src/parser_common.c
index 072a4e7..a5daeb7 100644
--- a/src/parser_common.c
+++ b/src/parser_common.c
@@ -88,22 +88,24 @@
return LY_SUCCESS;
}
- if (!(int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY))) {
- LOGERR(LYD_CTX(parent), LY_EINVAL, "Invalid parent %s \"%s\" node when not parsing any operation.",
- lys_nodetype2str(iter->schema->nodetype), iter->schema->name);
- return LY_EINVAL;
- } else if ((iter->schema->nodetype == LYS_RPC) && !(int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_REPLY))) {
- LOGERR(LYD_CTX(parent), LY_EINVAL, "Invalid parent RPC \"%s\" node when not parsing RPC nor rpc-reply.",
- iter->schema->name);
- return LY_EINVAL;
- } else if ((iter->schema->nodetype == LYS_ACTION) && !(int_opts & (LYD_INTOPT_ACTION | LYD_INTOPT_REPLY))) {
- LOGERR(LYD_CTX(parent), LY_EINVAL, "Invalid parent action \"%s\" node when not parsing action nor rpc-reply.",
- iter->schema->name);
- return LY_EINVAL;
- } else if ((iter->schema->nodetype == LYS_NOTIF) && !(int_opts & LYD_INTOPT_NOTIF)) {
- LOGERR(LYD_CTX(parent), LY_EINVAL, "Invalid parent notification \"%s\" node when not parsing a notification.",
- iter->schema->name);
- return LY_EINVAL;
+ if (!(int_opts & LYD_INTOPT_ANY)) {
+ if (!(int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY))) {
+ LOGERR(LYD_CTX(parent), LY_EINVAL, "Invalid parent %s \"%s\" node when not parsing any operation.",
+ lys_nodetype2str(iter->schema->nodetype), iter->schema->name);
+ return LY_EINVAL;
+ } else if ((iter->schema->nodetype == LYS_RPC) && !(int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_REPLY))) {
+ LOGERR(LYD_CTX(parent), LY_EINVAL, "Invalid parent RPC \"%s\" node when not parsing RPC nor rpc-reply.",
+ iter->schema->name);
+ return LY_EINVAL;
+ } else if ((iter->schema->nodetype == LYS_ACTION) && !(int_opts & (LYD_INTOPT_ACTION | LYD_INTOPT_REPLY))) {
+ LOGERR(LYD_CTX(parent), LY_EINVAL, "Invalid parent action \"%s\" node when not parsing action nor rpc-reply.",
+ iter->schema->name);
+ return LY_EINVAL;
+ } else if ((iter->schema->nodetype == LYS_NOTIF) && !(int_opts & LYD_INTOPT_NOTIF)) {
+ LOGERR(LYD_CTX(parent), LY_EINVAL, "Invalid parent notification \"%s\" node when not parsing a notification.",
+ iter->schema->name);
+ return LY_EINVAL;
+ }
}
*op = (struct lyd_node *)iter;
diff --git a/src/parser_internal.h b/src/parser_internal.h
index 4863145..458d297 100644
--- a/src/parser_internal.h
+++ b/src/parser_internal.h
@@ -227,17 +227,36 @@
* @param[in] in Input structure.
* @param[in] parse_opts Options for parser, see @ref dataparseroptions.
* @param[in] val_opts Options for the validation phase, see @ref datavalidationoptions.
- * @param[in] data_type Expected data type of the data.
- * @param[out] envp Individual parsed envelopes tree, returned only by specific @p data_type and possibly even if
- * an error occurs later.
+ * @param[in] int_opts Internal data parser options.
* @param[out] parsed Set to add all the parsed siblings into.
* @param[out] subtree_sibling Set if ::LYD_PARSE_SUBTREE is used and another subtree is following in @p in.
* @param[out] lydctx_p Data parser context to finish validation.
* @return LY_ERR value.
*/
LY_ERR lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+ struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, uint32_t int_opts,
+ struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p);
+
+/**
+ * @brief Parse XML string as a NETCONF message.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] ext Optional extension 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.
+ * @param[in] parse_opts Options for parser, see @ref dataparseroptions.
+ * @param[in] val_opts Options for the validation phase, see @ref datavalidationoptions.
+ * @param[in] data_type Expected NETCONF data type of the data.
+ * @param[out] envp Individual parsed envelopes tree, may be returned possibly even on an error.
+ * @param[out] parsed Set to add all the parsed siblings into.
+ * @param[out] subtree_sibling Set if ::LYD_PARSE_SUBTREE is used and another subtree is following in @p in.
+ * @param[out] lydctx_p Data parser context to finish validation.
+ * @return LY_ERR value.
+ */
+LY_ERR lyd_parse_xml_netconf(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, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p);
+ struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p);
/**
* @brief Parse JSON string as a YANG data tree.
@@ -249,14 +268,14 @@
* @param[in] in Input structure.
* @param[in] parse_opts Options for parser, see @ref dataparseroptions.
* @param[in] val_opts Options for the validation phase, see @ref datavalidationoptions.
- * @param[in] data_type Expected data type of the data.
+ * @param[in] int_opts Internal data parser options.
* @param[out] parsed Set to add all the parsed siblings into.
* @param[out] subtree_sibling Set if ::LYD_PARSE_SUBTREE is used and another subtree is following in @p in.
* @param[out] lydctx_p Data parser context to finish validation.
* @return LY_ERR value.
*/
LY_ERR lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
- struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
+ struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, uint32_t int_opts,
struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p);
/**
@@ -269,14 +288,14 @@
* @param[in] in Input structure.
* @param[in] parse_opts Options for parser, see @ref dataparseroptions.
* @param[in] val_opts Options for the validation phase, see @ref datavalidationoptions.
- * @param[in] data_type Expected data type of the data.
+ * @param[in] int_opts Internal data parser options.
* @param[out] parsed Set to add all the parsed siblings into.
* @param[out] subtree_sibling Set if ::LYD_PARSE_SUBTREE is used and another subtree is following in @p in.
* @param[out] lydctx_p Data parser context to finish validation.
* @return LY_ERR value.
*/
LY_ERR lyd_parse_lyb(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
- struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
+ struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, uint32_t int_opts,
struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p);
/**
diff --git a/src/parser_json.c b/src/parser_json.c
index 341fd7e..d14151e 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -259,7 +259,7 @@
if (parent->schema) {
mod = parent->schema->module;
}
- } else {
+ } else if (!(lydctx->int_opts & LYD_INTOPT_ANY)) {
LOGVAL(lydctx->jsonctx->ctx, LYVE_SYNTAX_JSON, "Top-level JSON object member \"%.*s\" must be namespace-qualified.",
(int)(is_attr ? name_len + 1 : name_len), is_attr ? name - 1 : name);
ret = LY_EVALID;
@@ -1216,17 +1216,7 @@
(*status != LYJSON_NUMBER) && (*status != LYJSON_STRING) && (*status != LYJSON_FALSE) &&
(*status != LYJSON_TRUE) && (*status != LYJSON_NULL), LY_ENOT);
} else {
- LY_CHECK_RET((*status != LYJSON_OBJECT) && (*status != LYJSON_OBJECT_EMPTY) && (*status != LYJSON_ARRAY), LY_ENOT);
- }
-
- if ((snode->nodetype == LYS_ANYDATA) && (*status == LYJSON_ARRAY)) {
- /* only special anydata [null] allowed, 2 more moves are needed */
- LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status));
- LY_CHECK_RET(*status != LYJSON_NULL, LY_ENOT);
- LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status));
- LY_CHECK_RET(*status != LYJSON_ARRAY_CLOSED, LY_ENOT);
-
- return lyd_create_any(snode, "[null]", LYD_ANYDATA_JSON, 0, node);
+ LY_CHECK_RET((*status != LYJSON_OBJECT) && (*status != LYJSON_OBJECT_EMPTY), LY_ENOT);
}
/* create any node */
@@ -1597,7 +1587,7 @@
case LYS_RPC:
case LYS_ANYDATA:
case LYS_ANYXML:
- if (snode->nodetype & (LYS_LEAF | LYS_ANYXML)) {
+ if ((snode->nodetype == LYS_LEAF) || (snode->nodetype == LYS_ANYXML)) {
if (status == LYJSON_ARRAY) {
expected = "name/[null]";
} else {
@@ -1707,39 +1697,18 @@
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 lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, uint32_t int_opts,
struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
{
LY_ERR rc = LY_SUCCESS;
struct lyd_json_ctx *lydctx = NULL;
enum LYJSON_PARSER_STATUS status;
- uint32_t int_opts = 0;
rc = lyd_parse_json_init(ctx, in, parse_opts, val_opts, &lydctx, &status);
LY_CHECK_GOTO(rc || status == LYJSON_END || status == LYJSON_OBJECT_EMPTY, cleanup);
assert(status == LYJSON_OBJECT);
- switch (data_type) {
- case LYD_TYPE_DATA_YANG:
- if (!(parse_opts & LYD_PARSE_SUBTREE)) {
- int_opts = LYD_INTOPT_WITH_SIBLINGS;
- }
- break;
- case LYD_TYPE_RPC_YANG:
- int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
- break;
- case LYD_TYPE_NOTIF_YANG:
- int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
- break;
- case LYD_TYPE_REPLY_YANG:
- int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
- break;
- default:
- LOGINT(ctx);
- rc = LY_EINT;
- goto cleanup;
- }
lydctx->int_opts = int_opts;
lydctx->ext = ext;
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index 2201269..58e76b2 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -41,10 +41,6 @@
#include "validation.h"
#include "xml.h"
-static 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, uint32_t int_opts,
- struct ly_set *parsed, struct lyd_ctx **lydctx_p);
-
static LY_ERR lyb_parse_siblings(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, struct lyd_node **first_p,
struct ly_set *parsed);
@@ -908,46 +904,6 @@
}
/**
- * @brief Parse the context of anydata/anyxml node.
- *
- * @param[in] ctx libyang context.
- * @param[in] data LYB data to parse.
- * @param[out] tree Parsed tree.
- * @return LY_ERR value.
- */
-static LY_ERR
-lyb_parse_any_content(const struct ly_ctx *ctx, const char *data, struct lyd_node **tree)
-{
- LY_ERR ret;
- uint32_t prev_lo;
- struct ly_in *in;
- struct lyd_ctx *lydctx = NULL;
-
- *tree = NULL;
-
- LY_CHECK_RET(ly_in_new_memory(data, &in));
-
- /* turn logging off */
- prev_lo = ly_log_options(0);
-
- ret = _lyd_parse_lyb(ctx, NULL, NULL, tree, in, LYD_PARSE_ONLY | LYD_PARSE_OPAQ | LYD_PARSE_STRICT, 0,
- LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS, NULL, &lydctx);
-
- /* turn logging on again */
- ly_log_options(prev_lo);
-
- ly_in_free(in, 0);
- if (lydctx) {
- lydctx->free(lydctx);
- }
- if (ret) {
- lyd_free_siblings(*tree);
- *tree = NULL;
- }
- return ret;
-}
-
-/**
* @brief Insert new node to @p parsed set.
*
* Also if needed, correct @p first_p.
@@ -1243,9 +1199,11 @@
struct lyd_node **first_p, struct ly_set *parsed)
{
LY_ERR ret;
- struct lyd_node *node = NULL, *tree;
+ struct lyd_node *node = NULL, *tree = NULL;
struct lyd_meta *meta = NULL;
LYD_ANYDATA_VALUETYPE value_type;
+ struct ly_in *in;
+ struct lyd_ctx *lydctx = NULL;
char *value = NULL;
uint32_t flags;
const struct ly_ctx *ctx = lybctx->lybctx->ctx;
@@ -1256,8 +1214,7 @@
/* parse value type */
lyb_read_number(&value_type, sizeof value_type, sizeof value_type, lybctx->lybctx);
- if (value_type == LYD_ANYDATA_DATATREE) {
- /* invalid situation */
+ if ((value_type == LYD_ANYDATA_DATATREE) || ((snode->nodetype == LYS_ANYDATA) && (value_type != LYD_ANYDATA_LYB))) {
LOGINT(ctx);
ret = LY_EINT;
goto error;
@@ -1268,13 +1225,20 @@
LY_CHECK_GOTO(ret, error);
if (value_type == LYD_ANYDATA_LYB) {
- /* try to parse LYB into a data tree */
- if (!lyb_parse_any_content(ctx, value, &tree)) {
- /* successfully parsed */
- free(value);
- value = (char *)tree;
- value_type = LYD_ANYDATA_DATATREE;
+ /* parse LYB into a data tree */
+ LY_CHECK_RET(ly_in_new_memory(value, &in));
+ ret = lyd_parse_lyb(ctx, NULL, NULL, &tree, in, LYD_PARSE_ONLY | LYD_PARSE_OPAQ | LYD_PARSE_STRICT, 0,
+ LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS, NULL, NULL, &lydctx);
+ ly_in_free(in, 0);
+ if (lydctx) {
+ lydctx->free(lydctx);
}
+ LY_CHECK_ERR_GOTO(ret, lyd_free_siblings(tree), error);
+
+ /* use the parsed tree as the value */
+ free(value);
+ value = (char *)tree;
+ value_type = LYD_ANYDATA_DATATREE;
}
/* create the node */
@@ -1672,10 +1636,10 @@
return LY_SUCCESS;
}
-static LY_ERR
-_lyd_parse_lyb(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+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, uint32_t int_opts,
- struct ly_set *parsed, struct lyd_ctx **lydctx_p)
+ struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
{
LY_ERR rc = LY_SUCCESS;
struct lyd_lyb_ctx *lybctx;
@@ -1683,6 +1647,12 @@
assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
+ LY_CHECK_ARG_RET(ctx, !(parse_opts & LYD_PARSE_SUBTREE), LY_EINVAL);
+
+ if (subtree_sibling) {
+ *subtree_sibling = 0;
+ }
+
lybctx = calloc(1, sizeof *lybctx);
LY_CHECK_ERR_RET(!lybctx, LOGMEM(ctx), LY_EMEM);
lybctx->lybctx = calloc(1, sizeof *lybctx->lybctx);
@@ -1742,42 +1712,6 @@
return rc;
}
-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, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
-{
- uint32_t int_opts;
-
- assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
- assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
-
- LY_CHECK_ARG_RET(ctx, !(parse_opts & LYD_PARSE_SUBTREE), LY_EINVAL);
-
- switch (data_type) {
- case LYD_TYPE_DATA_YANG:
- int_opts = LYD_INTOPT_WITH_SIBLINGS;
- break;
- case LYD_TYPE_RPC_YANG:
- int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
- break;
- case LYD_TYPE_NOTIF_YANG:
- int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
- break;
- case LYD_TYPE_REPLY_YANG:
- int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
- break;
- default:
- LOGINT(ctx);
- return LY_EINT;
- }
-
- if (subtree_sibling) {
- *subtree_sibling = 0;
- }
- return _lyd_parse_lyb(ctx, ext, parent, first_p, in, parse_opts, val_opts, int_opts, parsed, lydctx_p);
-}
-
LIBYANG_API_DEF int
lyd_lyb_data_length(const char *data)
{
diff --git a/src/parser_xml.c b/src/parser_xml.c
index ff91715..ba707f6 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -968,6 +968,87 @@
return rc;
}
+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, uint32_t int_opts,
+ struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
+{
+ LY_ERR rc = LY_SUCCESS;
+ struct lyd_xml_ctx *lydctx;
+ ly_bool parsed_data_nodes = 0;
+ enum LYXML_PARSER_STATUS status;
+
+ assert(ctx && in && lydctx_p);
+ assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
+ assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
+
+ /* init context */
+ lydctx = calloc(1, sizeof *lydctx);
+ LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
+ LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
+ lydctx->parse_opts = parse_opts;
+ lydctx->val_opts = val_opts;
+ lydctx->int_opts = int_opts;
+ lydctx->free = lyd_xml_ctx_free;
+ 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);
+
+ /* parse XML data */
+ while (lydctx->xmlctx->status == LYXML_ELEMENT) {
+ LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
+ parsed_data_nodes = 1;
+
+ if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
+ break;
+ }
+ }
+
+ /* check final state */
+ if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
+ LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
+ rc = LY_EVALID;
+ goto cleanup;
+ }
+ if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
+ LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
+ rc = LY_EVALID;
+ goto cleanup;
+ }
+
+ if (!parsed_data_nodes) {
+ /* no data nodes were parsed */
+ lydctx->op_node = NULL;
+ }
+
+ if (parse_opts & LYD_PARSE_SUBTREE) {
+ /* check for a sibling element */
+ assert(subtree_sibling);
+ if (!lyxml_ctx_peek(lydctx->xmlctx, &status) && (status == LYXML_ELEMENT)) {
+ *subtree_sibling = 1;
+ } else {
+ *subtree_sibling = 0;
+ }
+ }
+
+cleanup:
+ /* there should be no unres stored if validation should be skipped */
+ assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
+ !lydctx->node_when.count));
+
+ if (rc) {
+ lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
+ } else {
+ *lydctx_p = (struct lyd_ctx *)lydctx;
+
+ /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
+ lyxml_ctx_free(lydctx->xmlctx);
+ lydctx->xmlctx = NULL;
+ }
+ return rc;
+}
+
/**
* @brief Parse all expected non-data XML elements of a NETCONF rpc message.
*
@@ -1601,20 +1682,23 @@
}
LY_ERR
-lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+lyd_parse_xml_netconf(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, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
+ struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
{
LY_ERR rc = LY_SUCCESS;
struct lyd_xml_ctx *lydctx;
uint32_t i, int_opts = 0, close_elem = 0;
ly_bool parsed_data_nodes = 0;
- enum LYXML_PARSER_STATUS status;
assert(ctx && in && lydctx_p);
assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
+ assert((data_type == LYD_TYPE_RPC_NETCONF) || (data_type == LYD_TYPE_NOTIF_NETCONF) ||
+ (data_type == LYD_TYPE_REPLY_NETCONF));
+ assert(!(parse_opts & LYD_PARSE_SUBTREE));
+
/* init context */
lydctx = calloc(1, sizeof *lydctx);
LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
@@ -1625,20 +1709,6 @@
lydctx->ext = ext;
switch (data_type) {
- case LYD_TYPE_DATA_YANG:
- if (!(parse_opts & LYD_PARSE_SUBTREE)) {
- int_opts = LYD_INTOPT_WITH_SIBLINGS;
- }
- break;
- case LYD_TYPE_RPC_YANG:
- int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
- break;
- case LYD_TYPE_NOTIF_YANG:
- int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
- break;
- case LYD_TYPE_REPLY_YANG:
- int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
- break;
case LYD_TYPE_RPC_NETCONF:
assert(!parent);
rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem);
@@ -1663,7 +1733,12 @@
}
LY_CHECK_GOTO(rc, cleanup);
break;
+ default:
+ LOGINT(ctx);
+ rc = LY_EINT;
+ goto cleanup;
}
+
lydctx->int_opts = int_opts;
/* find the operation node if it exists already */
@@ -1709,16 +1784,6 @@
lydctx->op_node = NULL;
}
- if (parse_opts & LYD_PARSE_SUBTREE) {
- /* check for a sibling element */
- assert(subtree_sibling);
- if (!lyxml_ctx_peek(lydctx->xmlctx, &status) && (status == LYXML_ELEMENT)) {
- *subtree_sibling = 1;
- } else {
- *subtree_sibling = 0;
- }
- }
-
cleanup:
/* there should be no unres stored if validation should be skipped */
assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
diff --git a/src/printer_json.c b/src/printer_json.c
index 3c7a6fd..6cfd330 100644
--- a/src/printer_json.c
+++ b/src/printer_json.c
@@ -537,6 +537,10 @@
assert(any->schema->nodetype & LYD_NODE_ANY);
+ if ((any->schema->nodetype == LYS_ANYDATA) && (any->value_type != LYD_ANYDATA_DATATREE)) {
+ LOGINT_RET(pctx->ctx);
+ }
+
if (any->value_type == LYD_ANYDATA_LYB) {
uint32_t parser_options = LYD_PARSE_ONLY | LYD_PARSE_OPAQ | LYD_PARSE_STRICT;
@@ -605,7 +609,7 @@
}
} else {
/* print as a string */
- ly_print_(pctx->out, "\"%s\"", any->value.str);
+ json_print_string(pctx->out, any->value.str);
}
break;
case LYD_ANYDATA_LYB:
diff --git a/src/printer_lyb.c b/src/printer_lyb.c
index 62902de..7928262 100644
--- a/src/printer_lyb.c
+++ b/src/printer_lyb.c
@@ -1054,8 +1054,12 @@
struct ly_out *out2 = NULL;
struct lylyb_ctx *lybctx = lyd_lybctx->lybctx;
+ if ((anydata->schema->nodetype == LYS_ANYDATA) && (anydata->value_type != LYD_ANYDATA_DATATREE)) {
+ LOGINT_RET(lybctx->ctx);
+ }
+
if (anydata->value_type == LYD_ANYDATA_DATATREE) {
- /* will be printed as a nested LYB data tree */
+ /* will be printed as a nested LYB data tree because the used modules need to be written */
value_type = LYD_ANYDATA_LYB;
} else {
value_type = anydata->value_type;
diff --git a/src/printer_xml.c b/src/printer_xml.c
index 058bc44..c7a6c85 100644
--- a/src/printer_xml.c
+++ b/src/printer_xml.c
@@ -388,6 +388,10 @@
uint32_t prev_opts, prev_lo;
LY_ERR ret;
+ if ((node->schema->nodetype == LYS_ANYDATA) && (node->value_type != LYD_ANYDATA_DATATREE)) {
+ LOGINT_RET(pctx->ctx);
+ }
+
xml_print_node_open(pctx, &node->node);
if (!any->value.tree) {
diff --git a/src/tree_data.c b/src/tree_data.c
index a082d8a..e3d7ac9 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -1,9 +1,10 @@
/**
* @file tree_data.c
* @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
* @brief Data tree functions
*
- * Copyright (c) 2015 - 2020 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.
@@ -99,7 +100,7 @@
struct lyd_ctx *lydctx = NULL;
struct ly_set parsed = {0};
struct lyd_node *first;
- uint32_t i;
+ uint32_t i, int_opts = 0;
ly_bool subtree_sibling = 0;
assert(ctx && (parent || first_p));
@@ -112,18 +113,23 @@
/* remember input position */
in->func_start = in->current;
+ /* set internal options */
+ if (!(parse_opts & LYD_PARSE_SUBTREE)) {
+ int_opts = LYD_INTOPT_WITH_SIBLINGS;
+ }
+
/* parse the data */
switch (format) {
case LYD_XML:
- rc = lyd_parse_xml(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, NULL, &parsed,
+ rc = lyd_parse_xml(ctx, ext, parent, first_p, in, parse_opts, val_opts, int_opts, &parsed,
&subtree_sibling, &lydctx);
break;
case LYD_JSON:
- rc = lyd_parse_json(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed,
+ rc = lyd_parse_json(ctx, ext, parent, first_p, in, parse_opts, val_opts, int_opts, &parsed,
&subtree_sibling, &lydctx);
break;
case LYD_LYB:
- rc = lyd_parse_lyb(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed,
+ rc = lyd_parse_lyb(ctx, ext, parent, first_p, in, parse_opts, val_opts, int_opts, &parsed,
&subtree_sibling, &lydctx);
break;
case LYD_UNKNOWN:
@@ -288,7 +294,7 @@
struct lyd_ctx *lydctx = NULL;
struct ly_set parsed = {0};
struct lyd_node *first = NULL, *envp = NULL;
- uint32_t i, parse_opts, val_opts;
+ uint32_t i, parse_opts, val_opts, int_opts = 0;
if (!ctx) {
ctx = LYD_CTX(parent);
@@ -305,20 +311,25 @@
/* remember input position */
in->func_start = in->current;
- /* check params based on the data type */
- if ((data_type == LYD_TYPE_RPC_NETCONF) || (data_type == LYD_TYPE_NOTIF_NETCONF)) {
- LY_CHECK_ARG_RET(ctx, format == LYD_XML, !parent, tree, op, LY_EINVAL);
- } else if (data_type == LYD_TYPE_REPLY_NETCONF) {
- LY_CHECK_ARG_RET(ctx, format == LYD_XML, parent, parent->schema->nodetype & (LYS_RPC | LYS_ACTION), tree, !op,
- LY_EINVAL);
- }
+ /* set parse and validation opts */
parse_opts = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
val_opts = 0;
- /* parse the data */
- switch (format) {
- case LYD_XML:
- rc = lyd_parse_xml(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &envp, &parsed, NULL, &lydctx);
+ switch (data_type) {
+
+ /* special XML NETCONF data types */
+ case LYD_TYPE_RPC_NETCONF:
+ case LYD_TYPE_NOTIF_NETCONF:
+ LY_CHECK_ARG_RET(ctx, format == LYD_XML, !parent, tree, op, LY_EINVAL);
+ /* fallthrough */
+ case LYD_TYPE_REPLY_NETCONF:
+ if (data_type == LYD_TYPE_REPLY_NETCONF) {
+ LY_CHECK_ARG_RET(ctx, format == LYD_XML, parent, parent->schema->nodetype & (LYS_RPC | LYS_ACTION), tree, !op,
+ LY_EINVAL);
+ }
+
+ /* parse the NETCONF message */
+ rc = lyd_parse_xml_netconf(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) {
@@ -328,12 +339,47 @@
}
goto cleanup;
}
+
+ /* set out params correctly */
+ if (tree) {
+ if (envp) {
+ /* special out param meaning */
+ *tree = envp;
+ } else {
+ *tree = parent ? NULL : first;
+ }
+ }
+ if (op) {
+ *op = lydctx->op_node;
+ }
+ goto cleanup;
+
+ /* set internal opts */
+ case LYD_TYPE_RPC_YANG:
+ int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
+ break;
+ case LYD_TYPE_NOTIF_YANG:
+ int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
+ break;
+ case LYD_TYPE_REPLY_YANG:
+ int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
+ break;
+ case LYD_TYPE_DATA_YANG:
+ LOGINT(ctx);
+ rc = LY_EINT;
+ goto cleanup;
+ }
+
+ /* parse the data */
+ switch (format) {
+ case LYD_XML:
+ rc = lyd_parse_xml(ctx, ext, parent, &first, in, parse_opts, val_opts, int_opts, &parsed, NULL, &lydctx);
break;
case LYD_JSON:
- rc = lyd_parse_json(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &parsed, NULL, &lydctx);
+ rc = lyd_parse_json(ctx, ext, parent, &first, in, parse_opts, val_opts, int_opts, &parsed, NULL, &lydctx);
break;
case LYD_LYB:
- rc = lyd_parse_lyb(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &parsed, NULL, &lydctx);
+ rc = lyd_parse_lyb(ctx, ext, parent, &first, in, parse_opts, val_opts, int_opts, &parsed, NULL, &lydctx);
break;
case LYD_UNKNOWN:
LOGARG(ctx, format);
@@ -344,12 +390,7 @@
/* set out params correctly */
if (tree) {
- if (envp) {
- /* special out param meaning */
- *tree = envp;
- } else {
- *tree = parent ? NULL : first;
- }
+ *tree = parent ? NULL : first;
}
if (op) {
*op = lydctx->op_node;
diff --git a/src/tree_data_new.c b/src/tree_data_new.c
index b4fb4d6..42b9e9b 100644
--- a/src/tree_data_new.c
+++ b/src/tree_data_new.c
@@ -195,11 +195,85 @@
return ret;
}
+/**
+ * @brief Convert an anydata value into a datatree.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] value Anydata value.
+ * @param[in] value_type Anydata @p value type.
+ * @param[out] tree Parsed data tree.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyd_create_anydata_datatree(const struct ly_ctx *ctx, const void *value, LYD_ANYDATA_VALUETYPE value_type,
+ struct lyd_node **tree)
+{
+ LY_ERR r;
+ struct ly_in *in = NULL;
+ struct lyd_ctx *lydctx = NULL;
+ uint32_t parse_opts, int_opts;
+
+ *tree = NULL;
+
+ if (!value) {
+ /* empty data tree no matter the value type */
+ return LY_SUCCESS;
+ }
+
+ if (value_type == LYD_ANYDATA_STRING) {
+ /* detect format */
+ if (((char *)value)[0] == '<') {
+ value_type = LYD_ANYDATA_XML;
+ } else if (((char *)value)[0] == '{') {
+ value_type = LYD_ANYDATA_JSON;
+ } else if (!strncmp(value, "lyb", 3)) {
+ value_type = LYD_ANYDATA_LYB;
+ } else {
+ LOGERR(ctx, LY_EINVAL, "Invalid string value of an anydata node.");
+ return LY_EINVAL;
+ }
+ }
+
+ /* create input */
+ LY_CHECK_RET(ly_in_new_memory(value, &in));
+
+ /* set options */
+ parse_opts = LYD_PARSE_ONLY | LYD_PARSE_OPAQ;
+ int_opts = LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
+
+ switch (value_type) {
+ case LYD_ANYDATA_DATATREE:
+ case LYD_ANYDATA_STRING:
+ /* unreachable */
+ LOGINT_RET(ctx);
+ case LYD_ANYDATA_XML:
+ r = lyd_parse_xml(ctx, NULL, NULL, tree, in, parse_opts, 0, int_opts, NULL, NULL, &lydctx);
+ break;
+ case LYD_ANYDATA_JSON:
+ r = lyd_parse_json(ctx, NULL, NULL, tree, in, parse_opts, 0, int_opts, NULL, NULL, &lydctx);
+ break;
+ case LYD_ANYDATA_LYB:
+ r = lyd_parse_lyb(ctx, NULL, NULL, tree, in, parse_opts | LYD_PARSE_STRICT, 0, int_opts, NULL, NULL, &lydctx);
+ break;
+ }
+ if (lydctx) {
+ lydctx->free(lydctx);
+ }
+ ly_in_free(in, 0);
+
+ if (r) {
+ LOGERR(ctx, LY_EINVAL, "Failed to parse anydata content into a data tree.");
+ return LY_EINVAL;
+ }
+ return LY_SUCCESS;
+}
+
LY_ERR
lyd_create_any(const struct lysc_node *schema, const void *value, LYD_ANYDATA_VALUETYPE value_type, ly_bool use_value,
struct lyd_node **node)
{
LY_ERR ret;
+ struct lyd_node *tree;
struct lyd_node_any *any;
union lyd_any_value any_val;
@@ -212,6 +286,17 @@
any->prev = &any->node;
any->flags = LYD_NEW;
+ if ((schema->nodetype == LYS_ANYDATA) && (value_type != LYD_ANYDATA_DATATREE)) {
+ /* only a data tree can be stored */
+ LY_CHECK_RET(lyd_create_anydata_datatree(schema->module->ctx, value, value_type, &tree));
+ if (use_value) {
+ free((void *)value);
+ }
+ use_value = 1;
+ value = tree;
+ value_type = LYD_ANYDATA_DATATREE;
+ }
+
if (use_value) {
switch (value_type) {
case LYD_ANYDATA_DATATREE:
diff --git a/tests/utests/data/test_new.c b/tests/utests/data/test_new.c
index b55172f..7cb7ebd 100644
--- a/tests/utests/data/test_new.c
+++ b/tests/utests/data/test_new.c
@@ -153,7 +153,7 @@
CHECK_LOG_CTX("Inner node (container, notif, RPC, or action) \"l2\" not found.", NULL);
/* anydata */
- assert_int_equal(lyd_new_any(NULL, mod, "any", "some-value", 0, LYD_ANYDATA_STRING, 0, &node), LY_SUCCESS);
+ assert_int_equal(lyd_new_any(NULL, mod, "any", "{\"node\":\"val\"}", 0, LYD_ANYDATA_STRING, 0, &node), LY_SUCCESS);
lyd_free_tree(node);
/* key-less list */
diff --git a/tests/utests/data/test_parser_json.c b/tests/utests/data/test_parser_json.c
index a33416f..d341e31 100644
--- a/tests/utests/data/test_parser_json.c
+++ b/tests/utests/data/test_parser_json.c
@@ -282,7 +282,7 @@
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
- data = "{\"a:any\":[null]}";
+ data = "{\"a:any\":{\"node\":20}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;