path FEATURE variables instead of values

Supported now for node-instance-identifier.
diff --git a/src/path.c b/src/path.c
index e455b75..4ee9832 100644
--- a/src/path.c
+++ b/src/path.c
@@ -3,7 +3,7 @@
  * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief Path functions
  *
- * Copyright (c) 2020 CESNET, z.s.p.o.
+ * Copyright (c) 2020 - 2023 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.
@@ -11,6 +11,9 @@
  *
  *     https://opensource.org/licenses/BSD-3-Clause
  */
+
+#define _GNU_SOURCE
+
 #include "path.h"
 
 #include <assert.h>
@@ -106,8 +109,14 @@
                 /* '=' */
                 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
 
-                /* Literal or Number */
-                LY_CHECK_GOTO(lyxp_next_token2(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL, LYXP_TOKEN_NUMBER), token_error);
+                /* Literal, Number, or VariableReference */
+                if (lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_LITERAL) &&
+                        lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER) &&
+                        lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_VARREF)) {
+                    /* error */
+                    lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL);
+                    goto token_error;
+                }
 
                 /* ']' */
                 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
@@ -528,7 +537,7 @@
 LY_ERR
 ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
         const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint32_t *tok_idx, LY_VALUE_FORMAT format,
-        void *prefix_data, struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
+        void *prefix_data, struct ly_path_predicate **predicates)
 {
     LY_ERR ret = LY_SUCCESS;
     struct ly_path_predicate *p;
@@ -540,7 +549,7 @@
 
     LOG_LOCSET(cur_node, NULL, NULL, NULL);
 
-    *pred_type = 0;
+    *predicates = NULL;
 
     if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
         /* '[', no predicate */
@@ -572,11 +581,7 @@
             }
             ++(*tok_idx);
 
-            if (!*pred_type) {
-                /* new predicate */
-                *pred_type = LY_PATH_PREDTYPE_LIST;
-            }
-            assert(*pred_type == LY_PATH_PREDTYPE_LIST);
+            /* new predicate */
             LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
             p->key = key;
 
@@ -584,28 +589,39 @@
             assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
             ++(*tok_idx);
 
-            /* Literal or Number */
-            assert((expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) || (expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER));
-            if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
-                /* skip quotes */
-                val = expr->expr + expr->tok_pos[*tok_idx] + 1;
-                val_len = expr->tok_len[*tok_idx] - 2;
+            /* Literal, Number, or VariableReference */
+            if (expr->tokens[*tok_idx] == LYXP_TOKEN_VARREF) {
+                /* store the variable name */
+                p->variable = strndup(expr->expr + expr->tok_pos[*tok_idx], expr->tok_len[*tok_idx]);
+                LY_CHECK_ERR_GOTO(!p->variable, LOGMEM(ctx); ret = LY_EMEM, cleanup);
+
+                p->type = LY_PATH_PREDTYPE_LIST_VAR;
+                ++(*tok_idx);
             } else {
-                val = expr->expr + expr->tok_pos[*tok_idx];
-                val_len = expr->tok_len[*tok_idx];
+                if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
+                    /* skip quotes */
+                    val = expr->expr + expr->tok_pos[*tok_idx] + 1;
+                    val_len = expr->tok_len[*tok_idx] - 2;
+                } else {
+                    assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
+                    val = expr->expr + expr->tok_pos[*tok_idx];
+                    val_len = expr->tok_len[*tok_idx];
+                }
+
+                /* store the value */
+                LOG_LOCSET(key, NULL, NULL, NULL);
+                ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, NULL, format,
+                        prefix_data, LYD_HINT_DATA, key, NULL);
+                LOG_LOCBACK(key ? 1 : 0, 0, 0, 0);
+                LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
+
+                /* "allocate" the type to avoid problems when freeing the value after the type was freed */
+                LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
+
+                p->type = LY_PATH_PREDTYPE_LIST;
+                ++(*tok_idx);
             }
 
-            /* store the value */
-            LOG_LOCSET(key, NULL, NULL, NULL);
-            ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, NULL, format,
-                    prefix_data, LYD_HINT_DATA, key, NULL);
-            LOG_LOCBACK(key ? 1 : 0, 0, 0, 0);
-            LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
-            ++(*tok_idx);
-
-            /* "allocate" the type to avoid problems when freeing the value after the type was freed */
-            LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
-
             /* ']' */
             assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
             ++(*tok_idx);
@@ -622,7 +638,7 @@
             /* names (keys) are unique - it was checked when parsing */
             LOGVAL(ctx, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
                     lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
-            ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, *predicates);
+            ly_path_predicates_free(ctx, *predicates);
             *predicates = NULL;
             ret = LY_EVALID;
             goto cleanup;
@@ -638,8 +654,8 @@
         ++(*tok_idx);
 
         /* new predicate */
-        *pred_type = LY_PATH_PREDTYPE_LEAFLIST;
         LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
+        p->type = LY_PATH_PREDTYPE_LEAFLIST;
 
         /* '=' */
         assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
@@ -685,8 +701,8 @@
         }
 
         /* new predicate */
-        *pred_type = LY_PATH_PREDTYPE_POSITION;
         LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
+        p->type = LY_PATH_PREDTYPE_POSITION;
 
         /* syntax was already checked */
         p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&val, LY_BASE_DEC);
@@ -947,7 +963,7 @@
             ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data);
         } else {
             ret = ly_path_compile_predicate(ctx, cur_node, cur_mod, ctx_node, expr, &tok_idx, format, prefix_data,
-                    &p->predicates, &p->pred_type);
+                    &p->predicates);
         }
         LY_CHECK_GOTO(ret, cleanup);
     } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
@@ -994,8 +1010,8 @@
 }
 
 LY_ERR
-ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, LY_ARRAY_COUNT_TYPE *path_idx,
-        struct lyd_node **match)
+ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, const struct lyxp_var *vars,
+        LY_ARRAY_COUNT_TYPE *path_idx, struct lyd_node **match)
 {
     LY_ARRAY_COUNT_TYPE u;
     struct lyd_node *prev_node = NULL, *elem, *node = NULL, *target;
@@ -1017,35 +1033,37 @@
     }
 
     LY_ARRAY_FOR(path, u) {
-        switch (path[u].pred_type) {
-        case LY_PATH_PREDTYPE_POSITION:
-            /* we cannot use hashes and want an instance on a specific position */
-            pos = 1;
-            node = NULL;
-            LYD_LIST_FOR_INST(start, path[u].node, elem) {
-                if (pos == path[u].predicates[0].position) {
-                    node = elem;
-                    break;
+        if (path[u].predicates) {
+            switch (path[u].predicates[0].type) {
+            case LY_PATH_PREDTYPE_POSITION:
+                /* we cannot use hashes and want an instance on a specific position */
+                pos = 1;
+                node = NULL;
+                LYD_LIST_FOR_INST(start, path[u].node, elem) {
+                    if (pos == path[u].predicates[0].position) {
+                        node = elem;
+                        break;
+                    }
+                    ++pos;
                 }
-                ++pos;
+                break;
+            case LY_PATH_PREDTYPE_LEAFLIST:
+                /* we will use hashes to find one leaf-list instance */
+                LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
+                lyd_find_sibling_first(start, target, &node);
+                lyd_free_tree(target);
+                break;
+            case LY_PATH_PREDTYPE_LIST_VAR:
+            case LY_PATH_PREDTYPE_LIST:
+                /* we will use hashes to find one list instance */
+                LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, vars, &target));
+                lyd_find_sibling_first(start, target, &node);
+                lyd_free_tree(target);
+                break;
             }
-            break;
-        case LY_PATH_PREDTYPE_LEAFLIST:
-            /* we will use hashes to find one leaf-list instance */
-            LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
-            lyd_find_sibling_first(start, target, &node);
-            lyd_free_tree(target);
-            break;
-        case LY_PATH_PREDTYPE_LIST:
-            /* we will use hashes to find one list instance */
-            LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, &target));
-            lyd_find_sibling_first(start, target, &node);
-            lyd_free_tree(target);
-            break;
-        case LY_PATH_PREDTYPE_NONE:
+        } else {
             /* we will use hashes to find one any/container/leaf instance */
             lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
-            break;
         }
 
         if (!node) {
@@ -1092,12 +1110,12 @@
 }
 
 LY_ERR
-ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match)
+ly_path_eval(const struct ly_path *path, const struct lyd_node *start, const struct lyxp_var *vars, struct lyd_node **match)
 {
     LY_ERR ret;
     struct lyd_node *m;
 
-    ret = ly_path_eval_partial(path, start, NULL, &m);
+    ret = ly_path_eval_partial(path, start, vars, NULL, &m);
 
     if (ret == LY_SUCCESS) {
         /* last node was found */
@@ -1129,12 +1147,13 @@
         (*dup)[u].node = path[u].node;
         if (path[u].predicates) {
             LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
-            (*dup)[u].pred_type = path[u].pred_type;
             LY_ARRAY_FOR(path[u].predicates, v) {
                 struct ly_path_predicate *pred = &path[u].predicates[v];
 
                 LY_ARRAY_INCREMENT((*dup)[u].predicates);
-                switch (path[u].pred_type) {
+                (*dup)[u].predicates[v].type = pred->type;
+
+                switch (pred->type) {
                 case LY_PATH_PREDTYPE_POSITION:
                     /* position-predicate */
                     (*dup)[u].predicates[v].position = pred->position;
@@ -1146,7 +1165,10 @@
                     pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
                     LY_ATOMIC_INC_BARRIER(((struct lysc_type *)pred->value.realtype)->refcount);
                     break;
-                case LY_PATH_PREDTYPE_NONE:
+                case LY_PATH_PREDTYPE_LIST_VAR:
+                    /* key-predicate with a variable */
+                    (*dup)[u].predicates[v].key = pred->key;
+                    (*dup)[u].predicates[v].variable = strdup(pred->variable);
                     break;
                 }
             }
@@ -1157,7 +1179,7 @@
 }
 
 void
-ly_path_predicates_free(const struct ly_ctx *ctx, enum ly_path_pred_type pred_type, struct ly_path_predicate *predicates)
+ly_path_predicates_free(const struct ly_ctx *ctx, struct ly_path_predicate *predicates)
 {
     LY_ARRAY_COUNT_TYPE u;
     struct lysf_ctx fctx = {.ctx = (struct ly_ctx *)ctx};
@@ -1167,9 +1189,8 @@
     }
 
     LY_ARRAY_FOR(predicates, u) {
-        switch (pred_type) {
+        switch (predicates[u].type) {
         case LY_PATH_PREDTYPE_POSITION:
-        case LY_PATH_PREDTYPE_NONE:
             /* nothing to free */
             break;
         case LY_PATH_PREDTYPE_LIST:
@@ -1179,6 +1200,9 @@
                 lysc_type_free(&fctx, (struct lysc_type *)predicates[u].value.realtype);
             }
             break;
+        case LY_PATH_PREDTYPE_LIST_VAR:
+            free(predicates[u].variable);
+            break;
         }
     }
     LY_ARRAY_FREE(predicates);
@@ -1194,7 +1218,7 @@
     }
 
     LY_ARRAY_FOR(path, u) {
-        ly_path_predicates_free(ctx, path[u].pred_type, path[u].predicates);
+        ly_path_predicates_free(ctx, path[u].predicates);
     }
     LY_ARRAY_FREE(path);
 }
diff --git a/src/path.h b/src/path.h
index 674dd54..aec1d36 100644
--- a/src/path.h
+++ b/src/path.h
@@ -3,7 +3,7 @@
  * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief Path structure and manipulation routines.
  *
- * Copyright (c) 2020 CESNET, z.s.p.o.
+ * Copyright (c) 2020 - 2023 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.
@@ -29,24 +29,25 @@
 struct lyxp_expr;
 
 enum ly_path_pred_type {
-    LY_PATH_PREDTYPE_NONE = 0,  /**< no predicate */
     LY_PATH_PREDTYPE_POSITION,  /**< position predicate - [2] */
     LY_PATH_PREDTYPE_LIST,      /**< keys predicate - [key1='val1'][key2='val2']... */
-    LY_PATH_PREDTYPE_LEAFLIST   /**< leaflist value predicate - [.='value'] */
+    LY_PATH_PREDTYPE_LEAFLIST,  /**< leaflist value predicate - [.='value'] */
+    LY_PATH_PREDTYPE_LIST_VAR   /**< keys predicate with variable instead of value - [key1=$USER]... */
 };
 
 /**
  * @brief Structure for simple path predicate.
  */
 struct ly_path_predicate {
+    enum ly_path_pred_type type;            /**< Predicate type (see YANG ABNF) */
     union {
-        uint64_t position; /**< position value for the position-predicate */
-
+        uint64_t position;                  /**< position value for the position-predicate */
         struct {
-            const struct lysc_node *key; /**< key node of the predicate, NULL in
-                                            case of a leaf-list predicate */
-            struct lyd_value value; /**< value representation according to the
-                                       key's type, its realtype is allocated */
+            const struct lysc_node *key;    /**< key node of the predicate, NULL in case of a leaf-list predicate */
+            union {
+                struct lyd_value value;     /**< stored value representation according to the key's type (realtype ref) */
+                char *variable;             /**< XPath variable used instead of the value */
+            };
         };
     };
 };
@@ -61,7 +62,6 @@
                                        - is inner node - path is relative */
     const struct lysc_ext_instance *ext;    /**< Extension instance of @p node, if any */
     struct ly_path_predicate *predicates;   /**< [Sized array](@ref sizedarrays) of the path segment's predicates */
-    enum ly_path_pred_type pred_type;       /**< Predicate type (see YANG ABNF) */
 };
 
 /**
@@ -87,10 +87,10 @@
  * @defgroup path_pred_options Path predicate options.
  * @{
  */
-#define LY_PATH_PRED_KEYS       0x0100    /* expected predicate only - [node='value']* */
-#define LY_PATH_PRED_SIMPLE     0x0200    /* expected predicates - [node='value']*; [.='value']; [1] */
-#define LY_PATH_PRED_LEAFREF    0x0400  /* expected predicates only leafref - [node=current()/../../../node/node];
-                                           at least 1 ".." and 1 "node" after */
+#define LY_PATH_PRED_KEYS       0x0100  /** expected predicate only - [node='value']* */
+#define LY_PATH_PRED_SIMPLE     0x0200  /** expected predicates - ( [node='value'] | [node=$VAR] )*; [.='value']; [1] */
+#define LY_PATH_PRED_LEAFREF    0x0400  /** expected predicates only leafref - [node=current()/../../../node/node];
+                                            at least 1 ".." and 1 "node" after */
 /** @} */
 
 /**
@@ -199,18 +199,18 @@
  * @param[in] format Format of the path.
  * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
  * @param[out] predicates Compiled predicates.
- * @param[out] pred_type Type of the compiled predicate(s).
  * @return LY_ERR value.
  */
 LY_ERR ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
         const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint32_t *tok_idx, LY_VALUE_FORMAT format,
-        void *prefix_data, struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type);
+        void *prefix_data, struct ly_path_predicate **predicates);
 
 /**
  * @brief Resolve at least partially the target defined by ly_path structure. Not supported for leafref!
  *
  * @param[in] path Path structure specifying the target.
  * @param[in] start Starting node for relative paths, can be any for absolute paths.
+ * @param[in] vars Array of defined variables to use in predicates, may be NULL.
  * @param[out] path_idx Last found path segment index, can be NULL, set to 0 if not found.
  * @param[out] match Last found matching node, can be NULL, set to NULL if not found.
  * @return LY_ENOTFOUND if no nodes were found,
@@ -218,20 +218,22 @@
  * @return LY_SUCCESS when the last node in the path was found,
  * @return LY_ERR on another error.
  */
-LY_ERR ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, LY_ARRAY_COUNT_TYPE *path_idx,
-        struct lyd_node **match);
+LY_ERR ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, const struct lyxp_var *vars,
+        LY_ARRAY_COUNT_TYPE *path_idx, struct lyd_node **match);
 
 /**
  * @brief Resolve the target defined by ly_path structure. Not supported for leafref!
  *
  * @param[in] path Path structure specifying the target.
  * @param[in] start Starting node for relative paths, can be any for absolute paths.
+ * @param[in] vars Array of defined variables to use in predicates, may be NULL.
  * @param[out] match Found matching node, can be NULL, set to NULL if not found.
  * @return LY_ENOTFOUND if no nodes were found,
  * @return LY_SUCCESS when the last node in the path was found,
  * @return LY_ERR on another error.
  */
-LY_ERR ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match);
+LY_ERR ly_path_eval(const struct ly_path *path, const struct lyd_node *start, const struct lyxp_var *vars,
+        struct lyd_node **match);
 
 /**
  * @brief Duplicate ly_path structure.
@@ -247,11 +249,9 @@
  * @brief Free ly_path_predicate structure.
  *
  * @param[in] ctx libyang context.
- * @param[in] pred_type Predicate type.
  * @param[in] predicates Predicates ([sized array](@ref sizedarrays)) to free.
  */
-void ly_path_predicates_free(const struct ly_ctx *ctx, enum ly_path_pred_type pred_type,
-        struct ly_path_predicate *predicates);
+void ly_path_predicates_free(const struct ly_ctx *ctx, struct ly_path_predicate *predicates);
 
 /**
  * @brief Free ly_path structure.
diff --git a/src/plugins_types/instanceid.c b/src/plugins_types/instanceid.c
index d151d0a..0eef9cc 100644
--- a/src/plugins_types/instanceid.c
+++ b/src/plugins_types/instanceid.c
@@ -84,9 +84,7 @@
         LY_ARRAY_FOR(path[u].predicates, v) {
             struct ly_path_predicate *pred = &path[u].predicates[v];
 
-            switch (path[u].pred_type) {
-            case LY_PATH_PREDTYPE_NONE:
-                break;
+            switch (pred->type) {
             case LY_PATH_PREDTYPE_POSITION:
                 /* position predicate */
                 ret = ly_strcat(&result, "[%" PRIu64 "]", pred->position);
@@ -127,6 +125,10 @@
                     free((char *)strval);
                 }
                 break;
+            case LY_PATH_PREDTYPE_LIST_VAR:
+                LOGINT(path[u].node->module->ctx);
+                ret = LY_EINT;
+                goto cleanup;
             }
 
             LY_CHECK_GOTO(ret, cleanup);
@@ -162,7 +164,7 @@
 
     /* compile instance-identifier into path */
     if (format == LY_VALUE_LYB) {
-        /* The @p value in LYB format is the same as in JSON format. */
+        /* value in LYB format is the same as in JSON format. */
         ret = lyplg_type_lypath_new(ctx, value, value_len, options, LY_VALUE_JSON, prefix_data, ctx_node,
                 unres, &path, err);
     } else {
@@ -231,7 +233,7 @@
     }
 
     /* find the target in data */
-    if ((ret = ly_path_eval(storage->target, tree, NULL))) {
+    if ((ret = ly_path_eval(storage->target, tree, NULL, NULL))) {
         value = lyplg_type_print_instanceid(ctx, storage, LY_VALUE_CANON, NULL, NULL, NULL);
         path = lyd_path(ctx_node, LYD_PATH_STD, NULL, 0);
         return ly_err_new(err, ret, LYVE_DATA, path, strdup("instance-required"), LY_ERRMSG_NOINST, value);
@@ -259,37 +261,43 @@
         struct ly_path *s1 = &val1->target[u];
         struct ly_path *s2 = &val2->target[u];
 
-        if ((s1->node != s2->node) || (s1->pred_type != s2->pred_type) ||
-                (s1->predicates && (LY_ARRAY_COUNT(s1->predicates) != LY_ARRAY_COUNT(s2->predicates)))) {
+        if ((s1->node != s2->node) || (s1->predicates && (LY_ARRAY_COUNT(s1->predicates) != LY_ARRAY_COUNT(s2->predicates)))) {
             return LY_ENOT;
         }
-        if (s1->predicates) {
-            LY_ARRAY_FOR(s1->predicates, v) {
-                struct ly_path_predicate *pred1 = &s1->predicates[v];
-                struct ly_path_predicate *pred2 = &s2->predicates[v];
+        LY_ARRAY_FOR(s1->predicates, v) {
+            struct ly_path_predicate *pred1 = &s1->predicates[v];
+            struct ly_path_predicate *pred2 = &s2->predicates[v];
 
-                switch (s1->pred_type) {
-                case LY_PATH_PREDTYPE_NONE:
-                    break;
-                case LY_PATH_PREDTYPE_POSITION:
-                    /* position predicate */
-                    if (pred1->position != pred2->position) {
-                        return LY_ENOT;
-                    }
-                    break;
-                case LY_PATH_PREDTYPE_LIST:
-                    /* key-predicate */
-                    if ((pred1->key != pred2->key) ||
-                            ((struct lysc_node_leaf *)pred1->key)->type->plugin->compare(&pred1->value, &pred2->value)) {
-                        return LY_ENOT;
-                    }
-                    break;
-                case LY_PATH_PREDTYPE_LEAFLIST:
-                    /* leaf-list predicate */
-                    if (((struct lysc_node_leaflist *)s1->node)->type->plugin->compare(&pred1->value, &pred2->value)) {
-                        return LY_ENOT;
-                    }
+            if (pred1->type != pred2->type) {
+                return LY_ENOT;
+            }
+
+            switch (pred1->type) {
+            case LY_PATH_PREDTYPE_POSITION:
+                /* position predicate */
+                if (pred1->position != pred2->position) {
+                    return LY_ENOT;
                 }
+                break;
+            case LY_PATH_PREDTYPE_LIST:
+                /* key-predicate */
+                if ((pred1->key != pred2->key) ||
+                        ((struct lysc_node_leaf *)pred1->key)->type->plugin->compare(&pred1->value, &pred2->value)) {
+                    return LY_ENOT;
+                }
+                break;
+            case LY_PATH_PREDTYPE_LEAFLIST:
+                /* leaf-list predicate */
+                if (((struct lysc_node_leaflist *)s1->node)->type->plugin->compare(&pred1->value, &pred2->value)) {
+                    return LY_ENOT;
+                }
+                break;
+            case LY_PATH_PREDTYPE_LIST_VAR:
+                /* key-predicate with a variable */
+                if ((pred1->key != pred2->key) || strcmp(pred1->variable, pred2->variable)) {
+                    return LY_ENOT;
+                }
+                break;
             }
         }
     }
diff --git a/src/plugins_types/node_instanceid.c b/src/plugins_types/node_instanceid.c
index 04fb164..00cf207 100644
--- a/src/plugins_types/node_instanceid.c
+++ b/src/plugins_types/node_instanceid.c
@@ -90,9 +90,7 @@
         LY_ARRAY_FOR(path[u].predicates, v) {
             struct ly_path_predicate *pred = &path[u].predicates[v];
 
-            switch (path[u].pred_type) {
-            case LY_PATH_PREDTYPE_NONE:
-                break;
+            switch (pred->type) {
             case LY_PATH_PREDTYPE_POSITION:
                 /* position predicate */
                 ret = ly_strcat(&result, "[%" PRIu64 "]", pred->position);
@@ -133,6 +131,16 @@
                     free((char *)strval);
                 }
                 break;
+            case LY_PATH_PREDTYPE_LIST_VAR:
+                /* key-predicate with a variable */
+                if (inherit_prefix) {
+                    /* always the same prefix as the parent */
+                    ret = ly_strcat(&result, "[%s=$%s]", pred->key->name, pred->variable);
+                } else {
+                    ret = ly_strcat(&result, "[%s:%s=$%s]", lyplg_type_get_prefix(pred->key->module, format, prefix_data),
+                            pred->key->name, pred->variable);
+                }
+                break;
             }
 
             LY_CHECK_GOTO(ret, cleanup);
@@ -193,7 +201,7 @@
     ret = ly_path_parse(ctx, ctx_node, value, value_len, 0, LY_PATH_BEGIN_ABSOLUTE, prefix_opt, LY_PATH_PRED_SIMPLE, &exp);
     if (ret) {
         ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
-                "Invalid instance-identifier \"%.*s\" value - syntax error.", (int)value_len, (char *)value);
+                "Invalid node-instance-identifier \"%.*s\" value - syntax error.", (int)value_len, (char *)value);
         goto cleanup;
     }
 
@@ -209,7 +217,7 @@
             LY_VALUE_JSON : format, prefix_data, &path);
     if (ret) {
         ret = ly_err_new(err, ret, LYVE_DATA, NULL, NULL,
-                "Invalid instance-identifier \"%.*s\" value - semantic error.", (int)value_len, (char *)value);
+                "Invalid node-instance-identifier \"%.*s\" value - semantic error.", (int)value_len, (char *)value);
         goto cleanup;
     }
 
diff --git a/src/tree_data.c b/src/tree_data.c
index 6c2061d..ecfea86 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -1110,11 +1110,9 @@
 LIBYANG_API_DEF const struct lyd_node_term *
 lyd_target(const struct ly_path *path, const struct lyd_node *tree)
 {
-    struct lyd_node *target;
+    struct lyd_node *target = NULL;
 
-    if (ly_path_eval(path, tree, &target)) {
-        return NULL;
-    }
+    lyd_find_target(path, tree, &target);
 
     return (struct lyd_node_term *)target;
 }
@@ -2936,7 +2934,7 @@
     LY_CHECK_GOTO(ret, cleanup);
 
     /* evaluate the path */
-    ret = ly_path_eval_partial(lypath, ctx_node, NULL, match);
+    ret = ly_path_eval_partial(lypath, ctx_node, NULL, NULL, match);
 
 cleanup:
     lyxp_expr_free(LYD_CTX(ctx_node), expr);
@@ -2952,7 +2950,7 @@
 
     LY_CHECK_ARG_RET(NULL, path, LY_EINVAL);
 
-    ret = ly_path_eval(path, tree, &m);
+    ret = ly_path_eval(path, tree, NULL, &m);
     if (ret) {
         if (match) {
             *match = NULL;
diff --git a/src/tree_data_common.c b/src/tree_data_common.c
index b39b144..0275ad5 100644
--- a/src/tree_data_common.c
+++ b/src/tree_data_common.c
@@ -220,12 +220,12 @@
         return LY_EINVAL;
     }
 
-    /* If variable is already defined then change its value. */
-    if (*vars && !lyxp_vars_find(*vars, name, 0, &item)) {
+    /* if variable is already defined then change its value */
+    if (*vars && !lyxp_vars_find(NULL, *vars, name, 0, &item)) {
         var_value = strdup(value);
         LY_CHECK_RET(!var_value, LY_EMEM);
 
-        /* Set new value. */
+        /* update value */
         free(item->value);
         item->value = var_value;
     } else {
@@ -233,7 +233,7 @@
         var_value = strdup(value);
         LY_CHECK_ERR_GOTO(!var_name || !var_value, ret = LY_EMEM, error);
 
-        /* Add new variable. */
+        /* add new variable */
         LY_ARRAY_NEW_GOTO(NULL, *vars, item, ret, error);
         item->name = var_name;
         item->value = var_value;
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index 3cd3d19..40bc562 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -280,11 +280,13 @@
  *
  * @param[in] schema Schema node of the new data node.
  * @param[in] predicates Compiled key list predicates.
+ * @param[in] vars Array of defined variables to use in predicates, may be NULL.
  * @param[out] node Created node.
  * @return LY_SUCCESS on success.
  * @return LY_ERR value if an error occurred.
  */
-LY_ERR lyd_create_list(const struct lysc_node *schema, const struct ly_path_predicate *predicates, struct lyd_node **node);
+LY_ERR lyd_create_list(const struct lysc_node *schema, const struct ly_path_predicate *predicates,
+        const struct lyxp_var *vars, struct lyd_node **node);
 
 /**
  * @brief Create a list with all its keys (cannot be used for key-less list).
diff --git a/src/tree_data_new.c b/src/tree_data_new.c
index 864fc9e..d647be3 100644
--- a/src/tree_data_new.c
+++ b/src/tree_data_new.c
@@ -134,10 +134,14 @@
 }
 
 LY_ERR
-lyd_create_list(const struct lysc_node *schema, const struct ly_path_predicate *predicates, struct lyd_node **node)
+lyd_create_list(const struct lysc_node *schema, const struct ly_path_predicate *predicates, const struct lyxp_var *vars,
+        struct lyd_node **node)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyd_node *list = NULL, *key;
+    const struct lyd_value *value;
+    struct lyd_value val = {0};
+    struct lyxp_var *var;
     LY_ARRAY_COUNT_TYPE u;
 
     assert((schema->nodetype == LYS_LIST) && !(schema->flags & LYS_KEYLESS));
@@ -149,7 +153,31 @@
 
     /* create and insert all the keys */
     LY_ARRAY_FOR(predicates, u) {
-        LY_CHECK_GOTO(ret = lyd_create_term2(predicates[u].key, &predicates[u].value, &key), cleanup);
+        if (predicates[u].type == LY_PATH_PREDTYPE_LIST_VAR) {
+            /* find the var */
+            if ((ret = lyxp_vars_find(schema->module->ctx, vars, predicates[u].variable, 0, &var))) {
+                goto cleanup;
+            }
+
+            /* store the value */
+            LOG_LOCSET(predicates[u].key, NULL, NULL, NULL);
+            ret = lyd_value_store(schema->module->ctx, &val, ((struct lysc_node_leaf *)predicates[u].key)->type,
+                    var->value, strlen(var->value), NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, predicates[u].key, NULL);
+            LOG_LOCBACK(1, 0, 0, 0);
+            LY_CHECK_GOTO(ret, cleanup);
+
+            value = &val;
+        } else {
+            assert(predicates[u].type == LY_PATH_PREDTYPE_LIST);
+            value = &predicates[u].value;
+        }
+
+        ret = lyd_create_term2(predicates[u].key, value, &key);
+        if (val.realtype) {
+            val.realtype->plugin->free(schema->module->ctx, &val);
+            memset(&val, 0, sizeof val);
+        }
+        LY_CHECK_GOTO(ret, cleanup);
         lyd_insert_node(list, NULL, key, 0);
     }
 
@@ -172,7 +200,6 @@
     LY_ERR ret = LY_SUCCESS;
     struct lyxp_expr *expr = NULL;
     uint32_t exp_idx = 0;
-    enum ly_path_pred_type pred_type = 0;
     struct ly_path_predicate *predicates = NULL;
 
     LOG_LOCSET(schema, NULL, NULL, NULL);
@@ -183,15 +210,15 @@
 
     /* compile them */
     LY_CHECK_GOTO(ret = ly_path_compile_predicate(schema->module->ctx, NULL, NULL, schema, expr, &exp_idx, LY_VALUE_JSON,
-            NULL, &predicates, &pred_type), cleanup);
+            NULL, &predicates), cleanup);
 
     /* create the list node */
-    LY_CHECK_GOTO(ret = lyd_create_list(schema, predicates, node), cleanup);
+    LY_CHECK_GOTO(ret = lyd_create_list(schema, predicates, NULL, node), cleanup);
 
 cleanup:
     LOG_LOCBACK(1, 0, 0, 0);
     lyxp_expr_free(schema->module->ctx, expr);
-    ly_path_predicates_free(schema->module->ctx, pred_type, predicates);
+    ly_path_predicates_free(schema->module->ctx, predicates);
     return ret;
 }
 
@@ -1320,18 +1347,19 @@
         schema = path[u].node;
 
         if (lysc_is_dup_inst_list(schema)) {
-            if (path[u].pred_type == LY_PATH_PREDTYPE_NONE) {
+            if (!path[u].predicates) {
                 /* creating a new key-less list or state leaf-list instance */
                 create = 1;
                 new_count = u;
-            } else if (path[u].pred_type != LY_PATH_PREDTYPE_POSITION) {
+            } else if (path[u].predicates[0].type != LY_PATH_PREDTYPE_POSITION) {
                 LOG_LOCSET(schema, NULL, NULL, NULL);
                 LOGVAL(schema->module->ctx, LYVE_XPATH, "Invalid predicate for %s \"%s\" in path \"%s\".",
                         lys_nodetype2str(schema->nodetype), schema->name, str_path);
                 LOG_LOCBACK(1, 0, 0, 0);
                 return LY_EINVAL;
             }
-        } else if ((schema->nodetype == LYS_LIST) && (path[u].pred_type != LY_PATH_PREDTYPE_LIST)) {
+        } else if ((schema->nodetype == LYS_LIST) &&
+                (!path[u].predicates || (path[u].predicates[0].type != LY_PATH_PREDTYPE_LIST))) {
             if ((u < LY_ARRAY_COUNT(path) - 1) || !(options & LYD_NEW_PATH_OPAQ)) {
                 LOG_LOCSET(schema, NULL, NULL, NULL);
                 LOGVAL(schema->module->ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path \"%s\".",
@@ -1339,7 +1367,8 @@
                 LOG_LOCBACK(1, 0, 0, 0);
                 return LY_EINVAL;
             } /* else creating an opaque list */
-        } else if ((schema->nodetype == LYS_LEAFLIST) && (path[u].pred_type != LY_PATH_PREDTYPE_LEAFLIST)) {
+        } else if ((schema->nodetype == LYS_LEAFLIST) &&
+                (!path[u].predicates || (path[u].predicates[0].type != LY_PATH_PREDTYPE_LEAFLIST))) {
             r = LY_SUCCESS;
             if (options & LYD_NEW_PATH_OPAQ) {
                 r = lyd_value_validate(NULL, schema, value, value_len, NULL, NULL, NULL);
@@ -1351,8 +1380,8 @@
                 ++((struct lysc_type *)val.realtype)->refcount;
 
                 /* store the new predicate so that it is used when searching for this instance */
-                path[u].pred_type = LY_PATH_PREDTYPE_LEAFLIST;
                 LY_ARRAY_NEW_RET(schema->module->ctx, path[u].predicates, pred, LY_EMEM);
+                pred->type = LY_PATH_PREDTYPE_LEAFLIST;
                 pred->value = val;
             } /* else we have opaq flag and the value is not valid, leave no predicate and then create an opaque node */
         }
@@ -1442,7 +1471,7 @@
 
     /* try to find any existing nodes in the path */
     if (parent) {
-        ret = ly_path_eval_partial(p, parent, &path_idx, &node);
+        ret = ly_path_eval_partial(p, parent, NULL, &path_idx, &node);
         if (ret == LY_SUCCESS) {
             if (orig_count == LY_ARRAY_COUNT(p)) {
                 /* the node exists, are we supposed to update it or is it just a default? */
@@ -1487,15 +1516,14 @@
             if (lysc_is_dup_inst_list(schema)) {
                 /* create key-less list instance */
                 LY_CHECK_GOTO(ret = lyd_create_inner(schema, &node), cleanup);
-            } else if ((options & LYD_NEW_PATH_OPAQ) && (p[path_idx].pred_type == LY_PATH_PREDTYPE_NONE)) {
+            } else if ((options & LYD_NEW_PATH_OPAQ) && !p[path_idx].predicates) {
                 /* creating opaque list without keys */
                 LY_CHECK_GOTO(ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0,
                         schema->module->name, strlen(schema->module->name), NULL, 0, NULL, LY_VALUE_JSON, NULL,
                         LYD_NODEHINT_LIST, &node), cleanup);
             } else {
                 /* create standard list instance */
-                assert(p[path_idx].pred_type == LY_PATH_PREDTYPE_LIST);
-                LY_CHECK_GOTO(ret = lyd_create_list(schema, p[path_idx].predicates, &node), cleanup);
+                LY_CHECK_GOTO(ret = lyd_create_list(schema, p[path_idx].predicates, NULL, &node), cleanup);
             }
             break;
         case LYS_CONTAINER:
@@ -1505,7 +1533,8 @@
             LY_CHECK_GOTO(ret = lyd_create_inner(schema, &node), cleanup);
             break;
         case LYS_LEAFLIST:
-            if ((options & LYD_NEW_PATH_OPAQ) && (p[path_idx].pred_type != LY_PATH_PREDTYPE_LEAFLIST)) {
+            if ((options & LYD_NEW_PATH_OPAQ) &&
+                    (!p[path_idx].predicates || (p[path_idx].predicates[0].type != LY_PATH_PREDTYPE_LEAFLIST))) {
                 /* we have not checked this only for dup-inst lists, otherwise it must be opaque */
                 r = LY_EVALID;
                 if (lysc_is_dup_inst_list(schema)) {
@@ -1522,13 +1551,13 @@
             }
 
             /* get value to set */
-            if (p[path_idx].pred_type == LY_PATH_PREDTYPE_LEAFLIST) {
+            if (p[path_idx].predicates && (p[path_idx].predicates[0].type == LY_PATH_PREDTYPE_LEAFLIST)) {
                 val = &p[path_idx].predicates[0].value;
             }
 
             /* create a leaf-list instance */
             if (val) {
-                LY_CHECK_GOTO(ret = lyd_create_term2(schema, &p[path_idx].predicates[0].value, &node), cleanup);
+                LY_CHECK_GOTO(ret = lyd_create_term2(schema, val, &node), cleanup);
             } else {
                 LY_CHECK_GOTO(ret = lyd_create_term(schema, value, value_len, NULL, format, NULL, LYD_HINT_DATA,
                         NULL, &node), cleanup);
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 3ec4574..26b7c11 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -600,8 +600,8 @@
     LY_ARRAY_FOR(path, u) {
         /* add nodes from the path */
         LY_CHECK_GOTO(ret = ly_set_add(*set, (void *)path[u].node, 0, NULL), cleanup);
-        if (path[u].pred_type == LY_PATH_PREDTYPE_LIST) {
-            LY_ARRAY_FOR(path[u].predicates, v) {
+        LY_ARRAY_FOR(path[u].predicates, v) {
+            if ((path[u].predicates[v].type == LY_PATH_PREDTYPE_LIST) || (path[u].predicates[v].type == LY_PATH_PREDTYPE_LIST_VAR)) {
                 /* add all the keys in a predicate */
                 LY_CHECK_GOTO(ret = ly_set_add(*set, (void *)path[u].predicates[v].key, 0, NULL), cleanup);
             }
diff --git a/src/xpath.c b/src/xpath.c
index b83e1cc..77d6c6c 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -4030,7 +4030,7 @@
                 }
             } else {
                 assert(sleaf->type->basetype == LY_TYPE_INST);
-                if (ly_path_eval(leaf->value.target, set->tree, &node)) {
+                if (ly_path_eval(leaf->value.target, set->tree, NULL, &node)) {
                     LOGERR(set->ctx, LY_EVALID, "Invalid instance-identifier \"%s\" value - required instance not found.",
                             lyd_get_value(&leaf->node));
                     return LY_EVALID;
@@ -6144,7 +6144,7 @@
 
     /* create specific data instance if needed */
     if (scnode->nodetype == LYS_LIST) {
-        LY_CHECK_GOTO(ret = lyd_create_list(scnode, predicates, &inst), cleanup);
+        LY_CHECK_GOTO(ret = lyd_create_list(scnode, predicates, NULL, &inst), cleanup);
     } else if (scnode->nodetype == LYS_LEAFLIST) {
         LY_CHECK_GOTO(ret = lyd_create_term2(scnode, &predicates[0].value, &inst), cleanup);
     }
@@ -7705,14 +7705,13 @@
  * @param[in] ctx_scnode Found schema node as the context for the predicate.
  * @param[in] set Context set.
  * @param[out] predicates Parsed predicates.
- * @param[out] pred_type Type of @p predicates.
  * @return LY_SUCCESS on success,
  * @return LY_ENOT if a predicate could not be compiled.
  * @return LY_ERR on any error.
  */
 static LY_ERR
 eval_name_test_try_compile_predicates(const struct lyxp_expr *exp, uint32_t *tok_idx, const struct lysc_node *ctx_scnode,
-        const struct lyxp_set *set, struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
+        const struct lyxp_set *set, struct ly_path_predicate **predicates)
 {
     LY_ERR rc = LY_SUCCESS;
     uint32_t e_idx, val_start_idx, pred_idx = 0, temp_lo = 0, pred_len = 0, nested_pred;
@@ -7851,7 +7850,7 @@
 
     /* compile */
     rc = ly_path_compile_predicate(set->ctx, set->cur_node ? set->cur_node->schema : NULL, set->cur_mod, ctx_scnode, exp2,
-            &pred_idx, LY_VALUE_JSON, NULL, predicates, pred_type);
+            &pred_idx, LY_VALUE_JSON, NULL, predicates);
     LY_CHECK_GOTO(rc, cleanup);
 
     /* success, the predicate must include all the needed information for hash-based search */
@@ -8021,7 +8020,6 @@
     const struct lys_module *moveto_mod = NULL;
     const struct lysc_node *scnode = NULL;
     struct ly_path_predicate *predicates = NULL;
-    enum ly_path_pred_type pred_type = 0;
     int scnode_skip_pred = 0;
 
     LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
@@ -8063,7 +8061,7 @@
 
         if (scnode && (scnode->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
             /* try to create the predicates */
-            if (eval_name_test_try_compile_predicates(exp, tok_idx, scnode, set, &predicates, &pred_type)) {
+            if (eval_name_test_try_compile_predicates(exp, tok_idx, scnode, set, &predicates)) {
                 /* hashes cannot be used */
                 scnode = NULL;
             }
@@ -8180,7 +8178,7 @@
     }
     if (!(options & LYXP_SKIP_EXPR)) {
         lydict_remove(set->ctx, ncname_dict);
-        ly_path_predicates_free(set->ctx, pred_type, predicates);
+        ly_path_predicates_free(set->ctx, predicates);
     }
     return rc;
 }
@@ -8701,27 +8699,30 @@
 }
 
 LY_ERR
-lyxp_vars_find(struct lyxp_var *vars, const char *name, size_t name_len, struct lyxp_var **var)
+lyxp_vars_find(const struct ly_ctx *ctx, const struct lyxp_var *vars, const char *name, size_t name_len,
+        struct lyxp_var **var)
 {
-    LY_ERR ret = LY_ENOTFOUND;
     LY_ARRAY_COUNT_TYPE u;
 
-    assert(vars && name);
+    assert(name);
 
-    name_len = name_len ? name_len : strlen(name);
+    if (!name_len) {
+        name_len = strlen(name);
+    }
 
     LY_ARRAY_FOR(vars, u) {
         if (!strncmp(vars[u].name, name, name_len)) {
-            ret = LY_SUCCESS;
-            break;
+            if (var) {
+                *var = (struct lyxp_var *)&vars[u];
+            }
+            return LY_SUCCESS;
         }
     }
 
-    if (var && !ret) {
-        *var = &vars[u];
+    if (ctx) {
+        LOGERR(ctx, LY_ENOTFOUND, "Variable \"%.*s\" not defined.", (int)name_len, name);
     }
-
-    return ret;
+    return LY_ENOTFOUND;
 }
 
 /**
@@ -8740,17 +8741,14 @@
     LY_ERR ret;
     const char *name;
     struct lyxp_var *var;
-    const struct lyxp_var *vars;
     struct lyxp_expr *tokens = NULL;
     uint32_t token_index, name_len;
 
-    vars = set->vars;
-
     /* find out the name and value of the variable */
     name = &exp->expr[exp->tok_pos[*tok_idx]];
     name_len = exp->tok_len[*tok_idx];
-    ret = lyxp_vars_find((struct lyxp_var *)vars, name, name_len, &var);
-    LY_CHECK_ERR_RET(ret, LOGERR(set->ctx, ret, "XPath variable \"%.*s\" not defined.", (int)name_len, name), ret);
+    ret = lyxp_vars_find(set->ctx, set->vars, name, name_len, &var);
+    LY_CHECK_RET(ret);
 
     /* parse value */
     ret = lyxp_expr_parse(set->ctx, var->value, 0, 1, &tokens);
diff --git a/src/xpath.h b/src/xpath.h
index c34a0f3..803de7d 100644
--- a/src/xpath.h
+++ b/src/xpath.h
@@ -497,15 +497,17 @@
         enum lyxp_token want_tok1, enum lyxp_token want_tok2);
 
 /**
- * @brief Find variable named @name in @p vars.
+ * @brief Find variable named @p name in @p vars.
  *
+ * @param[in] ctx Context for logging, not logged if NULL.
  * @param[in] vars [Sized array](@ref sizedarrays) of XPath variables.
  * @param[in] name Name of the variable being searched.
  * @param[in] name_len Name length can be set to 0 if @p name is terminated by null byte.
  * @param[out] var Variable that was found. The parameter is optional.
  * @return LY_SUCCESS if the variable was found, otherwise LY_ENOTFOUND.
  */
-LY_ERR lyxp_vars_find(struct lyxp_var *vars, const char *name, size_t name_len, struct lyxp_var **var);
+LY_ERR lyxp_vars_find(const struct ly_ctx *ctx, const struct lyxp_var *vars, const char *name, size_t name_len,
+        struct lyxp_var **var);
 
 /**
  * @brief Frees a parsed XPath expression. @p expr should not be used afterwards.
diff --git a/tests/utests/basic/test_xpath.c b/tests/utests/basic/test_xpath.c
index d28de43..985ecc2 100644
--- a/tests/utests/basic/test_xpath.c
+++ b/tests/utests/basic/test_xpath.c
@@ -900,7 +900,7 @@
     LOCAL_SETUP(data, tree);
     assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var1", "\"mstr\""));
     assert_int_equal(LY_ENOTFOUND, lyd_find_xpath2(tree, "/foo[text() = $var55]", vars, &set));
-    CHECK_LOG_CTX("XPath variable \"var55\" not defined.", NULL);
+    CHECK_LOG_CTX("Variable \"var55\" not defined.", NULL);
     LOCAL_TEARDOWN(set, tree, vars);
 
     /* Syntax error in value. */
diff --git a/tests/utests/types/instanceid.c b/tests/utests/types/instanceid.c
index 4c46b64..b41e13e 100644
--- a/tests/utests/types/instanceid.c
+++ b/tests/utests/types/instanceid.c
@@ -79,12 +79,12 @@
 test_data_xml(void **state)
 {
     const char *schema, *schema2;
-    const enum ly_path_pred_type val1[] = {LY_PATH_PREDTYPE_NONE, LY_PATH_PREDTYPE_NONE};
-    const enum ly_path_pred_type val2[] = {LY_PATH_PREDTYPE_LIST, LY_PATH_PREDTYPE_NONE};
+    const enum ly_path_pred_type val1[] = {0, 0};
+    const enum ly_path_pred_type val2[] = {LY_PATH_PREDTYPE_LIST, 0};
     const enum ly_path_pred_type val3[] = {LY_PATH_PREDTYPE_LEAFLIST};
-    const enum ly_path_pred_type val4[] = {LY_PATH_PREDTYPE_LIST, LY_PATH_PREDTYPE_NONE};
-    const enum ly_path_pred_type val5[] = {LY_PATH_PREDTYPE_LIST, LY_PATH_PREDTYPE_NONE};
-    const enum ly_path_pred_type val6[] = {LY_PATH_PREDTYPE_LIST, LY_PATH_PREDTYPE_NONE};
+    const enum ly_path_pred_type val4[] = {LY_PATH_PREDTYPE_LIST, 0};
+    const enum ly_path_pred_type val5[] = {LY_PATH_PREDTYPE_LIST, 0};
+    const enum ly_path_pred_type val6[] = {LY_PATH_PREDTYPE_LIST, 0};
 
     /* xml test */
     schema = MODULE_CREATE_YANG("mod", "container cont {leaf l2 {type empty;}}");
diff --git a/tests/utests/utests.h b/tests/utests/utests.h
index c2e7733..0e0649d 100644
--- a/tests/utests/utests.h
+++ b/tests/utests/utests.h
@@ -1010,7 +1010,9 @@
         LY_ARRAY_COUNT_TYPE arr_size = sizeof(VALUE) / sizeof(VALUE[0]); \
         assert_int_equal(arr_size, LY_ARRAY_COUNT((NODE).target)); \
         for (LY_ARRAY_COUNT_TYPE it = 0; it < arr_size; it++) { \
-            assert_int_equal(VALUE[it], (NODE).target[it].pred_type); \
+            if ((NODE).target[it].predicates) { \
+                assert_int_equal(VALUE[it], (NODE).target[it].predicates[0].type); \
+            } \
         } \
     }