parser xml CHANGE non-xml specific functions made separate

So that they can be used in other parsers and
even API functions. Some general refactoring included.
diff --git a/src/tree_data.c b/src/tree_data.c
index 018259f..0b9b59f 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -27,15 +27,17 @@
 #include "tree.h"
 #include "tree_data.h"
 #include "tree_data_internal.h"
+#include "hash_table.h"
 #include "tree_schema.h"
 #include "plugins_exts_metadata.h"
+#include "plugins_exts_internal.h"
 
 struct ly_keys {
     char *str;
     struct {
         const struct lysc_node_leaf *schema;
         char *value;
-        const char *can_val;
+        struct lyd_value val;
     } *keys;
     size_t key_count;
 };
@@ -114,15 +116,15 @@
 }
 
 LY_ERR
-lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int dynamic, int second,
+lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int *dynamic, int second,
                 ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node **trees)
 {
-    LY_ERR ret = LY_SUCCESS, rc;
+    LY_ERR ret = LY_SUCCESS;
     struct ly_err_item *err = NULL;
     struct ly_ctx *ctx;
     struct lysc_type *type;
     int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
-            (dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
+            (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
     assert(node);
 
     ctx = node->schema->module->ctx;
@@ -131,36 +133,67 @@
     if (!second) {
         node->value.realtype = type;
     }
-    rc = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format,
+    ret = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format,
                              trees ? (void*)node : (void*)node->schema, trees,
                              &node->value, NULL, &err);
-    if (rc == LY_EINCOMPLETE) {
-        ret = rc;
-        /* continue with storing, just remember what to return if storing is ok */
-    } else if (rc) {
-        ret = rc;
+    if (ret && (ret != LY_EINCOMPLETE)) {
         if (err) {
             ly_err_print(err);
             LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
             ly_err_free(err);
         }
         goto error;
+    } else if (dynamic) {
+        *dynamic = 0;
     }
 
 error:
     return ret;
 }
 
+/* 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
+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)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct ly_err_item *err = NULL;
+    struct ly_ctx *ctx;
+    struct lysc_type *type;
+    int options = LY_TYPE_OPTS_STORE | LY_TYPE_OPTS_INCOMPLETE_DATA | (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0);
+
+    assert(val && schema && (schema->nodetype & LYD_NODE_TERM));
+
+    ctx = schema->module->ctx;
+    type = ((struct lysc_node_leaf *)schema)->type;
+    val->realtype = type;
+    ret = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format, (void *)schema, NULL,
+                              val, NULL, &err);
+    if (ret == LY_EINCOMPLETE) {
+        /* this is fine, we do not need it resolved */
+        ret = LY_SUCCESS;
+    } else if (ret && err) {
+        ly_err_print(err);
+        LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
+        ly_err_free(err);
+    }
+    if (!ret && dynamic) {
+        *dynamic = 0;
+    }
+
+    return ret;
+}
+
 LY_ERR
-lyd_value_parse_attr(struct lyd_attr *attr, const char *value, size_t value_len, int dynamic, int second,
+lyd_value_parse_attr(struct lyd_attr *attr, const char *value, size_t value_len, int *dynamic, int second,
                      ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node **trees)
 {
-    LY_ERR ret = LY_SUCCESS, rc;
+    LY_ERR ret = LY_SUCCESS;
     struct ly_err_item *err = NULL;
     struct ly_ctx *ctx;
     struct lyext_metadata *ant;
     int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
-            (dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
+            (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
     assert(attr);
 
     ctx = attr->parent->schema->module->ctx;
@@ -169,20 +202,18 @@
     if (!second) {
         attr->value.realtype = ant->type;
     }
-    rc = ant->type->plugin->store(ctx, ant->type, value, value_len, options, get_prefix, parser, format,
+    ret = ant->type->plugin->store(ctx, ant->type, value, value_len, options, get_prefix, parser, format,
                                   trees ? (void*)attr->parent : (void*)attr->parent->schema, trees,
                                   &attr->value, NULL, &err);
-    if (rc == LY_EINCOMPLETE) {
-        ret = rc;
-        /* continue with storing, just remember what to return if storing is ok */
-    } else if (rc) {
-        ret = rc;
+    if (ret && (ret != LY_EINCOMPLETE)) {
         if (err) {
             ly_err_print(err);
             LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
             ly_err_free(err);
         }
         goto error;
+    } else if (dynamic) {
+        *dynamic = 0;
     }
 
 error:
@@ -420,6 +451,426 @@
     return result;
 }
 
+LY_ERR
+lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_len, int *dynamic,
+                ly_clb_resolve_prefix get_prefix, void *prefix_data, LYD_FORMAT format, struct lyd_node **node)
+{
+    LY_ERR ret;
+    struct lyd_node_term *term;
+
+    term = calloc(1, sizeof *term);
+    LY_CHECK_ERR_RET(!term, LOGMEM(schema->module->ctx), LY_EMEM);
+
+    term->schema = schema;
+    term->prev = (struct lyd_node *)term;
+
+    ret = lyd_value_parse(term, value, value_len, dynamic, 0, get_prefix, prefix_data, format, NULL);
+    if (ret && (ret != LY_EINCOMPLETE)) {
+        free(term);
+        return ret;
+    }
+
+    *node = (struct lyd_node *)term;
+    return ret;
+}
+
+LY_ERR
+lyd_create_inner(const struct lysc_node *schema, struct lyd_node **node)
+{
+    struct lyd_node_inner *in;
+
+    in = calloc(1, sizeof *in);
+    LY_CHECK_ERR_RET(!in, LOGMEM(schema->module->ctx), LY_EMEM);
+
+    in->schema = schema;
+    in->prev = (struct lyd_node *)in;
+
+    if ((schema->nodetype == LYS_CONTAINER) && !(((struct lysc_node_container *)schema)->flags & LYS_PRESENCE)) {
+        /* non-presence cotnainer, default */
+        in->flags = LYD_DEFAULT;
+    }
+
+    *node = (struct lyd_node *)in;
+    return LY_SUCCESS;
+}
+
+static void
+ly_keys_clean(struct ly_keys *keys)
+{
+    size_t i;
+
+    for (i = 0; i < keys->key_count; ++i) {
+        keys->keys[i].schema->type->plugin->free(keys->keys[i].schema->module->ctx, &keys->keys[i].val);
+    }
+    free(keys->str);
+    free(keys->keys);
+}
+
+static char *
+ly_keys_parse_next(char **next_key, char **key_name)
+{
+    char *ptr, *ptr2, *val, quot;
+
+    ptr = *next_key;
+
+    /* "[" */
+    LY_CHECK_GOTO(ptr[0] != '[', error);
+    ++ptr;
+
+    /* key name */
+    ptr2 = strchr(ptr, '=');
+    LY_CHECK_GOTO(!ptr2, error);
+
+    *key_name = ptr;
+    ptr2[0] = '\0';
+
+    /* \0, was '=' */
+    ptr = ptr2 + 1;
+
+    /* quote */
+    LY_CHECK_GOTO((ptr[0] != '\'') && (ptr[0] != '\"'), error);
+    quot = ptr[0];
+    ++ptr;
+
+    /* value, terminate it */
+    val = ptr;
+    ptr2 = strchr(ptr, quot);
+    LY_CHECK_GOTO(!ptr2, error);
+    ptr2[0] = '\0';
+
+    /* \0, was quote */
+    ptr = ptr2 + 1;
+
+    /* "]" */
+    LY_CHECK_GOTO(ptr[0] != ']', error);
+    ++ptr;
+
+    *next_key = ptr;
+    return val;
+
+error:
+    *next_key = ptr;
+    return NULL;
+}
+
+/* fill keys structure; if store is set, fill also each val */
+static LY_ERR
+ly_keys_parse(const struct lysc_node *list, const char *keys_str, size_t keys_len, int store, struct ly_keys *keys)
+{
+    LY_ERR ret = LY_SUCCESS;
+    char *next_key, *name;
+    const struct lysc_node *key;
+    size_t i;
+
+    assert(list->nodetype == LYS_LIST);
+
+    memset(keys, 0, sizeof *keys);
+
+    keys->str = strndup(keys_str, keys_len ? keys_len : strlen(keys_str));
+    LY_CHECK_ERR_GOTO(!keys->str, LOGMEM(list->module->ctx); ret = LY_EMEM, cleanup);
+
+    next_key = keys->str;
+    while (next_key[0]) {
+        /* new key */
+        keys->keys = ly_realloc(keys->keys, (keys->key_count + 1) * sizeof *keys->keys);
+        LY_CHECK_ERR_GOTO(!keys->keys, LOGMEM(list->module->ctx); ret = LY_EMEM, cleanup);
+
+        /* fill */
+        keys->keys[keys->key_count].value = ly_keys_parse_next(&next_key, &name);
+        if (!keys->keys[keys->key_count].value) {
+            LOGERR(list->module->ctx, LY_EINVAL, "Invalid keys string (at \"%s\").", next_key);
+            ret = LY_EINVAL;
+            goto cleanup;
+        }
+
+        /* find schema node */
+        key = lys_find_child(list, list->module, name, 0, LYS_LEAF, 0);
+        if (!key) {
+            LOGERR(list->module->ctx, LY_EINVAL, "List \"%s\" has no key \"%s\".", list->name, name);
+            ret = LY_EINVAL;
+            goto cleanup;
+        }
+        keys->keys[keys->key_count].schema = (const struct lysc_node_leaf *)key;
+
+        /* check that we do not have it already */
+        for (i = 0; i < keys->key_count; ++i) {
+            if (keys->keys[i].schema == keys->keys[keys->key_count].schema) {
+                LOGERR(list->module->ctx, LY_EINVAL, "Duplicit key \"%s\" value.", name);
+                ret = LY_EINVAL;
+                goto cleanup;
+            }
+        }
+
+        if (store) {
+            /* store the value */
+            ret = lyd_value_store(&keys->keys[keys->key_count].val, key, keys->keys[keys->key_count].value, 0, 0,
+                                  lydjson_resolve_prefix, NULL, LYD_JSON);
+            LY_CHECK_GOTO(ret, cleanup);
+        }
+
+        /* another valid key */
+        ++keys->key_count;
+    }
+
+cleanup:
+    ly_keys_clean(keys);
+    return ret;
+}
+
+LY_ERR
+lyd_create_list(const struct lysc_node *schema, const char *keys_str, size_t keys_len, 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;
+
+    assert((schema->nodetype == LYS_LIST) && !(schema->flags & LYS_KEYLESS));
+
+    /* parse keys */
+    LY_CHECK_GOTO(ret = ly_keys_parse(schema, keys_str, keys_len, 0, &keys), cleanup);
+
+    /* 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) {
+        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) {
+        LY_CHECK_GOTO(ret = lyd_create_term((struct lysc_node *)keys.keys[i].schema, keys.keys[i].value, 0, 0,
+                                            lydjson_resolve_prefix, NULL, LYD_JSON, &key), cleanup);
+        lyd_insert_node(list, NULL, key);
+    }
+
+    /* success */
+    *node = list;
+    list = NULL;
+
+cleanup:
+    lyd_free_tree(list);
+    ly_keys_clean(&keys);
+    return ret;
+}
+
+LY_ERR
+lyd_create_any(const struct lysc_node *schema, const void *value, LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node)
+{
+    struct lyd_node_any *any;
+
+    any = calloc(1, sizeof *any);
+    LY_CHECK_ERR_RET(!any, LOGMEM(schema->module->ctx), LY_EMEM);
+
+    any->schema = schema;
+    any->prev = (struct lyd_node *)any;
+
+    any->value.xml = value;
+    any->value_type = value_type;
+
+    *node = (struct lyd_node *)any;
+    return LY_SUCCESS;
+}
+
+struct lyd_node *
+lyd_get_prev_key_anchor(const struct lyd_node *first_sibling, const struct lysc_node *new_key)
+{
+    const struct lysc_node *prev_key;
+    struct lyd_node *match = NULL;
+
+    if (!first_sibling) {
+        return NULL;
+    }
+
+    for (prev_key = new_key->prev; !match && prev_key->next; prev_key = prev_key->prev) {
+        lyd_find_sibling_val(first_sibling, prev_key, NULL, 0, &match);
+    }
+
+    return match;
+}
+
+/**
+ * @brief Insert node after a sibling.
+ *
+ * @param[in] sibling Sibling to insert after.
+ * @param[in] node Node to insert.
+ */
+static void
+lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
+{
+    assert(!node->next && (node->prev == node));
+
+    node->next = sibling->next;
+    node->prev = sibling;
+    sibling->next = node;
+    if (node->next) {
+        /* sibling had a succeeding node */
+        node->next->prev = node;
+    } else {
+        /* sibling was last, find first sibling and change its prev */
+        if (sibling->parent) {
+            sibling = sibling->parent->child;
+        } else {
+            for (; sibling->prev->next != node; sibling = sibling->prev);
+        }
+        sibling->prev = node;
+    }
+    node->parent = sibling->parent;
+}
+
+/**
+ * @brief Insert node before a sibling.
+ *
+ * @param[in] sibling Sibling to insert before.
+ * @param[in] node Node to insert.
+ */
+static void
+lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
+{
+    assert(!node->next && (node->prev == node));
+
+    node->next = sibling;
+    /* covers situation of sibling being first */
+    node->prev = sibling->prev;
+    sibling->prev = node;
+    if (node->prev->next) {
+        /* sibling had a preceding node */
+        node->prev->next = node;
+    } else if (sibling->parent) {
+        /* sibling was first and we must also change parent child pointer */
+        sibling->parent->child = node;
+    }
+    node->parent = sibling->parent;
+}
+
+/**
+ * @brief Insert node as the last child of a parent.
+ *
+ * @param[in] parent Parent to insert into.
+ * @param[in] node Node to insert.
+ */
+static void
+lyd_insert_last(struct lyd_node *parent, struct lyd_node *node)
+{
+    struct lyd_node_inner *par;
+
+    assert(!node->next && (node->prev == node));
+    assert(parent->schema->nodetype & LYD_NODE_INNER);
+
+    par = (struct lyd_node_inner *)parent;
+
+    if (!par->child) {
+        par->child = node;
+    } else {
+        node->prev = par->child->prev;
+        par->child->prev->next = node;
+        par->child->prev = node;
+    }
+    node->parent = par;
+}
+
+void
+lyd_insert_node(struct lyd_node *parent, struct lyd_node *first_sibling, struct lyd_node *node)
+{
+    struct lyd_node *key_anchor;
+
+    assert((!parent && first_sibling) || (!first_sibling && parent));
+    assert(node && node->hash);
+
+    if (parent) {
+        if (node->schema->flags & LYS_KEY) {
+            /* it is key and we need to insert it at the correct place */
+            key_anchor = lyd_get_prev_key_anchor(lyd_node_children(parent), node->schema);
+            if (key_anchor) {
+                lyd_insert_after(key_anchor, node);
+            } else if (lyd_node_children(parent)) {
+                lyd_insert_before((struct lyd_node *)lyd_node_children(parent), node);
+            } else {
+                lyd_insert_last(parent, node);
+            }
+        } else {
+            /* last child */
+            lyd_insert_last(parent, node);
+        }
+    } else {
+        /* last sibling */
+        lyd_insert_after(first_sibling->prev, node);
+    }
+
+    /* remove default flags from NP containers */
+    while (parent && (parent->flags & LYD_DEFAULT)) {
+        parent->flags &= ~LYD_DEFAULT;
+        parent = (struct lyd_node *)parent->parent;
+    }
+
+    /* insert into hash table */
+    lyd_insert_hash(node);
+}
+
+LY_ERR
+lyd_create_attr(struct lyd_node *parent, const struct lys_module *mod, const char *name, size_t name_len,
+                const char *value, size_t value_len, int *dynamic, ly_clb_resolve_prefix get_prefix, void *prefix_data,
+                LYD_FORMAT format, struct lyd_attr **attr)
+{
+    LY_ERR ret;
+    struct lysc_ext_instance *ant = NULL;
+    struct lyd_attr *at, *last;
+    uint32_t v;
+
+    LY_ARRAY_FOR(mod->compiled->exts, v) {
+        if (mod->compiled->exts[v].def->plugin == lyext_plugins_internal[LYEXT_PLUGIN_INTERNAL_ANNOTATION].plugin &&
+                !ly_strncmp(mod->compiled->exts[v].argument, name, name_len)) {
+            /* we have the annotation definition */
+            ant = &mod->compiled->exts[v];
+            break;
+        }
+    }
+    if (!ant) {
+        /* attribute is not defined as a metadata annotation (RFC 7952) */
+        LOGERR(mod->ctx, LY_EINVAL, "Annotation definition for attribute \"%s:%.*s\" not found.",
+                mod->name, name_len, name);
+        return LY_EINVAL;
+    }
+
+    at = calloc(1, sizeof *at);
+    LY_CHECK_ERR_RET(!at, LOGMEM(mod->ctx), LY_EMEM);
+    at->parent = parent;
+    at->annotation = ant;
+    ret = lyd_value_parse_attr(at, value, value_len, dynamic, 0, get_prefix, prefix_data, format, NULL);
+    if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
+        free(at);
+        return ret;
+    }
+    at->name = lydict_insert(mod->ctx, name, name_len);
+
+    /* insert into parent as the last attribute */
+    if (parent->attr) {
+        for (last = parent->attr; last->next; last = last->next);
+        last->next = at;
+    } else {
+        parent->attr = at;
+    }
+
+    /* remove default flags from NP containers */
+    while (parent && (parent->flags & LYD_DEFAULT)) {
+        parent->flags &= ~LYD_DEFAULT;
+        parent = (struct lyd_node *)parent->parent;
+    }
+
+    if (attr) {
+        *attr = at;
+    }
+    return ret;
+}
+
 API const struct lyd_node_term *
 lyd_target(struct lyd_value_path *path, const struct lyd_node **trees)
 {
@@ -1167,144 +1618,6 @@
     return NULL;
 }
 
-static char *
-lyd_keys_parse_next(char **next_key, char **key_name)
-{
-    char *ptr, *ptr2, *val, quot;
-
-    ptr = *next_key;
-
-    /* "[" */
-    LY_CHECK_GOTO(ptr[0] != '[', error);
-    ++ptr;
-
-    /* key name */
-    ptr2 = strchr(ptr, '=');
-    LY_CHECK_GOTO(!ptr2, error);
-
-    *key_name = ptr;
-    ptr2[0] = '\0';
-
-    /* \0, was '=' */
-    ptr = ptr2 + 1;
-
-    /* quote */
-    LY_CHECK_GOTO((ptr[0] != '\'') && (ptr[0] != '\"'), error);
-    quot = ptr[0];
-    ++ptr;
-
-    /* value, terminate it */
-    val = ptr;
-    ptr2 = strchr(ptr, quot);
-    LY_CHECK_GOTO(!ptr2, error);
-    ptr2[0] = '\0';
-
-    /* \0, was quote */
-    ptr = ptr2 + 1;
-
-    /* "]" */
-    LY_CHECK_GOTO(ptr[0] != ']', error);
-    ++ptr;
-
-    *next_key = ptr;
-    return val;
-
-error:
-    LOGERR(NULL, LY_EINVAL, "Invalid arguments - keys at \"%s\" (%s()).", ptr, __func__);
-    return NULL;
-}
-
-static void
-ly_keys_clean(struct ly_keys *keys)
-{
-    size_t i;
-
-    for (i = 0; i < keys->key_count; ++i) {
-        lydict_remove(keys->keys[i].schema->module->ctx, keys->keys[i].can_val);
-    }
-    free(keys->str);
-    free(keys->keys);
-}
-
-static LY_ERR
-lyd_value_canonize(const struct lysc_node *schema, const char *value, size_t val_len, const char **can_val)
-{
-    LY_ERR rc = LY_SUCCESS;
-    struct lysc_type *type;
-    struct ly_err_item *err;
-
-    assert(schema->nodetype & (LYS_LEAF | LYS_LEAFLIST));
-
-    if (!val_len) {
-        val_len = strlen(value);
-    }
-
-    /* check canonical value exists */
-    type = (struct lysc_type *)&((struct lysc_node_leaf *)schema)->type;
-    if (!type->plugin->has_canon(type)) {
-        LOGERR(schema->module->ctx, LY_EINVAL, "Key \"%s\" has no canonical value.", schema->name);
-        return LY_EINVAL;
-    }
-
-    /* make the value canonical */
-    rc = type->plugin->store(schema->module->ctx, type, value, val_len, LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_SCHEMA,
-                             NULL, NULL, 0, NULL, NULL, NULL, can_val, &err);
-    if (rc != LY_SUCCESS) {
-        ly_err_print(err);
-        ly_err_free(err);
-        return rc;
-    }
-
-    return LY_SUCCESS;
-}
-
-static LY_ERR
-ly_keys_parse(const struct lysc_node *list, const char *keys_str, size_t keys_len, int canonize, struct ly_keys *keys)
-{
-    LY_ERR rc = LY_SUCCESS;
-    char *next_key, *name;
-    const struct lysc_node *key;
-
-    assert(list->nodetype == LYS_LIST);
-
-    memset(keys, 0, sizeof *keys);
-
-    keys->str = strndup(keys_str, keys_len ? keys_len : strlen(keys_str));
-    LY_CHECK_ERR_GOTO(!keys->str, LOGMEM(list->module->ctx); rc = LY_EMEM, cleanup);
-
-    next_key = keys->str;
-    while (next_key[0]) {
-        /* new key */
-        keys->keys = ly_realloc(keys->keys, (keys->key_count + 1) * sizeof *keys->keys);
-        LY_CHECK_ERR_GOTO(!keys->keys, LOGMEM(list->module->ctx); rc = LY_EMEM, cleanup);
-
-        /* fill */
-        keys->keys[keys->key_count].value = lyd_keys_parse_next(&next_key, &name);
-
-        /* find schema node */
-        key = lys_find_child(list, list->module, name, 0, LYS_LEAF, 0);
-        if (!key) {
-            LOGERR(list->module->ctx, LY_EINVAL, "Node \"%s\" has no key \"%s\".", list->name, name);
-            rc = LY_EINVAL;
-            goto cleanup;
-        }
-        keys->keys[keys->key_count].schema = (const struct lysc_node_leaf *)key;
-
-        if (canonize) {
-            /* canonize the value */
-            rc = lyd_value_canonize(key, keys->keys[keys->key_count].value, 0, &keys->keys[keys->key_count].can_val);
-            LY_CHECK_GOTO(rc != LY_SUCCESS, cleanup);
-        }
-
-        /* another valid key */
-        ++keys->key_count;
-    }
-
-cleanup:
-    ly_keys_clean(keys);
-    return rc;
-}
-
 API LY_ERR
 lyd_find_sibling_next(const struct lyd_node *first, const struct lys_module *module, const char *name, size_t name_len,
                       const char *key_or_value, size_t val_len, struct lyd_node **match)
@@ -1314,9 +1627,8 @@
     struct lyd_node_term *term;
     const struct lysc_node *schema;
     struct ly_keys keys = {0};
-    const char *value = NULL, *node_val;
+    struct lyd_value val = {0};
     size_t i;
-    int dynamic;
 
     LY_CHECK_ARG_RET(NULL, module, name, LY_EINVAL);
 
@@ -1338,8 +1650,8 @@
     }
 
     if (key_or_value && (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
-        /* canonize the value */
-        LY_CHECK_GOTO(rc = lyd_value_canonize(schema, key_or_value, val_len, &value), cleanup);
+        /* store the value */
+        LY_CHECK_GOTO(lyd_value_store(&val, schema, key_or_value, val_len, 0, lydjson_resolve_prefix, NULL, LYD_JSON), cleanup);
     } else if (key_or_value && (schema->nodetype == LYS_LIST)) {
         /* parse keys into canonical values */
         LY_CHECK_GOTO(rc = ly_keys_parse(schema, key_or_value, val_len, 1, &keys), cleanup);
@@ -1364,9 +1676,7 @@
                 LY_CHECK_GOTO(rc, cleanup);
 
                 /* compare values */
-                node_val = term->value.realtype->plugin->print(&term->value, 0, NULL, NULL, &dynamic);
-                assert(!dynamic);
-                if (strcmp(node_val, keys.keys[i].can_val)) {
+                if (!term->value.realtype->plugin->compare(&term->value, &keys.keys[i].val)) {
                     break;
                 }
             }
@@ -1375,13 +1685,11 @@
                 /* not a match */
                 continue;
             }
-        } else if ((schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && value) {
+        } else if ((schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && val.realtype) {
             term = (struct lyd_node_term *)node;
 
             /* compare values */
-            node_val = term->value.realtype->plugin->print(&term->value, 0, NULL, NULL, &dynamic);
-            assert(!dynamic);
-            if (strcmp(node_val, value)) {
+            if (!term->value.realtype->plugin->compare(&term->value, &val)) {
                 /* not a match */
                 continue;
             }
@@ -1403,7 +1711,9 @@
 
 cleanup:
     ly_keys_clean(&keys);
-    lydict_remove(module->ctx, value);
+    if (val.realtype) {
+        val.realtype->plugin->free(module->ctx, &val);
+    }
     return rc;
 }
 
@@ -1535,6 +1845,83 @@
     return LY_EMEM;
 }
 
+static int
+lyd_hash_table_schema_val_equal(void *val1_p, void *val2_p, int UNUSED(mod), void *UNUSED(cb_data))
+{
+    struct lysc_node *val1;
+    struct lyd_node *val2;
+
+    val1 = *((struct lysc_node **)val1_p);
+    val2 = *((struct lyd_node **)val2_p);
+
+    assert(val1->nodetype & (LYD_NODE_INNER | LYS_LEAF));
+
+    if (val1 == val2->schema) {
+        /* schema match is enough */
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+static LY_ERR
+lyd_find_sibling_schema(const struct lyd_node *siblings, const struct lysc_node *schema, struct lyd_node **match)
+{
+    struct lyd_node **match_p;
+    struct lyd_node_inner *parent;
+    uint32_t hash;
+    values_equal_cb ht_cb;
+
+    assert(siblings && schema && (schema->nodetype & (LYD_NODE_INNER | LYS_LEAF)));
+
+    /* find first sibling */
+    if (siblings->parent) {
+        siblings = siblings->parent->child;
+    } else {
+        while (siblings->prev->next) {
+            siblings = siblings->prev;
+        }
+    }
+
+    parent = (struct lyd_node_inner *)siblings->parent;
+    if (parent && parent->children_ht) {
+        /* calculate our hash */
+        hash = dict_hash_multi(0, schema->module->name, strlen(schema->module->name));
+        hash = dict_hash_multi(hash, schema->name, strlen(schema->name));
+        hash = dict_hash_multi(hash, NULL, 0);
+
+        /* use special hash table function */
+        ht_cb = lyht_set_cb(parent->children_ht, lyd_hash_table_schema_val_equal);
+
+        /* find by hash */
+        if (!lyht_find(parent->children_ht, &schema, hash, (void **)&match_p)) {
+            siblings = *match_p;
+        } else {
+            /* not found */
+            siblings = NULL;
+        }
+
+        /* set the original hash table compare function back */
+        lyht_set_cb(parent->children_ht, ht_cb);
+    } else {
+        /* no children hash table */
+        for (; siblings; siblings = siblings->next) {
+            if (siblings->schema == schema) {
+                /* schema match is enough */
+                break;
+            }
+        }
+    }
+
+    if (!siblings) {
+        *match = NULL;
+        return LY_ENOTFOUND;
+    }
+
+    *match = (struct lyd_node *)siblings;
+    return LY_SUCCESS;
+}
+
 API LY_ERR
 lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *schema, const char *key_or_value,
                      size_t val_len, struct lyd_node **match)
@@ -1561,31 +1948,31 @@
         return LY_ENOTFOUND;
     }
 
-    /* create data node */
+    /* create data node if needed and find it */
     switch (schema->nodetype) {
     case LYS_CONTAINER:
     case LYS_ANYXML:
     case LYS_ANYDATA:
     case LYS_NOTIF:
     case LYS_RPC:
-        /* target used attributes: schema, hash */
-        //TODO target = lyd_create(schema, 0);
-        LY_CHECK_RET(!target, LY_EMEM);
-        break;
     case LYS_LEAF:
-        /* target used attributes: schema, hash */
-        //TODO target = lyd_create_term(schema, NULL, 0, 0);
-        LY_CHECK_RET(!target, LY_EMEM);
+        /* find it based on schema only */
+        rc = lyd_find_sibling_schema(siblings, schema, match);
         break;
     case LYS_LEAFLIST:
         /* target used attributes: schema, hash, value */
-        //TODO target = lyd_create_term(schema, key_or_value, val_len, 0);
-        LY_CHECK_RET(!target, LY_EMEM);
-        break;
+        LY_CHECK_RET(lyd_create_term(schema, key_or_value, val_len, NULL, lydjson_resolve_prefix, NULL, LYD_JSON, &target));
+        lyd_hash(target);
+        /* fallthrough */
     case LYS_LIST:
-        /* target used attributes: schema, hash, child (all keys) */
-        //TODO target = lyd_create_list(schema, key_or_value, val_len);
-        LY_CHECK_RET(!target, LY_EMEM);
+        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, &target));
+            lyd_hash(target);
+        }
+
+        /* find it */
+        rc = lyd_find_sibling_first(siblings, target, match);
         break;
     default:
         /* unreachable */
@@ -1593,9 +1980,6 @@
         return LY_EINT;
     }
 
-    /* find it */
-    rc = lyd_find_sibling_first(siblings, target, match);
-
     lyd_free_tree(target);
     return rc;
 }