validation FEATURE multi-error parsing/validation
Refs #1978
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 5a929da..ccbb2a9 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -40,6 +40,9 @@
#include "validation.h"
#include "xml.h"
+static LY_ERR lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p,
+ struct ly_set *parsed);
+
void
lyd_xml_ctx_free(struct lyd_ctx *lydctx)
{
@@ -430,7 +433,7 @@
* @param[out] anchor Anchor to insert after in case of a list.
*/
static void
-lydxml_get_hints_opaq(const char *name, size_t name_len, const char *value, size_t value_len, struct lyd_node *first,
+lydxml_get_hints_opaq(const char *name, size_t name_len, const char *value, size_t value_len, const struct lyd_node *first,
const char *ns, uint32_t *hints, struct lyd_node **anchor)
{
struct lyd_node_opaq *opaq;
@@ -485,7 +488,7 @@
opaq->hints |= LYD_NODEHINT_LIST;
*hints |= LYD_NODEHINT_LIST;
}
- *anchor = first;
+ *anchor = (struct lyd_node *)first;
break;
}
} while (first->prev->next);
@@ -506,7 +509,7 @@
* @return LY_ERR on error.
*/
static LY_ERR
-lydxml_subtree_snode(struct lyd_xml_ctx *lydctx, const struct lyd_node *parent, const char *prefix, size_t prefix_len,
+lydxml_subtree_get_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;
@@ -604,34 +607,338 @@
}
/**
- * @brief Parse XML subtree.
+ * @brief Parse an XML opque node.
+ *
+ * @param[in] lydctx XML YANG data parser context.
+ * @param[in] sibling Existing sibling node, if any.
+ * @param[in] prefix Parsed node prefix.
+ * @param[in] prefix_len Length of @p prefix.
+ * @param[in] name Parsed node name.
+ * @param[in] name_len Length of @p name.
+ * @param[out] insert_anchor Optional anchor node for inserting this node.
+ * @param[out] node Created node.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydxml_subtree_opaq(struct lyd_xml_ctx *lydctx, const struct lyd_node *sibling, const char *prefix, uint32_t prefix_len,
+ const char *name, uint32_t name_len, struct lyd_node **insert_anchor, struct lyd_node **node)
+{
+ LY_ERR rc = LY_SUCCESS;
+ struct lyxml_ctx *xmlctx = lydctx->xmlctx;
+ const char *ns_uri;
+ const struct lyxml_ns *ns;
+ uint32_t hints;
+ void *val_prefix_data = NULL;
+ LY_VALUE_FORMAT format;
+
+ assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
+
+ *node = NULL;
+
+ if (xmlctx->ws_only) {
+ /* ignore WS-only value */
+ if (xmlctx->dynamic) {
+ free((char *)xmlctx->value);
+ }
+ xmlctx->dynamic = 0;
+ xmlctx->value = "";
+ xmlctx->value_len = 0;
+ format = LY_VALUE_XML;
+ } else {
+ /* get value prefixes */
+ rc = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns, &format,
+ &val_prefix_data);
+ LY_CHECK_GOTO(rc, cleanup);
+ }
+
+ /* get NS again, it may have been backed up and restored */
+ ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
+ ns_uri = ns ? ns->uri : NULL;
+
+ /* get best-effort node hints */
+ lydxml_get_hints_opaq(name, name_len, xmlctx->value, xmlctx->value_len, sibling, ns_uri, &hints, insert_anchor);
+
+ /* create node */
+ rc = lyd_create_opaq(xmlctx->ctx, name, name_len, prefix, prefix_len, ns_uri, ns_uri ? strlen(ns_uri) : 0,
+ xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, hints, node);
+ LY_CHECK_GOTO(rc, cleanup);
+ val_prefix_data = NULL;
+
+ /* parser next */
+ rc = lyxml_ctx_next(xmlctx);
+ LY_CHECK_GOTO(rc, cleanup);
+
+ /* process children */
+ while (xmlctx->status == LYXML_ELEMENT) {
+ rc = lydxml_subtree_r(lydctx, *node, lyd_node_child_p(*node), NULL);
+ LY_CHECK_GOTO(rc, cleanup);
+ }
+
+cleanup:
+ ly_free_prefix_data(format, val_prefix_data);
+ if (rc) {
+ lyd_free_tree(*node);
+ *node = NULL;
+ }
+ return rc;
+}
+
+/**
+ * @brief Parse an XML leaf/leaf-list node.
+ *
+ * @param[in] lydctx XML YANG data parser context.
+ * @param[in] parent Parent node, if any.
+ * @param[in] snode Schema node of the new node.
+ * @param[out] node Created node.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydxml_subtree_term(struct lyd_xml_ctx *lydctx, struct lyd_node *parent, const struct lysc_node *snode,
+ struct lyd_node **node)
+{
+ LY_ERR r, rc = LY_SUCCESS;
+ struct lyxml_ctx *xmlctx = lydctx->xmlctx;
+ struct lyd_node *anchor;
+
+ *node = NULL;
+
+ /* create node */
+ r = lyd_parser_create_term((struct lyd_ctx *)lydctx, snode, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic,
+ LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, node);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+
+ if (*node) {
+ LOG_LOCSET(snode, *node, NULL, NULL);
+ }
+
+ if (parent && (snode->flags & LYS_KEY)) {
+ /* check the key order, the anchor must never be a key */
+ anchor = lyd_insert_get_next_anchor(lyd_child(parent), *node);
+ if (anchor && anchor->schema && (anchor->schema->flags & LYS_KEY)) {
+ if (lydctx->parse_opts & LYD_PARSE_STRICT) {
+ LOGVAL(xmlctx->ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", snode->name);
+ r = LY_EVALID;
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ } else {
+ LOGWRN(xmlctx->ctx, "Invalid position of the key \"%s\" in a list.", snode->name);
+ }
+ }
+ }
+
+ /* parser next */
+ r = lyxml_ctx_next(xmlctx);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+
+ /* no children expected */
+ if (xmlctx->status == LYXML_ELEMENT) {
+ LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
+ (int)xmlctx->name_len, xmlctx->name, snode->name);
+ r = LY_EVALID;
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ }
+
+cleanup:
+ if (*node) {
+ LOG_LOCBACK(1, 1, 0, 0);
+ }
+ if (rc && (!(lydctx->val_opts & LYD_VALIDATE_MULTI_ERROR) || (rc != LY_EVALID))) {
+ lyd_free_tree(*node);
+ *node = NULL;
+ }
+ return rc;
+}
+
+/**
+ * @brief Parse an XML inner node.
+ *
+ * @param[in] lydctx XML YANG data parser context.
+ * @param[in] snode Schema node of the new node.
+ * @param[in] ext Extension instance of @p snode, if any.
+ * @param[out] node Created node.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydxml_subtree_inner(struct lyd_xml_ctx *lydctx, const struct lysc_node *snode, const struct lysc_ext_instance *ext,
+ struct lyd_node **node)
+{
+ LY_ERR r, rc = LY_SUCCESS;
+ struct lyxml_ctx *xmlctx = lydctx->xmlctx;
+ uint32_t prev_parse_opts = lydctx->parse_opts;
+
+ *node = NULL;
+
+ if (!xmlctx->ws_only) {
+ /* value in inner node */
+ LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
+ (int)xmlctx->value_len, xmlctx->value, snode->name);
+ r = LY_EVALID;
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ }
+
+ /* create node */
+ rc = lyd_create_inner(snode, node);
+ LY_CHECK_GOTO(rc, cleanup);
+
+ if (*node) {
+ LOG_LOCSET(snode, *node, NULL, NULL);
+ }
+
+ /* parser next */
+ rc = lyxml_ctx_next(xmlctx);
+ LY_CHECK_GOTO(rc, cleanup);
+
+ if (ext) {
+ /* only parse these extension data and validate afterwards */
+ lydctx->parse_opts |= LYD_PARSE_ONLY;
+ }
+
+ /* process children */
+ while (xmlctx->status == LYXML_ELEMENT) {
+ r = lydxml_subtree_r(lydctx, *node, lyd_node_child_p(*node), NULL);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ }
+
+ /* restore options */
+ lydctx->parse_opts = prev_parse_opts;
+
+ if (snode->nodetype == LYS_LIST) {
+ /* check all keys exist */
+ r = lyd_parse_check_keys(*node);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ }
+
+ if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
+ /* new node validation, autodelete CANNOT occur, all nodes are new */
+ r = lyd_validate_new(lyd_node_child_p(*node), snode, NULL, lydctx->val_opts, NULL);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+
+ /* add any missing default children */
+ r = lyd_new_implicit_r(*node, lyd_node_child_p(*node), NULL, NULL, &lydctx->node_when, &lydctx->node_types,
+ &lydctx->ext_node, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+ }
+
+ if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
+ /* rememeber the RPC/action/notification */
+ lydctx->op_node = *node;
+ }
+
+cleanup:
+ if (*node) {
+ LOG_LOCBACK(1, 1, 0, 0);
+ }
+ lydctx->parse_opts = prev_parse_opts;
+ if (rc && (!(lydctx->val_opts & LYD_VALIDATE_MULTI_ERROR) || (rc != LY_EVALID))) {
+ lyd_free_tree(*node);
+ *node = NULL;
+ }
+ return rc;
+}
+
+/**
+ * @brief Parse an XML anyxml/anydata node.
+ *
+ * @param[in] lydctx XML YANG data parser context.
+ * @param[in] snode Schema node of the new node.
+ * @param[in] ext Extension instance of @p snode, if any.
+ * @param[out] node Created node.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lydxml_subtree_any(struct lyd_xml_ctx *lydctx, const struct lysc_node *snode, const struct lysc_ext_instance *ext,
+ struct lyd_node **node)
+{
+ LY_ERR r, rc = LY_SUCCESS;
+ struct lyxml_ctx *xmlctx = lydctx->xmlctx;
+ uint32_t prev_parse_opts = lydctx->parse_opts, prev_int_opts = lydctx->int_opts;
+ struct lyd_node *child = NULL;
+ char *val = NULL;
+
+ *node = NULL;
+
+ if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
+ /* value in anydata node, we expect a tree */
+ LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
+ (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
+ r = LY_EVALID;
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ }
+
+ if (!xmlctx->ws_only) {
+ /* use an arbitrary text value for anyxml */
+ val = strndup(xmlctx->value, xmlctx->value_len);
+ LY_CHECK_ERR_GOTO(!val, LOGMEM(xmlctx->ctx); rc = LY_EMEM, cleanup);
+
+ /* parser next */
+ r = lyxml_ctx_next(xmlctx);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+
+ /* create node */
+ r = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, node);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+ val = NULL;
+ } else {
+ /* parser next */
+ r = lyxml_ctx_next(xmlctx);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+
+ /* update options so that generic data can be parsed */
+ lydctx->parse_opts &= ~LYD_PARSE_STRICT;
+ lydctx->parse_opts |= LYD_PARSE_OPAQ | (ext ? LYD_PARSE_ONLY : 0);
+ lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
+
+ /* parse any data tree */
+ while (xmlctx->status == LYXML_ELEMENT) {
+ r = lydxml_subtree_r(lydctx, NULL, &child, NULL);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ }
+
+ /* restore options */
+ lydctx->parse_opts = prev_parse_opts;
+ lydctx->int_opts = prev_int_opts;
+
+ /* create node */
+ r = lyd_create_any(snode, child, LYD_ANYDATA_DATATREE, 1, node);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+ child = NULL;
+ }
+
+cleanup:
+ lydctx->parse_opts = prev_parse_opts;
+ lydctx->int_opts = prev_int_opts;
+ free(val);
+ lyd_free_tree(child);
+ if (rc && (!(lydctx->val_opts & LYD_VALIDATE_MULTI_ERROR) || (rc != LY_EVALID))) {
+ lyd_free_tree(*node);
+ *node = NULL;
+ }
+ return rc;
+}
+
+/**
+ * @brief Parse an XML subtree, recursively.
*
* @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] first_p Pointer to the first (@p parent or top-level) child.
* @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, *ns_uri;
+ LY_ERR r, rc = 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, hints;
- struct lyd_node *node = NULL, *anchor, *insert_anchor = NULL;
- void *val_prefix_data = NULL;
- LY_VALUE_FORMAT format;
+ uint32_t orig_parse_opts;
+ struct lyd_node *node = NULL, *insert_anchor = NULL;
ly_bool parse_subtree;
- char *val;
assert(parent || first_p);
@@ -652,237 +959,85 @@
name_len = xmlctx->name_len;
/* parser next */
- LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
+ rc = lyxml_ctx_next(xmlctx);
+ LY_CHECK_GOTO(rc, cleanup);
/* get the schema node */
- LY_CHECK_GOTO(ret = lydxml_subtree_snode(lydctx, parent, prefix, prefix_len, name, name_len, &snode, &ext), error);
+ rc = lydxml_subtree_get_snode(lydctx, parent, prefix, prefix_len, name, name_len, &snode, &ext);
+ LY_CHECK_GOTO(rc, cleanup);
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;
+ rc = lydxml_data_skip(xmlctx);
+ goto cleanup;
}
/* create metadata/attributes */
if (xmlctx->status == LYXML_ATTRIBUTE) {
if (snode) {
- ret = lydxml_metadata(lydctx, snode, &meta);
- LY_CHECK_GOTO(ret, error);
+ rc = lydxml_metadata(lydctx, snode, &meta);
+ LY_CHECK_GOTO(rc, cleanup);
} else {
assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
- ret = lydxml_attrs(xmlctx, &attr);
- LY_CHECK_GOTO(ret, error);
+ rc = lydxml_attrs(xmlctx, &attr);
+ LY_CHECK_GOTO(rc, cleanup);
}
}
assert(xmlctx->status == LYXML_ELEM_CONTENT);
if (!snode) {
- assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
-
- if (xmlctx->ws_only) {
- /* ignore WS-only value */
- if (xmlctx->dynamic) {
- free((char *)xmlctx->value);
- }
- xmlctx->dynamic = 0;
- xmlctx->value = "";
- xmlctx->value_len = 0;
- format = LY_VALUE_XML;
- } else {
- /* get value prefixes */
- ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
- &xmlctx->ns, &format, &val_prefix_data);
- LY_CHECK_GOTO(ret, error);
- }
-
- /* get NS again, it may have been backed up and restored */
- ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
- ns_uri = ns ? ns->uri : NULL;
-
- /* get best-effort node hints */
- lydxml_get_hints_opaq(name, name_len, xmlctx->value, xmlctx->value_len, parent ? lyd_child(parent) : *first_p,
- ns_uri, &hints, &insert_anchor);
-
- /* create node */
- ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns_uri, ns_uri ? strlen(ns_uri) : 0,
- xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, hints, &node);
- LY_CHECK_GOTO(ret, error);
-
- /* parser next */
- LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
-
- /* process children */
- while (xmlctx->status == LYXML_ELEMENT) {
- ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
- LY_CHECK_GOTO(ret, error);
- }
+ /* opaque */
+ r = lydxml_subtree_opaq(lydctx, parent ? lyd_child(parent) : *first_p, prefix, prefix_len, name, name_len,
+ &insert_anchor, &node);
} else if (snode->nodetype & LYD_NODE_TERM) {
- /* create node */
- LY_CHECK_GOTO(ret = lyd_parser_create_term((struct lyd_ctx *)lydctx, snode, xmlctx->value, xmlctx->value_len,
- &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
- LOG_LOCSET(snode, node, NULL, NULL);
-
- if (parent && (node->schema->flags & LYS_KEY)) {
- /* check the key order, the anchor must never be a key */
- anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
- if (anchor && anchor->schema && (anchor->schema->flags & LYS_KEY)) {
- if (lydctx->parse_opts & LYD_PARSE_STRICT) {
- LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
- ret = LY_EVALID;
- goto error;
- } else {
- LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
- }
- }
- }
-
- /* parser next */
- LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
-
- /* no children expected */
- if (xmlctx->status == LYXML_ELEMENT) {
- LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
- (int)xmlctx->name_len, xmlctx->name, snode->name);
- ret = LY_EVALID;
- goto error;
- }
+ /* term */
+ r = lydxml_subtree_term(lydctx, parent, snode, &node);
} else if (snode->nodetype & LYD_NODE_INNER) {
- if (!xmlctx->ws_only) {
- /* value in inner node */
- LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
- (int)xmlctx->value_len, xmlctx->value, snode->name);
- ret = LY_EVALID;
- goto error;
- }
-
- /* create node */
- ret = lyd_create_inner(snode, &node);
- LY_CHECK_GOTO(ret, error);
-
- LOG_LOCSET(snode, node, NULL, NULL);
-
- /* 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);
- }
-
- if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
- /* new node validation, autodelete CANNOT occur, all nodes are new */
- ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
- LY_CHECK_GOTO(ret, error);
-
- /* add any missing default children */
- ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_types,
- &lydctx->ext_node, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
- LY_CHECK_GOTO(ret, error);
- }
-
- if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
- /* rememeber the RPC/action/notification */
- lydctx->op_node = node;
- }
+ /* inner */
+ r = lydxml_subtree_inner(lydctx, snode, ext, &node);
} else if (snode->nodetype & LYD_NODE_ANY) {
- if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
- /* value in anydata node, we expect a tree */
- LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
- (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
- ret = LY_EVALID;
- goto error;
- }
-
- if (!xmlctx->ws_only) {
- /* use an arbitrary text value for anyxml */
- val = strndup(xmlctx->value, xmlctx->value_len);
- LY_CHECK_ERR_GOTO(!val, LOGMEM(xmlctx->ctx); ret = LY_EMEM, error);
-
- /* parser next */
- LY_CHECK_ERR_GOTO(ret = lyxml_ctx_next(xmlctx), free(val), error);
-
- /* create node */
- ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
- LY_CHECK_ERR_GOTO(ret, free(val), error);
- } else {
- /* parser next */
- LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
-
- /* 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 | (ext ? LYD_PARSE_ONLY : 0);
- prev_int_opts = lydctx->int_opts;
- lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
-
- /* parse any data tree */
- anchor = NULL;
- while (xmlctx->status == LYXML_ELEMENT) {
- ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
- if (ret) {
- lyd_free_siblings(anchor);
- break;
- }
- }
-
- /* restore options */
- lydctx->parse_opts = prev_parse_opts;
- lydctx->int_opts = prev_int_opts;
-
- LY_CHECK_GOTO(ret, error);
-
- /* create node */
- ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
- LY_CHECK_GOTO(ret, error);
- }
+ /* any */
+ r = lydxml_subtree_any(lydctx, snode, ext, &node);
}
- assert(node);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+ LY_CHECK_GOTO(!node, cleanup);
if (snode) {
/* add/correct flags */
- LY_CHECK_GOTO(ret = lyd_parse_set_data_flags(node, &meta, (struct lyd_ctx *)lydctx, ext), error);
+ r = lyd_parse_set_data_flags(node, &meta, (struct lyd_ctx *)lydctx, ext);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
/* store for ext instance node validation, if needed */
- LY_CHECK_GOTO(ret = lyd_validate_node_ext(node, &lydctx->ext_node), error);
+ r = lyd_validate_node_ext(node, &lydctx->ext_node);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
}
}
/* parser next */
assert(xmlctx->status == LYXML_ELEM_CLOSE);
if (!parse_subtree) {
- LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
+ r = lyxml_ctx_next(xmlctx);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
}
/* add metadata/attributes */
if (snode) {
lyd_insert_meta(node, meta, 0);
+ meta = NULL;
} else {
lyd_insert_attr(node, attr);
+ attr = NULL;
}
/* insert, keep first pointer correct */
if (insert_anchor) {
lyd_insert_after(insert_anchor, node);
} else if (ext) {
- LY_CHECK_GOTO(ret = lyplg_ext_insert(parent, node), error);
+ r = lyplg_ext_insert(parent, node);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
} else {
lyd_insert_node(parent, first_p, node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
}
@@ -895,17 +1050,11 @@
ly_set_add(parsed, node, 1, NULL);
}
+cleanup:
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);
- lyd_free_tree(node);
- return ret;
+ return rc;
}
/**
@@ -987,7 +1136,7 @@
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;
+ LY_ERR r, rc = LY_SUCCESS;
struct lyd_xml_ctx *lydctx;
ly_bool parsed_data_nodes = 0;
enum LYXML_PARSER_STATUS status;
@@ -1011,7 +1160,9 @@
/* parse XML data */
while (lydctx->xmlctx->status == LYXML_ELEMENT) {
- LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
+ r = lydxml_subtree_r(lydctx, parent, first_p, parsed);
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
+
parsed_data_nodes = 1;
if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
@@ -1022,13 +1173,13 @@
/* 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;
+ r = LY_EVALID;
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, 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;
+ r = LY_EVALID;
+ LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
}
if (!parsed_data_nodes) {
@@ -1051,7 +1202,7 @@
assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
!lydctx->node_when.count));
- if (rc) {
+ if (rc && (!(lydctx->val_opts & LYD_VALIDATE_MULTI_ERROR) || (rc != LY_EVALID))) {
lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
} else {
*lydctx_p = (struct lyd_ctx *)lydctx;