resolve BUGFIX instid prefixes are always mandatory
diff --git a/src/resolve.c b/src/resolve.c
index 0f7c9db..aea5ddd 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -510,7 +510,7 @@
 
 /**
  * @brief Parse instance-identifier in JSON data format. That means that prefixes
- *        (which are mandatory) are actually model names.
+ *        (which are mandatory for every node-identifier) are actually model names.
  *
  * instance-identifier = 1*("/" (node-identifier *predicate))
  *
@@ -530,19 +530,6 @@
 {
     int parsed = 0, ret;
 
-    assert(id);
-    if (model) {
-        *model = NULL;
-    }
-    if (mod_len) {
-        *mod_len = 0;
-    }
-    if (name) {
-        *name = NULL;
-    }
-    if (nam_len) {
-        *nam_len = 0;
-    }
     if (has_predicate) {
         *has_predicate = 0;
     }
@@ -554,14 +541,34 @@
     ++parsed;
     ++id;
 
-    if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
-        return -parsed + ret;
+    if ((ret = parse_identifier(id)) < 1) {
+        return ret;
     }
 
+    *model = id;
+    *mod_len = ret;
+
     parsed += ret;
     id += ret;
 
-    if ((id[0] == '[') && has_predicate) {
+    if (id[0] != ':') {
+        return -parsed;
+    }
+
+    ++parsed;
+    ++id;
+
+    if ((ret = parse_identifier(id)) < 1) {
+        return ret;
+    }
+
+    *name = id;
+    *nam_len = ret;
+
+    parsed += ret;
+    id += ret;
+
+    if (id[0] == '[') {
         *has_predicate = 1;
     }
 
@@ -3716,20 +3723,17 @@
 resolve_predicate(const char *pred, struct unres_data *node_match)
 {
     /* ... /node[target = value] ... */
-    struct unres_data target_match;
-    struct ly_ctx *ctx;
-    const struct lys_module *mod;
+    struct lyd_node *target;
     const char *model, *name, *value;
-    char *str;
-    int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
+    int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
     uint32_t j;
 
     assert(pred && node_match->count);
 
-    ctx = node_match->node[0]->schema->module->ctx;
     idx = -1;
     parsed = 0;
 
+    pred_iter = -1;
     do {
         if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
             return -parsed+i;
@@ -3737,63 +3741,98 @@
         parsed += i;
         pred += i;
 
-        /* pos */
         if (isdigit(name[0])) {
+            /* pos */
+            assert(!value);
             idx = atoi(name);
+        } else if (name[0] != '.') {
+            /* list keys */
+            if (pred_iter < 0) {
+                pred_iter = 1;
+            } else {
+                ++pred_iter;
+            }
         }
 
         for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
             /* target */
-            memset(&target_match, 0, sizeof target_match);
-            if ((name[0] == '.') || !value) {
-                target_match.count = 1;
-                target_match.node = malloc(sizeof *target_match.node);
-                if (!target_match.node) {
-                    LOGMEM;
-                    return -1;
-                }
-                target_match.node[0] = node_match->node[j];
-            } else {
-                str = strndup(model, mod_len);
-                mod = ly_ctx_get_module(ctx, str, NULL);
-                free(str);
-
-                if (resolve_data(mod, name, nam_len, node_match->node[j]->child, &target_match)) {
-                    goto remove_instid;
-                }
-            }
-
-            /* check that we have the correct type */
             if (name[0] == '.') {
+                /* leaf-list value */
                 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
                     goto remove_instid;
                 }
-            } else if (value) {
+
+                target = node_match->node[j];
+                /* check the value */
+                if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
+                    || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
+                    goto remove_instid;
+                }
+
+            } else if (!value) {
+                /* keyless list position */
+                if ((node_match->node[j]->schema->nodetype != LYS_LIST)
+                        || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
+                    goto remove_instid;
+                }
+
+                if (idx != cur_idx) {
+                    goto remove_instid;
+                }
+
+            } else {
+                /* list key value */
                 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
                     goto remove_instid;
                 }
+
+                /* key module must match the list module */
+                if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
+                        || node_match->node[j]->schema->module->name[mod_len]) {
+                    goto remove_instid;
+                }
+                /* find the key leaf */
+                for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); target = target->next);
+                if (!target) {
+                    goto remove_instid;
+                }
+                if ((struct lys_node_leaf *)target->schema !=
+                        ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
+                    goto remove_instid;
+                }
+
+                /* check the value */
+                if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
+                    || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
+                    goto remove_instid;
+                }
             }
 
-            if ((value && (strncmp(((struct lyd_node_leaf_list *)target_match.node[0])->value_str, value, val_len)
-                    || ((struct lyd_node_leaf_list *)target_match.node[0])->value_str[val_len]))
-                    || (!value && (idx != cur_idx))) {
-                goto remove_instid;
-            }
-
-            free(target_match.node);
-
-            /* leafref is ok, continue check with next leafref */
+            /* instid is ok, continue check with the next one */
             ++j;
             continue;
 
 remove_instid:
-            free(target_match.node);
-
-            /* does not fulfill conditions, remove leafref record */
+            /* does not fulfill conditions, remove instid record */
             unres_data_del(node_match, j);
         }
     } while (has_predicate);
 
+    /* check that all list keys were specified */
+    if ((pred_iter > 0) && node_match->count) {
+        for (j = 0; j < node_match->count; ++j) {
+            assert(node_match->node[j]->schema->nodetype == LYS_LIST);
+            if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
+                /* not enough predicates, just remove the list instance */
+                unres_data_del(node_match, j);
+            }
+        }
+
+        if (!node_match->count) {
+            LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
+        }
+    }
+
     return parsed;
 }
 
@@ -3810,13 +3849,12 @@
 {
     int i = 0, j;
     struct lyd_node *result = NULL;
-    const struct lys_module *mod, *prev_mod;
+    const struct lys_module *mod;
     struct ly_ctx *ctx = data->schema->module->ctx;
     const char *model, *name;
     char *str;
     int mod_len, name_len, has_predicate;
     struct unres_data node_match;
-    uint32_t k;
 
     memset(&node_match, 0, sizeof node_match);
 
@@ -3827,8 +3865,6 @@
         for (; data->prev->next; data = data->prev);
     }
 
-    prev_mod = lyd_node_module(data);
-
     /* search for the instance node */
     while (path[i]) {
         j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
@@ -3838,17 +3874,13 @@
         }
         i += j;
 
-        if (model) {
-            str = strndup(model, mod_len);
-            if (!str) {
-                LOGMEM;
-                goto error;
-            }
-            mod = ly_ctx_get_module(ctx, str, NULL);
-            free(str);
-        } else {
-            mod = prev_mod;
+        str = strndup(model, mod_len);
+        if (!str) {
+            LOGMEM;
+            goto error;
         }
+        mod = ly_ctx_get_module(ctx, str, NULL);
+        free(str);
 
         if (resolve_data(mod, name, name_len, data, &node_match)) {
             /* no instance exists */
@@ -3857,19 +3889,6 @@
 
         if (has_predicate) {
             /* we have predicate, so the current results must be list or leaf-list */
-            for (k = 0; k < node_match.count;) {
-                if ((node_match.node[k]->schema->nodetype == LYS_LIST &&
-                        ((struct lys_node_list *)node_match.node[k]->schema)->keys)
-                        || (node_match.node[k]->schema->nodetype == LYS_LEAFLIST)) {
-                    /* instid is ok, continue check with next instid */
-                    ++k;
-                    continue;
-                }
-
-                /* does not fulfill conditions, remove inst record */
-                unres_data_del(&node_match, k);
-            }
-
             j = resolve_predicate(&path[i], &node_match);
             if (j < 1) {
                 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
@@ -3882,8 +3901,6 @@
                 return NULL;
             }
         }
-
-        prev_mod = mod;
     }
 
     if (!node_match.count) {
@@ -3892,21 +3909,17 @@
     } else if (node_match.count > 1) {
         /* instance identifier must resolve to a single node */
         LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
-
         goto error;
     } else {
         /* we have required result, remember it and cleanup */
         result = node_match.node[0];
         free(node_match.node);
-
         return result;
     }
 
 error:
-
     /* cleanup */
     free(node_match.node);
-
     return NULL;
 }