path FEATURE new compiled path structure (#1108)
Refactoring includes using it for
instance-identifier and for checking leafref,
it is evaluated using stanrad XPath. Predicates
used for lyd_new_list2(), tests included.
diff --git a/src/tree_data.c b/src/tree_data.c
index 20c0a7a..eb6a5fe 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -33,6 +33,7 @@
#include "dict.h"
#include "hash_table.h"
#include "log.h"
+#include "path.h"
#include "plugins_exts.h"
#include "plugins_exts_metadata.h"
#include "plugins_exts_internal.h"
@@ -74,8 +75,7 @@
node->value.realtype = type;
}
ret = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format,
- tree ? (void *)node : (void *)node->schema, tree,
- &node->value, NULL, &err);
+ tree ? (void *)node : (void *)node->schema, tree, &node->value, NULL, &err);
if (ret && (ret != LY_EINCOMPLETE)) {
if (err) {
/* node may not be connected yet so use the schema node */
@@ -96,7 +96,7 @@
}
/* similar to lyd_value_parse except can be used just to store the value, hence does also not support a second call */
-static LY_ERR
+LY_ERR
lyd_value_store(struct lyd_value *val, const struct lysc_node *schema, const char *value, size_t value_len, int *dynamic,
ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format)
{
@@ -647,48 +647,20 @@
}
LY_ERR
-lyd_create_list(const struct lysc_node *schema, const char *keys_str, size_t keys_len, LYD_FORMAT keys_format, int log,
- struct lyd_node **node)
+lyd_create_list(const struct lysc_node *schema, const struct ly_path_predicate *predicates, struct lyd_node **node)
{
LY_ERR ret = LY_SUCCESS;
- const struct lysc_node *key_s;
struct lyd_node *list = NULL, *key;
- struct ly_keys keys = {0};
- size_t i;
+ LY_ARRAY_SIZE_TYPE u;
- assert((schema->nodetype == LYS_LIST) && !(schema->flags & LYS_KEYLESS) && (keys_format != LYD_XML));
-
- /* parse keys */
- LY_CHECK_GOTO(ret = ly_keys_parse(schema, keys_str, keys_len, 0, log, &keys), cleanup);
+ assert((schema->nodetype == LYS_LIST) && !(schema->flags & LYS_KEYLESS));
/* create list */
LY_CHECK_GOTO(ret = lyd_create_inner(schema, &list), cleanup);
- /* everything was checked except that all keys are set */
- i = 0;
- for (key_s = lysc_node_children(schema, 0); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
- ++i;
- }
- if (i != keys.key_count) {
- if (log) {
- LOGERR(schema->module->ctx, LY_EINVAL, "List \"%s\" is missing some keys.", schema->name);
- }
- ret = LY_EINVAL;
- goto cleanup;
- }
-
/* create and insert all the keys */
- for (i = 0; i < keys.key_count; ++i) {
- if (keys_format == LYD_JSON) {
- ret = lyd_create_term((struct lysc_node *)keys.keys[i].schema, keys.keys[i].value, strlen(keys.keys[i].value),
- NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &key);
- } else {
- assert(keys_format == LYD_SCHEMA);
- ret = lyd_create_term((struct lysc_node *)keys.keys[i].schema, keys.keys[i].value, strlen(keys.keys[i].value),
- NULL, lys_resolve_prefix, NULL, LYD_SCHEMA, &key);
- }
- LY_CHECK_GOTO(ret && (ret != LY_EINCOMPLETE), cleanup);
- ret = LY_SUCCESS;
+ LY_ARRAY_FOR(predicates, u) {
+ LY_CHECK_GOTO(ret = lyd_create_term2(predicates[u].key, &predicates[u].value, &key), cleanup);
lyd_insert_node(list, NULL, key);
}
@@ -701,7 +673,32 @@
cleanup:
lyd_free_tree(list);
- ly_keys_clean(&keys);
+ return ret;
+}
+
+static LY_ERR
+lyd_create_list2(const struct lysc_node *schema, const char *keys, size_t keys_len, struct lyd_node **node)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lyxp_expr *expr = NULL;
+ uint16_t exp_idx = 0;
+ enum ly_path_pred_type pred_type = 0;
+ struct ly_path_predicate *predicates = NULL;
+
+ /* parse keys */
+ LY_CHECK_GOTO(ret = ly_path_parse_predicate(schema->module->ctx, keys, keys_len, LY_PATH_PREFIX_OPTIONAL,
+ LY_PATH_PRED_KEYS, &expr), cleanup);
+
+ /* compile them */
+ LY_CHECK_GOTO(ret = ly_path_compile_predicate(schema->module, schema, expr, &exp_idx, lydjson_resolve_prefix, NULL,
+ LYD_JSON, &predicates, &pred_type), cleanup);
+
+ /* create the list node */
+ LY_CHECK_GOTO(ret = lyd_create_list(schema, predicates, node), cleanup);
+
+cleanup:
+ lyxp_expr_free(schema->module->ctx, expr);
+ ly_path_predicates_free(schema->module->ctx, pred_type, NULL, predicates);
return ret;
}
@@ -848,11 +845,23 @@
if (!module) {
module = parent->schema->module;
}
+ if (!keys) {
+ keys = "";
+ }
+ /* find schema node */
schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, 0);
LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "List node \"%s\" not found.", name), NULL);
- if (!lyd_create_list(schema, keys, keys ? strlen(keys) : 0, LYD_JSON, 1, &ret) && parent) {
+ if ((schema->flags & LYS_KEYLESS) && !keys[0]) {
+ /* key-less list */
+ LY_CHECK_RET(lyd_create_inner(schema, &ret), NULL);
+ } else {
+ /* create the list node */
+ LY_CHECK_RET(lyd_create_list2(schema, keys, strlen(keys), &ret), NULL);
+ }
+
+ if (parent) {
lyd_insert_node(parent, NULL, ret);
}
return ret;
@@ -930,7 +939,7 @@
str = strndup(name, name_len);
module = ly_ctx_get_module_implemented(ctx, str);
free(str);
- LY_CHECK_ERR_RET(!module, LOGERR(ctx, LY_EINVAL, "Module \"%*.s\" not found.", pref_len, prefix), NULL);
+ LY_CHECK_ERR_RET(!module, LOGERR(ctx, LY_EINVAL, "Module \"%.*s\" not found.", pref_len, prefix), NULL);
}
/* set value if none */
@@ -1532,84 +1541,15 @@
}
API const struct lyd_node_term *
-lyd_target(struct lyd_value_path *path, const struct lyd_node *tree)
+lyd_target(const struct ly_path *path, const struct lyd_node *tree)
{
- LY_ARRAY_SIZE_TYPE u, v;
- const struct lyd_node *start_sibling;
- struct lyd_node *node = NULL;
- uint64_t pos = 1;
- int match;
+ struct lyd_node *target;
- LY_CHECK_ARG_RET(NULL, path, tree, NULL);
-
- /* first iteration */
- start_sibling = tree;
- u = 0;
- while (u < LY_ARRAY_SIZE(path)) {
- /* find next node instance */
- if (start_sibling && !start_sibling->prev->next && !(path[u].node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
- /* starting from the beginning using hashes */
- lyd_find_sibling_val(start_sibling, path[u].node, NULL, 0, &node);
- } else {
- /* next matching sibling */
- lyd_find_sibling_next2(start_sibling, path[u].node, NULL, 0, &node);
- }
- if (!node) {
- break;
- }
-
- /* check predicate if any */
- match = 1;
- LY_ARRAY_FOR(path[u].predicates, v) {
- if (path[u].predicates[v].type == 0) {
- assert(LY_ARRAY_SIZE(path[u].predicates) == 1);
- /* position predicate */
- if (pos != path[u].predicates[v].position) {
- pos++;
- match = 0;
- }
- } else if (path[u].predicates[v].type == 1) {
- /* key-predicate */
- struct lysc_type *type = ((struct lysc_node_leaf *)path[u].predicates[v].key)->type;
- struct lyd_node *key;
-
- lyd_find_sibling_val(lyd_node_children(node), path[u].predicates[v].key, NULL, 0, &key);
- if (!key) {
- /* probably error and we shouldn't be here due to previous checks when creating path */
- match = 0;
- } else if (type->plugin->compare(&((struct lyd_node_term *)key)->value, path[u].predicates[v].value)) {
- match = 0;
- }
- } else if (path[u].predicates[v].type == 2) {
- /* leaf-list-predicate */
- struct lysc_type *type = ((struct lysc_node_leaf *)path[u].node)->type;
-
- if (type->plugin->compare(&((struct lyd_node_term *)node)->value, path[u].predicates[v].value)) {
- match = 0;
- }
- } else {
- LOGINT(NULL);
- return NULL;
- }
-
- if (!match) {
- /* useless to check more predicates */
- break;
- }
- }
-
- if (!match) {
- /* try to match next sibling */
- start_sibling = node->next;
- } else {
- /* matched, move to the next path segment */
- ++u;
- start_sibling = lyd_node_children(node);
- pos = 1;
- }
+ if (ly_path_eval(path, tree, &target)) {
+ return NULL;
}
- return (const struct lyd_node_term *)node;
+ return (struct lyd_node_term *)target;
}
API LY_ERR
@@ -2644,7 +2584,7 @@
case LYS_RPC:
case LYS_ACTION:
case LYS_LEAF:
- /* find it based on schema only */
+ /* find it based on schema only, there cannot be more instances */
rc = lyd_find_sibling_schema(siblings, schema, match);
break;
case LYS_LEAFLIST:
@@ -2656,7 +2596,7 @@
case LYS_LIST:
if (schema->nodetype == LYS_LIST) {
/* target used attributes: schema, hash, child (all keys) */
- LY_CHECK_RET(lyd_create_list(schema, key_or_value, val_len, LYD_JSON, 1, &target));
+ LY_CHECK_RET(lyd_create_list2(schema, key_or_value, val_len, &target));
}
/* find it */
@@ -2685,7 +2625,7 @@
memset(&xp_set, 0, sizeof xp_set);
/* compile expression */
- exp = lyxp_expr_parse((struct ly_ctx *)LYD_NODE_CTX(ctx_node), xpath);
+ exp = lyxp_expr_parse((struct ly_ctx *)LYD_NODE_CTX(ctx_node), xpath, 0, 1);
LY_CHECK_ERR_GOTO(!exp, ret = LY_EINVAL, cleanup);
/* evaluate expression */