parser UPDATE guess opaque node schema nodes
... for their descendant parsing purposes.
Refs #2086
diff --git a/src/common.h b/src/common.h
index 4009f3c..b9842bc 100644
--- a/src/common.h
+++ b/src/common.h
@@ -130,6 +130,21 @@
void ly_log_location_revert(uint32_t scnode_steps, uint32_t dnode_steps, uint32_t path_steps, uint32_t in_steps);
/**
+ * @brief Get the stored data node for logging at the index.
+ *
+ * @param[in] idx Index of the data node.
+ * @return Logged data node, NULL if out of range.
+ */
+const struct lyd_node *ly_log_location_dnode(uint32_t idx);
+
+/**
+ * @brief Get the count of stored data nodes for logging.
+ *
+ * @return Count of the data nodes.
+ */
+uint32_t ly_log_location_dnode_count(void);
+
+/**
* @brief Update location data for logger, not provided arguments (NULLs) are kept (does not override).
*
* @param[in] SCNODE Compiled schema node.
diff --git a/src/log.c b/src/log.c
index a788a2e..a0d997f 100644
--- a/src/log.c
+++ b/src/log.c
@@ -500,6 +500,22 @@
}
}
+const struct lyd_node *
+ly_log_location_dnode(uint32_t idx)
+{
+ if (idx < log_location.dnodes.count) {
+ return log_location.dnodes.dnodes[idx];
+ }
+
+ return NULL;
+}
+
+uint32_t
+ly_log_location_dnode_count(void)
+{
+ return log_location.dnodes.count;
+}
+
/**
* @brief Store generated error in a context.
*
diff --git a/src/parser_common.c b/src/parser_common.c
index a859925..040318e 100644
--- a/src/parser_common.c
+++ b/src/parser_common.c
@@ -157,6 +157,63 @@
return LY_SUCCESS;
}
+const struct lysc_node *
+lyd_parser_node_schema(const struct lyd_node *node)
+{
+ uint32_t i;
+ const struct lyd_node *iter;
+ const struct lysc_node *schema = NULL;
+ const struct lys_module *mod;
+
+ if (!node) {
+ return NULL;
+ } else if (node->schema) {
+ /* simplest case */
+ return node->schema;
+ }
+
+ /* find the first schema node in the parsed nodes */
+ i = ly_log_location_dnode_count();
+ if (i) {
+ do {
+ --i;
+ if (ly_log_location_dnode(i)->schema) {
+ /* this node is processed */
+ schema = ly_log_location_dnode(i)->schema;
+ ++i;
+ break;
+ }
+ } while (i);
+ }
+
+ /* get schema node of an opaque node */
+ do {
+ /* get next data node */
+ if (i == ly_log_location_dnode_count()) {
+ iter = node;
+ } else {
+ iter = ly_log_location_dnode(i);
+ }
+ assert(!iter->schema);
+
+ /* get module */
+ mod = lyd_owner_module(iter);
+ if (!mod) {
+ /* unknown module, no schema node */
+ schema = NULL;
+ break;
+ }
+
+ /* get schema node */
+ schema = lys_find_child(schema, mod, LYD_NAME(iter), 0, 0, 0);
+
+ /* move to the descendant */
+ ++i;
+ } while (schema && (iter != node));
+
+ return schema;
+}
+
LY_ERR
lyd_parser_check_schema(struct lyd_ctx *lydctx, const struct lysc_node *snode)
{
diff --git a/src/parser_internal.h b/src/parser_internal.h
index 419d68e..5b632a2 100644
--- a/src/parser_internal.h
+++ b/src/parser_internal.h
@@ -358,6 +358,14 @@
LY_ERR lyd_parser_find_operation(const struct lyd_node *parent, uint32_t int_opts, struct lyd_node **op);
/**
+ * @brief Get schema node of a node being parsed, use nodes stored for logging.
+ *
+ * @param[in] node Node whose schema node to get.
+ * @return Schema node even for an opaque node, NULL if none found.
+ */
+const struct lysc_node *lyd_parser_node_schema(const struct lyd_node *node);
+
+/**
* @brief Check that a data node representing the @p snode is suitable based on options.
*
* @param[in] lydctx Common data parsers context.
diff --git a/src/parser_json.c b/src/parser_json.c
index fca58f4..589e9c6 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -295,7 +295,7 @@
if (!parent && lydctx->ext) {
*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(lyd_parser_node_schema(parent), mod, name, name_len, 0, getnext_opts);
}
if (!*snode) {
/* check for extension data */
@@ -1018,17 +1018,23 @@
struct lyd_node *parent, enum LYJSON_PARSER_STATUS *status_p, enum LYJSON_PARSER_STATUS *status_inner_p,
struct lyd_node **first_p, struct lyd_node **node_p)
{
- LY_CHECK_RET(lydjson_create_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status_inner_p, node_p));
+ LY_ERR ret = LY_SUCCESS;
+
+ LY_CHECK_GOTO(ret = lydjson_create_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status_inner_p, node_p), cleanup);
+
+ assert(*node_p);
+ LOG_LOCSET(NULL, *node_p, NULL, NULL);
if ((*status_p == LYJSON_ARRAY) && (*status_inner_p == LYJSON_NULL)) {
/* special array null value */
((struct lyd_node_opaq *)*node_p)->hints |= LYD_VALHINT_EMPTY;
/* must be the only item */
- LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_inner_p));
+ LY_CHECK_GOTO(ret = lyjson_ctx_next(lydctx->jsonctx, status_inner_p), cleanup);
if (*status_inner_p != LYJSON_ARRAY_CLOSED) {
LOGVAL(lydctx->jsonctx->ctx, LYVE_SYNTAX, "Array \"null\" member with another member.");
- return LY_EVALID;
+ ret = LY_EVALID;
+ goto cleanup;
}
goto finish;
@@ -1042,7 +1048,7 @@
/* but first process children of the object in the array */
do {
- LY_CHECK_RET(lydjson_subtree_r(lydctx, *node_p, lyd_node_child_p(*node_p), NULL));
+ LY_CHECK_GOTO(ret = lydjson_subtree_r(lydctx, *node_p, lyd_node_child_p(*node_p), NULL), cleanup);
*status_inner_p = lyjson_ctx_status(lydctx->jsonctx);
} while (*status_inner_p == LYJSON_OBJECT_NEXT);
} else {
@@ -1050,30 +1056,42 @@
((struct lyd_node_opaq *)*node_p)->hints |= LYD_NODEHINT_LEAFLIST;
}
- LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_inner_p));
+ LY_CHECK_GOTO(ret = lyjson_ctx_next(lydctx->jsonctx, status_inner_p), cleanup);
if (*status_inner_p == LYJSON_ARRAY_CLOSED) {
goto finish;
}
assert(*status_inner_p == LYJSON_ARRAY_NEXT);
/* continue with the next instance */
- LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_inner_p));
- assert(node_p);
+ LY_CHECK_GOTO(ret = lyjson_ctx_next(lydctx->jsonctx, status_inner_p), cleanup);
+ assert(*node_p);
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));
+
+ LOG_LOCBACK(0, 1, 0, 0);
+
+ LY_CHECK_GOTO(ret = lydjson_create_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status_inner_p, node_p), cleanup);
+
+ assert(*node_p);
+ LOG_LOCSET(NULL, *node_p, NULL, NULL);
}
if (*status_p == LYJSON_OBJECT) {
/* process children */
do {
- LY_CHECK_RET(lydjson_subtree_r(lydctx, *node_p, lyd_node_child_p(*node_p), NULL));
+ LY_CHECK_GOTO(ret = lydjson_subtree_r(lydctx, *node_p, lyd_node_child_p(*node_p), NULL), cleanup);
*status_p = lyjson_ctx_status(lydctx->jsonctx);
} while (*status_p == LYJSON_OBJECT_NEXT);
}
finish:
/* finish linking metadata */
- return lydjson_metadata_finish(lydctx, lyd_node_child_p(*node_p));
+ ret = lydjson_metadata_finish(lydctx, lyd_node_child_p(*node_p));
+
+cleanup:
+ if (*node_p) {
+ LOG_LOCBACK(0, 1, 0, 0);
+ }
+ return ret;
}
/**
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index 2e3d0c5..788be94 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -1171,6 +1171,9 @@
value, strlen(value), &dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
LY_CHECK_GOTO(ret, cleanup);
+ assert(node);
+ LOG_LOCSET(NULL, node, NULL, NULL);
+
/* process children */
ret = lyb_parse_siblings(lybctx, node, NULL, NULL);
LY_CHECK_GOTO(ret, cleanup);
@@ -1178,8 +1181,12 @@
/* register parsed opaq node */
lyb_finish_opaq(lybctx, parent, flags, &attr, &node, first_p, parsed);
assert(!attr && !node);
+ LOG_LOCBACK(0, 1, 0, 0);
cleanup:
+ if (node) {
+ LOG_LOCBACK(0, 1, 0, 0);
+ }
free(prefix);
free(module_key);
free(name);
@@ -1265,9 +1272,13 @@
goto error;
}
+ assert(node);
+ LOG_LOCSET(NULL, node, NULL, NULL);
+
/* register parsed anydata node */
lyb_finish_node(lybctx, parent, flags, &meta, &node, first_p, parsed);
+ LOG_LOCBACK(0, 1, 0, 0);
return LY_SUCCESS;
error:
@@ -1304,6 +1315,9 @@
ret = lyd_create_inner(snode, &node);
LY_CHECK_GOTO(ret, error);
+ assert(node);
+ LOG_LOCSET(NULL, node, NULL, NULL);
+
/* process children */
ret = lyb_parse_siblings(lybctx, node, NULL, NULL);
LY_CHECK_GOTO(ret, error);
@@ -1320,9 +1334,13 @@
/* register parsed node */
lyb_finish_node(lybctx, parent, flags, &meta, &node, first_p, parsed);
+ LOG_LOCBACK(0, 1, 0, 0);
return LY_SUCCESS;
error:
+ if (node) {
+ LOG_LOCBACK(0, 1, 0, 0);
+ }
lyd_free_meta_siblings(meta);
lyd_free_tree(node);
return ret;
@@ -1355,8 +1373,12 @@
ret = lyb_create_term(lybctx, snode, &node);
LY_CHECK_GOTO(ret, error);
+ assert(node);
+ LOG_LOCSET(NULL, node, NULL, NULL);
+
lyb_finish_node(lybctx, parent, flags, &meta, &node, first_p, parsed);
+ LOG_LOCBACK(0, 1, 0, 0);
return LY_SUCCESS;
error:
@@ -1416,6 +1438,7 @@
struct lyd_node *node = NULL;
struct lyd_meta *meta = NULL;
uint32_t flags;
+ ly_bool log_node = 0;
/* register a new sibling */
ret = lyb_read_start_siblings(lybctx->lybctx);
@@ -1430,6 +1453,10 @@
ret = lyd_create_inner(snode, &node);
LY_CHECK_GOTO(ret, error);
+ assert(node);
+ LOG_LOCSET(NULL, node, NULL, NULL);
+ log_node = 1;
+
/* process children */
ret = lyb_parse_siblings(lybctx, node, NULL, NULL);
LY_CHECK_GOTO(ret, error);
@@ -1445,6 +1472,9 @@
/* register parsed list node */
lyb_finish_node(lybctx, parent, flags, &meta, &node, first_p, parsed);
+
+ LOG_LOCBACK(0, 1, 0, 0);
+ log_node = 0;
}
/* end the sibling */
@@ -1454,6 +1484,9 @@
return LY_SUCCESS;
error:
+ if (log_node) {
+ LOG_LOCBACK(0, 1, 0, 0);
+ }
lyd_free_meta_siblings(meta);
lyd_free_tree(node);
return ret;
@@ -1492,7 +1525,7 @@
case LYB_NODE_CHILD:
case LYB_NODE_OPAQ:
/* read hash, find the schema node starting from parent schema, if any */
- LY_CHECK_GOTO(ret = lyb_parse_schema_hash(lybctx, parent ? parent->schema : NULL, NULL, &snode), cleanup);
+ LY_CHECK_GOTO(ret = lyb_parse_schema_hash(lybctx, lyd_parser_node_schema(parent), NULL, &snode), cleanup);
break;
case LYB_NODE_EXT:
/* ext, read module name */
diff --git a/src/parser_xml.c b/src/parser_xml.c
index b24e9fa..a117825 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -570,46 +570,45 @@
}
/* get the schema node */
- if (mod) {
- if (!parent && lydctx->ext) {
- *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);
+ if (!parent && lydctx->ext) {
+ *snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
+ } else {
+ /* try to find parent schema node even if it is an opaque node (not connected to the parent) */
+ *snode = lys_find_child(lyd_parser_node_schema(parent), mod, name, name_len, 0, getnext_opts);
+ }
+ if (!*snode) {
+ /* check for extension data */
+ 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;
}
- if (!*snode) {
- /* check for extension data */
- 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;
- }
- /* unknown data node */
- if (lydctx->parse_opts & LYD_PARSE_STRICT) {
- if (parent) {
- LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
- (int)name_len, name, LYD_NAME(parent));
- } else if (lydctx->ext) {
- if (lydctx->ext->argument) {
- LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
- (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
- } else {
- LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
- (int)name_len, name, lydctx->ext->def->name);
- }
+ /* unknown data node */
+ if (lydctx->parse_opts & LYD_PARSE_STRICT) {
+ if (parent) {
+ LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
+ (int)name_len, name, LYD_NAME(parent));
+ } else if (lydctx->ext) {
+ if (lydctx->ext->argument) {
+ LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
+ (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
} else {
- LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
- (int)name_len, name, mod->name);
+ LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
+ (int)name_len, name, lydctx->ext->def->name);
}
- return LY_EVALID;
+ } else {
+ LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
+ (int)name_len, name, mod->name);
}
- return LY_SUCCESS;
- } else {
- /* check that schema node is valid and can be used */
- LY_CHECK_RET(lyd_parser_check_schema((struct lyd_ctx *)lydctx, *snode));
- LY_CHECK_RET(lydxml_data_check_opaq(lydctx, snode));
+ return LY_EVALID;
}
+ return LY_SUCCESS;
+ } else {
+ /* check that schema node is valid and can be used */
+ LY_CHECK_RET(lyd_parser_check_schema((struct lyd_ctx *)lydctx, *snode));
+ LY_CHECK_RET(lydxml_data_check_opaq(lydctx, snode));
}
return LY_SUCCESS;
@@ -672,6 +671,9 @@
NULL, format, NULL, hints, node);
LY_CHECK_GOTO(rc, cleanup);
+ assert(*node);
+ LOG_LOCSET(NULL, *node, NULL, NULL);
+
/* parser next */
rc = lyxml_ctx_next(xmlctx);
LY_CHECK_GOTO(rc, cleanup);
@@ -706,6 +708,9 @@
val_prefix_data = NULL;
cleanup:
+ if (*node) {
+ LOG_LOCBACK(0, 1, 0, 0);
+ }
ly_free_prefix_data(format, val_prefix_data);
if (dynamic) {
free((char *)value);
diff --git a/src/tree_data.c b/src/tree_data.c
index a5a0201..463daac 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -697,7 +697,7 @@
lyd_insert_hash(node);
/* finish hashes for our parent, if needed and possible */
- if (node->schema && (node->schema->flags & LYS_KEY) && parent && lyd_insert_has_keys(parent)) {
+ if (node->schema && (node->schema->flags & LYS_KEY) && parent && parent->schema && lyd_insert_has_keys(parent)) {
lyd_hash(parent);
/* now we can insert even the list into its parent HT */
diff --git a/src/tree_data_common.c b/src/tree_data_common.c
index 3f168ae..115886b 100644
--- a/src/tree_data_common.c
+++ b/src/tree_data_common.c
@@ -757,17 +757,10 @@
}
LY_LIST_FOR(lyd_child(node), child) {
- if (child->schema) {
- /* skip data nodes, opaque nodes are after them */
- continue;
- }
-
- opaq_k = (struct lyd_node_opaq *)child;
-
/* find the key schema node */
for (i = 0; i < key_set.count; ++i) {
key = key_set.snodes[i];
- if (!strcmp(key->name, opaq_k->name.name)) {
+ if (!strcmp(key->name, LYD_NAME(child))) {
break;
}
}
@@ -779,7 +772,13 @@
/* key found */
ly_set_rm_index(&key_set, i, NULL);
+ if (child->schema) {
+ /* valid key */
+ continue;
+ }
+
/* check value */
+ opaq_k = (struct lyd_node_opaq *)child;
ret = ly_value_validate(LYD_CTX(node), key, opaq_k->value, strlen(opaq_k->value), opaq_k->format,
opaq_k->val_prefix_data, opaq_k->hints);
LY_CHECK_GOTO(ret, cleanup);
@@ -1059,27 +1058,30 @@
return node->schema;
}
+ /* find the first schema node in the parents */
+ for (iter = lyd_parent(node); iter && !iter->schema; iter = lyd_parent(iter)) {}
+ if (iter) {
+ prev_iter = iter;
+ schema = prev_iter->schema;
+ }
+
/* get schema node of an opaque node */
do {
/* get next data node */
for (iter = node; lyd_parent(iter) != prev_iter; iter = lyd_parent(iter)) {}
- /* get equivalent schema node */
- if (iter->schema) {
- schema = iter->schema;
- } else {
- /* get module */
- mod = lyd_owner_module(iter);
- if (!mod && !schema) {
- /* top-level opaque node has unknown module */
- break;
- }
-
- /* get schema node */
- schema = lys_find_child(schema, mod ? mod : schema->module, LYD_NAME(iter), 0, 0, 0);
+ /* get module */
+ mod = lyd_owner_module(iter);
+ if (!mod) {
+ /* unknown module, no schema node */
+ schema = NULL;
+ break;
}
- /* remember to move to the descendant */
+ /* get schema node */
+ schema = lys_find_child(schema, mod, LYD_NAME(iter), 0, 0, 0);
+
+ /* move to the descendant */
prev_iter = iter;
} while (schema && (iter != node));
diff --git a/tests/utests/data/test_parser_json.c b/tests/utests/data/test_parser_json.c
index e5513da..e9619e2 100644
--- a/tests/utests/data/test_parser_json.c
+++ b/tests/utests/data/test_parser_json.c
@@ -584,7 +584,7 @@
/* empty name */
PARSER_CHECK_ERROR("{\"@a:foo\":{\"\":0}}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
- "JSON object member name cannot be a zero-length string.", "Line number 1.");
+ "JSON object member name cannot be a zero-length string.", "Data location \"/@a:foo\", line number 1.");
/* opaque data tree format print */
data =
diff --git a/tests/utests/data/test_parser_xml.c b/tests/utests/data/test_parser_xml.c
index 340724c..889e502 100644
--- a/tests/utests/data/test_parser_xml.c
+++ b/tests/utests/data/test_parser_xml.c
@@ -350,7 +350,7 @@
" <c xmld:id=\"D\">1</c>\n"
"</a>\n",
LYD_XML, LYD_PARSE_OPAQ, LYD_VALIDATE_PRESENT, &tree));
- CHECK_LOG_CTX("Unknown XML prefix \"xmld\".", "Line number 3.");
+ CHECK_LOG_CTX("Unknown XML prefix \"xmld\".", "Data location \"/a\", line number 3.");
}
static void