data tree NEW functions for searching in siblings

... using hashes if possible. Other refactoring
included.
diff --git a/src/log.h b/src/log.h
index e5f54b7..74a12c4 100644
--- a/src/log.h
+++ b/src/log.h
@@ -48,7 +48,7 @@
  * @param[in] level Verbosity level.
  * @return Previous verbosity level.
  */
-LY_LOG_LEVEL ly_verb (LY_LOG_LEVEL level);
+LY_LOG_LEVEL ly_verb(LY_LOG_LEVEL level);
 
 /**
  * @defgroup logopts Logging options
@@ -75,7 +75,7 @@
  * @param[in] opts Bitfield of @ref logopts.
  * @return Previous logger options.
  */
-int ly_log_options (int opts);
+int ly_log_options(int opts);
 
 #ifndef NDEBUG
 
@@ -102,7 +102,7 @@
  * @brief Enable specific debugging messages (independent of log level).
  * @param[in] dbg_groups Bitfield of enabled debug message groups (see @ref dbggroup).
  */
-void ly_verb_dbg (int dbg_groups);
+void ly_verb_dbg(int dbg_groups);
 
 #endif
 
@@ -120,13 +120,13 @@
  *            presence) or it can be NULL, so consider it as an optional parameter. If the flag is 0, libyang will
  *            not bother with resolving the path.
  */
-void ly_set_log_clb (void(*clb) (LY_LOG_LEVEL level, const char *msg, const char *path), int path);
+void ly_set_log_clb(void(*clb)(LY_LOG_LEVEL level, const char *msg, const char *path), int path);
 
 /**
  * @brief Get logger callback.
  * @return Logger callback (can be NULL).
  */
-void (*ly_get_log_clb (void)) (LY_LOG_LEVEL, const char *, const char *);
+void (*ly_get_log_clb(void))(LY_LOG_LEVEL, const char *, const char *);
 
 /** @} log */
 
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 1508e78..c150f42 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -281,7 +281,7 @@
             LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
             goto error;
         }
-        snode = lys_child(parent ? parent->schema : NULL, mod, name, name_len, 0, 0);
+        snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, 0);
         if (!snode) {
             LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.", name_len, name, mod->name);
             goto error;
@@ -490,7 +490,7 @@
             ly_set_add(&ctx->when_check, cur, LY_SET_OPT_USEASLIST);
         }
 
-        /* calculate the hash and insert it into parent (list with keys is handled when its keys are inserted) */
+        /* calculate the hash and insert it into parent */
         lyd_hash(cur);
         lyd_insert_hash(cur);
 
diff --git a/src/plugins_types.c b/src/plugins_types.c
index aa34d2e..a741889 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -58,6 +58,24 @@
 }
 
 /**
+ * @brief Generic has_canon callback returning always true.
+ */
+static int
+ly_type_canon_true(struct lysc_type *UNUSED(type))
+{
+    return 1;
+}
+
+/**
+ * @brief Generic has_canon callback returning always false.
+ */
+static int
+ly_type_canon_false(struct lysc_type *UNUSED(type))
+{
+    return 0;
+}
+
+/**
  * @brief Generic duplication callback of the original value only.
  *
  * Implementation of the ly_type_dup_clb.
@@ -218,7 +236,7 @@
     }
 
     *err = NULL;
-    switch(ly_parse_uint(value, value_len, max, base, ret)) {
+    switch (ly_parse_uint(value, value_len, max, base, ret)) {
     case LY_EDENIED:
         asprintf(&errmsg, "Value \"%.*s\" is out of %s's min/max bounds.", (int)value_len, value, datatype);
         goto error;
@@ -1445,7 +1463,7 @@
 
     if ((options & LY_TYPE_OPTS_INCOMPLETE_DATA) || (options & LY_TYPE_OPTS_SCHEMA) || !require_instance) {
         /* a) in schema tree */
-        *node_s = lys_child(*node_s, mod, id, id_len, 0, 0);
+        *node_s = lys_find_child(*node_s, mod, id, id_len, 0, 0);
         if (!(*node_s)) {
             asprintf(errmsg, "Invalid instance-identifier \"%.*s\" value - path \"%.*s\" does not exists in the YANG schema.",
                      (int)orig_len, orig, (int)(*token - orig), orig);
@@ -1455,8 +1473,8 @@
         /* b) in data tree */
         if (*node_d) {
             /* internal node */
-            const struct lyd_node *children = lyd_node_children(*node_d);
-            if (!children || !(*node_d = lyd_search(children, mod, id, id_len, 0, NULL, 0))) {
+            lyd_find_sibling_next(lyd_node_children(*node_d), mod, id, id_len, NULL, 0, (struct lyd_node **)node_d);
+            if (!*node_d) {
                 asprintf(errmsg, "Invalid instance-identifier \"%.*s\" value - path \"%.*s\" does not exists in the data tree(s).",
                          (int)orig_len, orig, (int)(*token - orig), orig);
                 return LY_EVALID;
@@ -1464,7 +1482,7 @@
         } else {
             /* top-level node */
             LY_ARRAY_FOR(trees, u) {
-                *node_d = lyd_search(trees[u], mod, id, id_len, 0, NULL, 0);
+                lyd_find_sibling_next(trees[u], mod, id, id_len, NULL, 0, (struct lyd_node **)node_d);
                 if (*node_d) {
                     break;
                 }
@@ -1746,7 +1764,7 @@
                         }
                         /* go to another instance */
                         t = start;
-                        node_d = lyd_search(node_d->next, node_s->module, node_s->name, strlen(node_s->name), LYS_LIST, NULL, 0);
+                        lyd_find_sibling_next(node_d->next, node_s->module, node_s->name, 0, NULL, 0, (struct lyd_node **)&node_d);
                         if (node_d) {
                             /* reset variables to the first predicate of this list to check it completely */
                             key_d = node_d;
@@ -1823,7 +1841,7 @@
                             break;
                         }
                         /* go to another instance */
-                        key_d = lyd_search(key_d->next, node_s->module, node_s->name, strlen(node_s->name), LYS_LEAFLIST, NULL, 0);
+                        lyd_find_sibling_next(key_d->next, node_s->module, node_s->name, 0, NULL, 0, (struct lyd_node **)&key_d);
                     }
                     if (!key_d) {
                         asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - leaf-list-predicate \"%.*s\" does not match any \"%s\" instance.",
@@ -1871,7 +1889,7 @@
                 if (node_d) {
                     /* get the correct instance */
                     for (uint64_t u = pos; u > 1; u--) {
-                        node_d = lyd_search(node_d->next, node_s->module, node_s->name, strlen(node_s->name), node_s->nodetype, NULL, 0);
+                        lyd_find_sibling_next(node_d->next, node_s->module, node_s->name, 0, NULL, 0, (struct lyd_node **)&node_d);
                         if (!node_d) {
                             asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - "
                                      "position-predicate %"PRIu64" is bigger than number of instances in the data tree (%"PRIu64").",
@@ -2213,7 +2231,7 @@
                 start_search = lyd_node_children(node);
 next_instance_inner:
                 if (start_search) {
-                    node = lyd_search(start_search, mod_node, id, id_len, 0, NULL, 0);
+                    lyd_find_sibling_next(start_search, mod_node, id, id_len, NULL, 0, (struct lyd_node **)&node);
                 } else {
                     node = NULL;
                 }
@@ -2222,7 +2240,7 @@
                 LY_ARRAY_FOR(trees, u) {
                     start_search = trees[u];
 next_instance_toplevel:
-                    node = lyd_search(start_search, mod_node, id, id_len, 0, NULL, 0);
+                    lyd_find_sibling_next(start_search, mod_node, id, id_len, NULL, 0, (struct lyd_node **)&node);
                     if (node) {
                         break;
                     }
@@ -2270,7 +2288,7 @@
             ly_parse_nodeid(&token, &src_prefix, &src_prefix_len, &src, &src_len);
             mod_pred = lys_module_find_prefix(mod_context, src_prefix, src_prefix_len);
 
-            key = (const struct lyd_node_term*)lyd_search(lyd_node_children(node), mod_pred, src, src_len, LYS_LEAF, NULL, 0);
+            lyd_find_sibling_next(lyd_node_children(node), mod_pred, src, src_len, NULL, 0, (struct lyd_node **)&key);
             if (!key) {
                 asprintf(errmsg, "Internal error - missing expected list's key \"%.*s\" in module \"%s\" (%s:%d).",
                          (int)src_len, src, mod_pred->name, __FILE__, __LINE__);
@@ -2300,14 +2318,14 @@
                 if (!value) {
                     /* top-level search */
                     LY_ARRAY_FOR(trees, u) {
-                        value = lyd_search(trees[u], mod_pred, src, src_len, 0, NULL, 0);
+                        lyd_find_sibling_next(trees[u], mod_pred, src, src_len, NULL, 0, (struct lyd_node **)&value);
                         if (value) {
                             break;
                         }
                     }
                 } else {
                     /* inner node */
-                    value = lyd_search(lyd_node_children(value), mod_pred, src, src_len, 0, NULL, 0);
+                    lyd_find_sibling_next(lyd_node_children(value), mod_pred, src, src_len, NULL, 0, (struct lyd_node **)&value);
                 }
                 if (!value) {
                     /* node not found - try another instance */
@@ -2388,8 +2406,8 @@
 
     /* check value according to the real type of the leafref target */
     ret = type_lr->realtype->plugin->store(ctx, type_lr->realtype, value, value_len, options,
-                                             resolve_prefix, parser, format, context_node, trees,
-                                             storage, canonized, err);
+                                           resolve_prefix, parser, format, context_node, trees,
+                                           storage, canonized, err);
     if (ret != LY_SUCCESS && ret != LY_EINCOMPLETE) {
         return ret;
     }
@@ -2467,6 +2485,18 @@
 }
 
 /**
+ * @brief Has canonical of the YANG built-in leafref type.
+ */
+static int
+ly_type_canon_leafref(struct lysc_type *type)
+{
+    struct lysc_type_leafref *lref_type;
+
+    lref_type = (struct lysc_type_leafref *)type;
+    return lref_type->realtype->plugin->has_canon(lref_type->realtype);
+}
+
+/**
  * @brief Validate, canonize and store value of the YANG built-in union type.
  *
  * Implementation of the ly_type_store_clb.
@@ -2652,46 +2682,86 @@
 }
 
 /**
+ * @brief Has canonical of the YANG built-in union type.
+ */
+static int
+ly_type_canon_union(struct lysc_type *type)
+{
+    struct lysc_type_union *uni_type;
+    uint16_t i;
+
+    uni_type = (struct lysc_type_union *)type;
+
+    LY_ARRAY_FOR(uni_type->types, i) {
+        if (!uni_type->types[i]->plugin->has_canon(uni_type->types[i])) {
+            return 0;
+        }
+    }
+
+    /* all types have canonical value */
+    return 1;
+}
+
+/**
  * @brief Set of type plugins for YANG built-in types
  */
 struct lysc_type_plugin ly_builtin_type_plugins[LY_DATA_TYPE_COUNT] = {
     {0}, /* LY_TYPE_UNKNOWN */
-    {.type = LY_TYPE_BINARY, .store = ly_type_store_binary, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
-     .duplicate = ly_type_dup_canonical, .free = ly_type_free_canonical, .id = "libyang 2 - binary, version 1"},
-    {.type = LY_TYPE_UINT8, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
-     .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical, .id = "libyang 2 - unsigned integer, version 1"},
-    {.type = LY_TYPE_UINT16, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
-     .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical, .id = "libyang 2 - unsigned integer, version 1"},
-    {.type = LY_TYPE_UINT32, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
-     .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical, .id = "libyang 2 - unsigned integer, version 1"},
-    {.type = LY_TYPE_UINT64, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
-     .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical, .id = "libyang 2 - unsigned integer, version 1"},
-    {.type = LY_TYPE_STRING, .store = ly_type_store_string, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
-     .duplicate = ly_type_dup_original, .free = ly_type_free_original, .id = "libyang 2 - string, version 1"},
-    {.type = LY_TYPE_BITS, .store = ly_type_store_bits, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
-     .duplicate = ly_type_dup_bits, .free = ly_type_free_bits, .id = "libyang 2 - bits, version 1"},
-    {.type = LY_TYPE_BOOL, .store = ly_type_store_boolean, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
-     .duplicate = ly_type_dup_boolean, .free = ly_type_free_original, .id = "libyang 2 - boolean, version 1"},
-    {.type = LY_TYPE_DEC64, .store = ly_type_store_decimal64, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
-     .duplicate = ly_type_dup_decimal64, .free = ly_type_free_canonical, .id = "libyang 2 - decimal64, version 1"},
-    {.type = LY_TYPE_EMPTY, .store = ly_type_store_empty, .compare = ly_type_compare_empty, .print = ly_type_print_canonical,
-     .duplicate = ly_type_dup_original, .free = ly_type_free_original, .id = "libyang 2 - empty, version 1"},
-    {.type = LY_TYPE_ENUM, .store = ly_type_store_enum, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
-     .duplicate = ly_type_dup_enum, .free = ly_type_free_original, .id = "libyang 2 - enumeration, version 1"},
-    {.type = LY_TYPE_IDENT, .store = ly_type_store_identityref, .compare = ly_type_compare_identityref, .print = ly_type_print_identityref,
-     .duplicate = ly_type_dup_identityref, .free = ly_type_free_canonical, .id = "libyang 2 - identityref, version 1"},
-    {.type = LY_TYPE_INST, .store = ly_type_store_instanceid, .compare = ly_type_compare_instanceid, .print = ly_type_print_instanceid,
-     .duplicate = ly_type_dup_instanceid, .free = ly_type_free_instanceid, .id = "libyang 2 - instance-identifier, version 1"},
-    {.type = LY_TYPE_LEAFREF, .store = ly_type_store_leafref, .compare = ly_type_compare_leafref, .print = ly_type_print_leafref,
-     .duplicate = ly_type_dup_leafref, .free = ly_type_free_leafref, .id = "libyang 2 - leafref, version 1"},
-    {.type = LY_TYPE_UNION, .store = ly_type_store_union, .compare = ly_type_compare_union, .print = ly_type_print_union,
-     .duplicate = ly_type_dup_union, .free = ly_type_free_union, .id = "libyang 2 - union,version 1"},
-    {.type = LY_TYPE_INT8, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
-     .duplicate = ly_type_dup_int, .free = ly_type_free_canonical, .id = "libyang 2 - integer, version 1"},
-    {.type = LY_TYPE_INT16, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
-     .duplicate = ly_type_dup_int, .free = ly_type_free_canonical, .id = "libyang 2 - integer, version 1"},
-    {.type = LY_TYPE_INT32, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
-     .duplicate = ly_type_dup_int, .free = ly_type_free_canonical, .id = "libyang 2 - integer, version 1"},
-    {.type = LY_TYPE_INT64, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .print = ly_type_print_canonical,
-     .duplicate = ly_type_dup_int, .free = ly_type_free_canonical, .id = "libyang 2 - integer, version 1"},
+    {.type = LY_TYPE_BINARY, .store = ly_type_store_binary, .compare = ly_type_compare_canonical,
+        .print = ly_type_print_canonical, .duplicate = ly_type_dup_canonical, .free = ly_type_free_canonical,
+        .has_canon = ly_type_canon_true, .id = "libyang 2 - binary, version 1"},
+    {.type = LY_TYPE_UINT8, .store = ly_type_store_uint, .compare = ly_type_compare_canonical,
+        .print = ly_type_print_canonical, .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical,
+        .has_canon = ly_type_canon_true, .id = "libyang 2 - unsigned integer, version 1"},
+    {.type = LY_TYPE_UINT16, .store = ly_type_store_uint, .compare = ly_type_compare_canonical,
+        .print = ly_type_print_canonical, .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical,
+        .has_canon = ly_type_canon_true, .id = "libyang 2 - unsigned integer, version 1"},
+    {.type = LY_TYPE_UINT32, .store = ly_type_store_uint, .compare = ly_type_compare_canonical,
+        .print = ly_type_print_canonical, .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical,
+        .has_canon = ly_type_canon_true, .id = "libyang 2 - unsigned integer, version 1"},
+    {.type = LY_TYPE_UINT64, .store = ly_type_store_uint, .compare = ly_type_compare_canonical,
+        .print = ly_type_print_canonical, .duplicate = ly_type_dup_uint, .free = ly_type_free_canonical,
+        .has_canon = ly_type_canon_true, .id = "libyang 2 - unsigned integer, version 1"},
+    {.type = LY_TYPE_STRING, .store = ly_type_store_string, .compare = ly_type_compare_canonical,
+        .print = ly_type_print_canonical, .duplicate = ly_type_dup_original, .free = ly_type_free_original,
+        .has_canon = ly_type_canon_true, .id = "libyang 2 - string, version 1"},
+    {.type = LY_TYPE_BITS, .store = ly_type_store_bits, .compare = ly_type_compare_canonical,
+        .print = ly_type_print_canonical, .duplicate = ly_type_dup_bits, .free = ly_type_free_bits,
+        .has_canon = ly_type_canon_true, .id = "libyang 2 - bits, version 1"},
+    {.type = LY_TYPE_BOOL, .store = ly_type_store_boolean, .compare = ly_type_compare_canonical,
+        .print = ly_type_print_canonical, .duplicate = ly_type_dup_boolean, .free = ly_type_free_original,
+        .has_canon = ly_type_canon_true, .id = "libyang 2 - boolean, version 1"},
+    {.type = LY_TYPE_DEC64, .store = ly_type_store_decimal64, .compare = ly_type_compare_canonical,
+        .print = ly_type_print_canonical, .duplicate = ly_type_dup_decimal64, .free = ly_type_free_canonical,
+        .has_canon = ly_type_canon_true, .id = "libyang 2 - decimal64, version 1"},
+    {.type = LY_TYPE_EMPTY, .store = ly_type_store_empty, .compare = ly_type_compare_empty,
+        .print = ly_type_print_canonical, .duplicate = ly_type_dup_original, .free = ly_type_free_original,
+        .has_canon = ly_type_canon_true, .id = "libyang 2 - empty, version 1"},
+    {.type = LY_TYPE_ENUM, .store = ly_type_store_enum, .compare = ly_type_compare_canonical,
+        .print = ly_type_print_canonical, .duplicate = ly_type_dup_enum, .free = ly_type_free_original,
+        .has_canon = ly_type_canon_true, .id = "libyang 2 - enumeration, version 1"},
+    {.type = LY_TYPE_IDENT, .store = ly_type_store_identityref, .compare = ly_type_compare_identityref,
+        .print = ly_type_print_identityref, .duplicate = ly_type_dup_identityref, .free = ly_type_free_canonical,
+        .has_canon = ly_type_canon_false, .id = "libyang 2 - identityref, version 1"},
+    {.type = LY_TYPE_INST, .store = ly_type_store_instanceid, .compare = ly_type_compare_instanceid,
+        .print = ly_type_print_instanceid, .duplicate = ly_type_dup_instanceid, .free = ly_type_free_instanceid,
+        .has_canon = ly_type_canon_false, .id = "libyang 2 - instance-identifier, version 1"},
+    {.type = LY_TYPE_LEAFREF, .store = ly_type_store_leafref, .compare = ly_type_compare_leafref,
+        .print = ly_type_print_leafref, .duplicate = ly_type_dup_leafref, .free = ly_type_free_leafref,
+        .has_canon = ly_type_canon_leafref, .id = "libyang 2 - leafref, version 1"},
+    {.type = LY_TYPE_UNION, .store = ly_type_store_union, .compare = ly_type_compare_union,
+        .print = ly_type_print_union, .duplicate = ly_type_dup_union, .free = ly_type_free_union,
+        .has_canon = ly_type_canon_union, .id = "libyang 2 - union,version 1"},
+    {.type = LY_TYPE_INT8, .store = ly_type_store_int, .compare = ly_type_compare_canonical,
+        .print = ly_type_print_canonical, .duplicate = ly_type_dup_int, .free = ly_type_free_canonical,
+        .has_canon = ly_type_canon_true, .id = "libyang 2 - integer, version 1"},
+    {.type = LY_TYPE_INT16, .store = ly_type_store_int, .compare = ly_type_compare_canonical,
+        .print = ly_type_print_canonical, .duplicate = ly_type_dup_int, .free = ly_type_free_canonical,
+        .has_canon = ly_type_canon_true, .id = "libyang 2 - integer, version 1"},
+    {.type = LY_TYPE_INT32, .store = ly_type_store_int, .compare = ly_type_compare_canonical,
+        .print = ly_type_print_canonical, .duplicate = ly_type_dup_int, .free = ly_type_free_canonical,
+        .has_canon = ly_type_canon_true, .id = "libyang 2 - integer, version 1"},
+    {.type = LY_TYPE_INT64, .store = ly_type_store_int, .compare = ly_type_compare_canonical,
+        .print = ly_type_print_canonical, .duplicate = ly_type_dup_int, .free = ly_type_free_canonical,
+        .has_canon = ly_type_canon_true, .id = "libyang 2 - integer, version 1"},
 };
diff --git a/src/plugins_types.h b/src/plugins_types.h
index 4df1d94..3db7f36 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -95,13 +95,14 @@
 /**
  * @defgroup plugintypeopts Options for type plugin callbacks. The same set of the options is passed to all the type's callbacks used together.
  *
- * Options applicable to ly_type_validate_clb() and ly_typestore_clb.
+ * Options applicable to ly_type_validate_clb() and ly_type_store_clb.
  * @{
  */
 #define LY_TYPE_OPTS_CANONIZE     0x01 /**< Canonize the given value and store it (insert into the context's dictionary)
                                             as the value's canonized string */
-#define LY_TYPE_OPTS_DYNAMIC      0x02 /**< Flag for the dynamically allocated string value, in this case the value is supposed to be freed
-                                            or directly inserted into the context's dictionary (e.g. in case of canonization).
+#define LY_TYPE_OPTS_DYNAMIC      0x02 /**< Flag for the dynamically allocated string value, in this case the value
+                                            is supposed to be freed or directly inserted into the context's dictionary
+                                            (e.g. in case of canonization).
                                             In any case, the caller of the callback does not free the provided string value after calling
                                             the type's callbacks with this option */
 #define LY_TYPE_OPTS_STORE        0x04 /**< Flag announcing calling of ly_type_store_clb() */
@@ -130,22 +131,23 @@
  * @param[in] value Lexical representation of the value to be validated (and canonized).
  *            It is never NULL, empty string is represented as "" with zero @p value_len.
  * @param[in] value_len Length (number of bytes) of the given \p value.
- * @param[in] options [Type plugin options ](@ref plugintypeopts).
- *
+ * @param[in] options [Type plugin options](@ref plugintypeopts).
  * @param[in] resolve_prefix Parser-specific callback to resolve prefixes used in the value strings.
  * @param[in] parser Parser's data for @p resolve_prefix
  * @param[in] format Input format of the data.
- * @param[in] context_node The @p value's node for the case that the require-instance restriction is supposed to be resolved. This argument is of
- *            lys_node (in case LY_TYPE_OPTS_INCOMPLETE_DATA or LY_TYPE_OPTS_SCHEMA set in @p options) or lyd_node structure.
- * @param[in] trees ([Sized array](@ref sizedarrays)) of external data trees (e.g. when validating RPC/Notification) where the required data
- *            instance can be placed.
- *
+ * @param[in] context_node The @p value's node for the case that the require-instance restriction is supposed to be resolved.
+ *            This argument is a lys_node (in case LY_TYPE_OPTS_INCOMPLETE_DATA or LY_TYPE_OPTS_SCHEMA set in @p options)
+ *            or lyd_node structure.
+ * @param[in] trees ([Sized array](@ref sizedarrays)) of external data trees (e.g. when validating RPC/Notification)
+ *            where the required data instance can be placed.
  * @param[in,out] storage If LY_TYPE_OPTS_STORE option set, the parsed data are stored into this structure in the type's specific way.
  *             If the @p canonized differs from the storage's canonized member, the canonized value is also stored here despite the
  *             LY_TYPE_OPTS_CANONIZE option.
- * @param[out] canonized If LY_TYPE_OPTS_CANONIZE option set, the canonized string stored in the @p ctx dictionary is returned via this parameter.
- * @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic error message is prepared instead.
- * The error structure can be created by ly_err_new().
+ * @param[out] canonized If LY_TYPE_OPTS_CANONIZE option set, the canonized string stored in the @p ctx dictionary
+ *             is returned via this parameter.
+ * @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic
+ *             error message is prepared instead.
+ *             The error structure can be created by ly_err_new().
  * @return LY_SUCCESS on success
  * @return LY_EINCOMPLETE in case the option included LY_TYPE_OPTS_INCOMPLETE_DATA flag and the data @p trees are needed to finish the validation.
  * @return LY_ERR value if an error occurred and the value could not be canonized following the type's rules.
@@ -168,7 +170,7 @@
 typedef LY_ERR (*ly_type_compare_clb)(const struct lyd_value *val1, const struct lyd_value *val2);
 
 /**
- * @brief Callback to receive printed (canoncal) value of the data stored in @p value.
+ * @brief Callback to receive printed (canonical) value of the data stored in @p value.
  *
  * @param[in] value Value to print.
  * @param[in] format Format in which the data are supposed to be printed.
@@ -181,7 +183,8 @@
  *         can be responsible for freeing allocated memory.
  * @return NULL in case of error.
  */
-typedef const char *(*ly_type_print_clb)(const struct lyd_value *value, LYD_FORMAT format, ly_clb_get_prefix get_prefix, void *printer, int *dynamic);
+typedef const char *(*ly_type_print_clb)(const struct lyd_value *value, LYD_FORMAT format, ly_clb_get_prefix get_prefix,
+                                         void *printer, int *dynamic);
 
 /**
  * @brief Callback to duplicate data in data structure. Note that callback is even responsible for duplicating lyd_value::canonized.
@@ -204,6 +207,18 @@
 typedef void (*ly_type_free_clb)(struct ly_ctx *ctx, struct lyd_value *value);
 
 /**
+ * @brief Callback for returning information whether the type has a canonical value.
+ *
+ * Note that if it returns non-zero (true), this type's @p print and @p store callbacks must never use
+ * its @p format and @p get_prefix parameters! Also, @p print callback should never set @p dynamic to true!
+ *
+ * @param[in] type Type of the value.
+ * @return 0 if the type has no canonical value.
+ * @return non-zero if the type has a canonical value.
+ */
+typedef int (*ly_type_has_canon_clb)(struct lysc_type *type);
+
+/**
  * @brief Hold type-specific functions for various operations with the data values.
  *
  * libyang includes set of plugins for all the built-in types. They are, by default, inherited to the derived types.
@@ -217,6 +232,7 @@
     ly_type_print_clb print;         /**< printer callback to get string representing the value */
     ly_type_dup_clb duplicate;       /**< data duplication callback */
     ly_type_free_clb free;           /**< optional function to free the type-spceific way stored value */
+    ly_type_has_canon_clb has_canon; /**< callback for checking whether a type has caonical value */
     const char *id;                  /**< Plugin identification (mainly for distinguish incompatible versions when used by external tools) */
 };
 
diff --git a/src/tree_data.c b/src/tree_data.c
index 61d9ca6..018259f 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -30,6 +30,16 @@
 #include "tree_schema.h"
 #include "plugins_exts_metadata.h"
 
+struct ly_keys {
+    char *str;
+    struct {
+        const struct lysc_node_leaf *schema;
+        char *value;
+        const char *can_val;
+    } *keys;
+    size_t key_count;
+};
+
 API void
 lyd_trees_free(const struct lyd_node **trees, int free_data)
 {
@@ -103,49 +113,6 @@
     return trees;
 }
 
-API const struct lyd_node *
-lyd_search(const struct lyd_node *first, const struct lys_module *module,
-          const char *name, size_t name_len, uint16_t nodetype, const char *value, size_t value_len)
-{
-    const struct lyd_node *node = NULL;
-    const struct lysc_node *snode;
-
-    LY_CHECK_ARG_RET(NULL, module, name, NULL);
-    if (!nodetype) {
-        nodetype = 0xffff;
-    }
-
-    LY_LIST_FOR(first, node) {
-        snode = node->schema;
-        if (!(snode->nodetype & nodetype)) {
-            continue;
-        }
-        if (snode->module != module) {
-            continue;
-        }
-
-        if (ly_strncmp(snode->name, name, name_len)) {
-            continue;
-        }
-
-        if (value) {
-            if (snode->nodetype == LYS_LIST) {
-                /* TODO handle value as keys of the list instance */
-            } else if (snode->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
-                if (ly_strncmp(((struct lyd_node_term*)node)->value.original, value, value_len)) {
-                    continue;
-                }
-            } else {
-                continue;
-            }
-        }
-
-        /* all criteria passed */
-        return node;
-    }
-    return NULL;
-}
-
 LY_ERR
 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)
@@ -457,7 +424,8 @@
 lyd_target(struct lyd_value_path *path, const struct lyd_node **trees)
 {
     unsigned int u, v, x;
-    const struct lyd_node *node = NULL, *parent = NULL, *start_search;
+    const struct lyd_node *parent = NULL, *start_search;
+    struct lyd_node *node = NULL;
     uint64_t pos = 1;
 
     LY_CHECK_ARG_RET(NULL, path, trees, NULL);
@@ -466,13 +434,13 @@
         if (parent) {
             start_search = lyd_node_children(parent);
 search_inner:
-            node = lyd_search(start_search, path[u].node->module, path[u].node->name, strlen(path[u].node->name), path[u].node->nodetype, NULL, 0);
+            lyd_find_sibling_next(start_search, path[u].node->module, path[u].node->name, 0, NULL, 0, &node);
         } else {
             LY_ARRAY_FOR(trees, v) {
                 start_search = trees[v];
 search_toplevel:
                 /* WARNING! to use search_toplevel label correctly, variable v must be preserved and not changed! */
-                node = lyd_search(start_search, path[u].node->module, path[u].node->name, strlen(path[u].node->name), path[u].node->nodetype, NULL, 0);
+                lyd_find_sibling_next(start_search, path[u].node->module, path[u].node->name, 0, NULL, 0, &node);
                 if (node) {
                     break;
                 }
@@ -495,9 +463,9 @@
             } else if (path[u].predicates[x].type == 1) {
                 /* key-predicate */
                 struct lysc_type *type = ((struct lysc_node_leaf*)path[u].predicates[x].key)->type;
-                const struct lyd_node *key = lyd_search(lyd_node_children(node), path[u].predicates[x].key->module,
-                                                        path[u].predicates[x].key->name, strlen(path[u].predicates[x].key->name),
-                                                        LYS_LEAF, NULL, 0);
+                struct lyd_node *key;
+                lyd_find_sibling_next(lyd_node_children(node), path[u].predicates[x].key->module,
+                                      path[u].predicates[x].key->name, 0, NULL, 0, &key);
                 if (!key) {
                     /* probably error and we shouldn't be here due to previous checks when creating path */
                     goto search_repeat;
@@ -1133,3 +1101,501 @@
 
     return buffer;
 }
+
+API struct ly_set *
+lyd_find_instance(const struct lyd_node *sibling, const struct lysc_node *schema)
+{
+    struct ly_set *ret, *ret_aux, *spath;
+    const struct lysc_node *siter, *sparent;
+    const struct lyd_node *iter;
+    unsigned int i, j;
+
+    LY_CHECK_ARG_RET(NULL, sibling, schema, NULL);
+    if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
+        LOGARG(schema->module->ctx, schema);
+        return NULL;
+    }
+
+    ret = ly_set_new();
+    spath = ly_set_new();
+    LY_CHECK_ERR_GOTO(!ret || !spath, LOGMEM(schema->module->ctx), error);
+
+    /* build schema path until sibling parent */
+    sparent = sibling->parent ? sibling->parent->schema : NULL;
+    for (siter = schema; siter && (siter != sparent); siter = siter->parent) {
+        if (siter->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC | LYS_ACTION)) {
+            /* standard data node */
+            ly_set_add(spath, (void *)siter, LY_SET_OPT_USEASLIST);
+
+        } /* else skip the rest node types */
+    }
+    /* no valid path */
+    LY_CHECK_GOTO(!spath->count, error);
+
+    /* start searching */
+    LY_LIST_FOR(sibling, iter) {
+        if (iter->schema == spath->objs[spath->count - 1]) {
+            ly_set_add(ret, (void *)iter, LY_SET_OPT_USEASLIST);
+        }
+    }
+    for (i = spath->count - 1; i; i--) {
+        if (!ret->count) {
+            /* nothing found */
+            break;
+        }
+
+        ret_aux = ly_set_new();
+        LY_CHECK_ERR_GOTO(!ret_aux, LOGMEM(schema->module->ctx), error);
+        for (j = 0; j < ret->count; j++) {
+            LY_LIST_FOR(lyd_node_children(ret->objs[j]), iter) {
+                if (iter->schema == spath->objs[i - 1]) {
+                    ly_set_add(ret_aux, (void *)iter, LY_SET_OPT_USEASLIST);
+                }
+            }
+        }
+        ly_set_free(ret, NULL);
+        ret = ret_aux;
+    }
+
+    ly_set_free(spath, NULL);
+    return ret;
+
+error:
+    ly_set_free(ret, NULL);
+    ly_set_free(spath, NULL);
+
+    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)
+{
+    LY_ERR rc;
+    const struct lyd_node *node = NULL;
+    struct lyd_node_term *term;
+    const struct lysc_node *schema;
+    struct ly_keys keys = {0};
+    const char *value = NULL, *node_val;
+    size_t i;
+    int dynamic;
+
+    LY_CHECK_ARG_RET(NULL, module, name, LY_EINVAL);
+
+    if (!first) {
+        /* no data */
+        *match = NULL;
+        return LY_ENOTFOUND;
+    }
+
+    /* find schema */
+    schema = lys_find_child(first->parent ? first->parent->schema : NULL, module, name, name_len, 0, 0);
+    if (!schema) {
+        LOGERR(module->ctx, LY_EINVAL, "Schema node not found.");
+        return LY_EINVAL;
+    }
+
+    if (key_or_value && !val_len) {
+        val_len = strlen(key_or_value);
+    }
+
+    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);
+    } 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);
+    }
+
+    /* find first matching value */
+    LY_LIST_FOR(first, node) {
+        if (node->schema != schema) {
+            continue;
+        }
+
+        if ((schema->nodetype == LYS_LIST) && keys.str) {
+            /* compare all set keys */
+            for (i = 0; i < keys.key_count; ++i) {
+                /* find key */
+                rc = lyd_find_sibling_val(lyd_node_children(node), (struct lysc_node *)keys.keys[i].schema, NULL, 0,
+                                          (struct lyd_node **)&term);
+                if (rc == LY_ENOTFOUND) {
+                    /* all keys must always exist */
+                    LOGINT_RET(module->ctx);
+                }
+                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)) {
+                    break;
+                }
+            }
+
+            if (i < keys.key_count) {
+                /* not a match */
+                continue;
+            }
+        } else if ((schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && value) {
+            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)) {
+                /* not a match */
+                continue;
+            }
+        }
+
+        /* all criteria passed */
+        break;
+    }
+
+    if (!node) {
+        rc = LY_ENOTFOUND;
+        *match = NULL;
+        goto cleanup;
+    }
+
+    /* success */
+    *match = (struct lyd_node *)node;
+    rc = LY_SUCCESS;
+
+cleanup:
+    ly_keys_clean(&keys);
+    lydict_remove(module->ctx, value);
+    return rc;
+}
+
+API LY_ERR
+lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match)
+{
+    struct lyd_node **match_p;
+    struct lyd_node_inner *parent;
+
+    LY_CHECK_ARG_RET(NULL, target, match, LY_EINVAL);
+
+    if (!siblings) {
+        /* no data */
+        *match = NULL;
+        return LY_ENOTFOUND;
+    }
+
+    /* 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) {
+        assert(target->hash);
+
+        /* find by hash */
+        if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
+            siblings = *match_p;
+        } else {
+            /* not found */
+            siblings = NULL;
+        }
+    } else {
+        /* no children hash table */
+        for (; siblings; siblings = siblings->next) {
+            if (!lyd_compare(siblings, target, 0)) {
+                break;
+            }
+        }
+    }
+
+    if (!siblings) {
+        *match = NULL;
+        return LY_ENOTFOUND;
+    }
+
+    *match = (struct lyd_node *)siblings;
+    return LY_SUCCESS;
+}
+
+API LY_ERR
+lyd_find_sibling_set(const struct lyd_node *siblings, const struct lyd_node *target, struct ly_set **set)
+{
+    struct lyd_node_inner *parent;
+    struct lyd_node *match;
+    struct lyd_node **match_p;
+    struct ly_set *ret;
+
+    LY_CHECK_ARG_RET(NULL, target, set, LY_EINVAL);
+
+    if (!siblings) {
+        /* no data */
+        return LY_ENOTFOUND;
+    }
+
+    ret = ly_set_new();
+    LY_CHECK_ERR_RET(!ret, LOGMEM(target->schema->module->ctx), LY_EMEM);
+
+    /* 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) {
+        assert(target->hash);
+
+        /* find by hash */
+        if (!lyht_find(parent->children_ht, &target, target->hash, (void **)&match_p)) {
+            match = *match_p;
+        } else {
+            /* not found */
+            match = NULL;
+        }
+        while (match) {
+            /* add all found nodes into the return set */
+            if (ly_set_add(ret, match, LY_SET_OPT_USEASLIST) == -1) {
+                goto error;
+            }
+
+            /* find next instance */
+            if (lyht_find_next(parent->children_ht, &match, match->hash, (void **)&match_p)) {
+                match = NULL;
+            } else {
+                match = *match_p;
+            }
+        }
+    } else {
+        /* no children hash table */
+        for (; siblings; siblings = siblings->next) {
+            if (!lyd_compare(siblings, target, 0)) {
+                /* a match */
+                if (ly_set_add(ret, (struct lyd_node *)siblings, LY_SET_OPT_USEASLIST) == -1) {
+                    goto error;
+                }
+            }
+        }
+    }
+
+    if (!ret->count) {
+        ly_set_free(ret, NULL);
+        return LY_ENOTFOUND;
+    }
+
+    *set = ret;
+    return LY_SUCCESS;
+
+error:
+    ly_set_free(ret, NULL);
+    return LY_EMEM;
+}
+
+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)
+{
+    LY_ERR rc;
+    struct lyd_node *target = NULL;
+
+    LY_CHECK_ARG_RET(NULL, schema, LY_EINVAL);
+    if ((schema->nodetype == LYS_LIST) && schema->flags & LYS_KEYLESS) {
+        LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - key-less list (%s()).", __func__);
+        return LY_EINVAL;
+    } else if ((schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) && !key_or_value) {
+        LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - no value/keys for a (leaf-)list (%s()).", __func__);
+        return LY_EINVAL;
+    } else if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
+        LOGERR(schema->module->ctx, LY_EINVAL, "Invalid arguments - schema type %s (%s()).",
+               lys_nodetype2str(schema->nodetype), __func__);
+        return LY_EINVAL;
+    }
+
+    if (!siblings) {
+        /* no data */
+        *match = NULL;
+        return LY_ENOTFOUND;
+    }
+
+    /* create data node */
+    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);
+        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;
+    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);
+        break;
+    default:
+        /* unreachable */
+        LOGINT(schema->module->ctx);
+        return LY_EINT;
+    }
+
+    /* find it */
+    rc = lyd_find_sibling_first(siblings, target, match);
+
+    lyd_free_tree(target);
+    return rc;
+}
diff --git a/src/tree_data.h b/src/tree_data.h
index 8b8b986..888b9e9 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -393,12 +393,14 @@
  */
 
 #define LYD_OPT_DATA       0x00 /**< Default type of data - complete datastore content with configuration as well as
-                                     state data. */
+                                state data. */
 #define LYD_OPT_CONFIG     LYD_OPT_NO_STATE /**< A configuration datastore - complete datastore without state data. */
-#define LYD_OPT_GET        LYD_OPT_PARSE_ONLY /**< Data content from a NETCONF reply message to the NETCONF \<get\> operation. */
+#define LYD_OPT_GET        LYD_OPT_PARSE_ONLY /**< Data content from a NETCONF reply message to the NETCONF
+                                \<get\> operation. */
 #define LYD_OPT_GETCONFIG  LYD_OPT_PARSE_ONLY | LYD_OPT_NO_STATE /**< Data content from a NETCONF reply message to
-                                                                      the NETCONF \<get-config\> operation. */
-#define LYD_OPT_EDIT       LYD_OPT_PARSE_ONLY | LYD_OPT_EMPTY_INST /**< Content of the NETCONF \<edit-config\>'s config element. */
+                                the NETCONF \<get-config\> operation. */
+#define LYD_OPT_EDIT       LYD_OPT_PARSE_ONLY | LYD_OPT_NO_STATE | LYD_OPT_EMPTY_INST /**< Content of
+                                the NETCONF \<edit-config\>'s config element. */
 
 #define LYD_OPT_STRICT     0x0001 /**< Instead of silent ignoring data without schema definition raise an error. */
 #define LYD_OPT_PARSE_ONLY 0x0002 /**< Data will be only parsed and no (only required) validation will be performed. */
@@ -427,26 +429,6 @@
 const struct lyd_node *lyd_node_children(const struct lyd_node *node);
 
 /**
- * @brief Find the node, in the list, satisfying the given restrictions.
- *
- * @param[in] first Starting child node for search.
- * @param[in] module Module of the node to find (mandatory argument).
- * @param[in] name Name of the node to find (mandatory argument).
- * @param[in] name_len Optional length of the @p name argument in case it is not NULL-terminated string.
- * @param[in] nodetype Optional mask for the nodetype of the node to find, 0 is understood as all nodetypes.
- * @param[in] value Optional restriction for lyd_node_term nodes to select node with the specific value. Note that this
- * search restriction is limited to compare original string representation of the @p first value. Some of the types have
- * canonical representation defined so the same value can be represented by multiple lexical representation. In such a
- * case the @p value not matching the original representation of @p first may still be the same.
- * For such a case there is more advanced lyd_value_compare() to check if the values matches.
- * @param[in] value_len Optional length of the @p value argument in case it is not NULL-terminated string.
- * @return The sibling node of the @p first (or itself), satisfying the given restrictions.
- * @return NULL in case there is no node satisfying the restrictions.
- */
-const struct lyd_node *lyd_search(const struct lyd_node *first, const struct lys_module *module,
-                                  const char *name, size_t name_len, uint16_t nodetype, const char *value, size_t value_len);
-
-/**
  * @brief Parse (and validate) data from memory.
  *
  * In case of LY_XML format, the data string is parsed completely. It means that when it contains
@@ -739,6 +721,108 @@
  */
 char *lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size_t buflen);
 
+/**
+ * @brief Search in the given siblings for instances of the provided schema node, recursively.
+ * Does **not** use hashes - should not be used unless necessary for best performance.
+ *
+ * If \p sibling is the first top-level sibling, the whole data tree is effectively searched.
+ *
+ * @param[in] sibling Starting data sibling for the search.
+ * @param[in] schema Schema node of the data nodes caller wants to find.
+ * @return Set of found data nodes. If no data node is found, the returned set is empty.
+ * @return NULL in case of error.
+ */
+struct ly_set *lyd_find_instance(const struct lyd_node *sibling, const struct lysc_node *schema);
+
+/**
+ * @brief Find the node, in the list, satisfying the given restrictions.
+ * Does **not** use hashes - should not be used unless necessary for best performance.
+ *
+ * @param[in] first Starting sibling node for search, only succeeding ones are searched.
+ * @param[in] module Module of the node to find.
+ * @param[in] name Name of the node to find.
+ * @param[in] name_len Optional length of the @p name argument in case it is not NULL-terminated string.
+ * @param[in] key_or_value Expected value depends on the type of @p name node:
+ *              LYS_CONTAINER:
+ *              LYS_ANYXML:
+ *              LYS_ANYDATA:
+ *              LYS_NOTIF:
+ *              LYS_RPC:
+ *              LYS_ACTION:
+ *                  NULL should be always set, will be ignored.
+ *              LYS_LEAF:
+ *              LYS_LEAFLIST:
+ *                  Optional restriction on the specific leaf(-list) value. Can be set only if the node
+ *                  has a canonical value!
+ *              LYS_LIST:
+ *                  Optional keys values of the matching list instances in the form of "[key1='val1'][key2='val2']...".
+ *                  The keys do not have to be ordered and not all keys need to be specified, but they must have
+ *                  a canonical value!
+ * @param[in] val_len Optional length of the @p key_or_value argument in case it is not NULL-terminated string.
+ * @param[out] match Found data node.
+ * @return LY_SUCCESS on success, @p match set.
+ * @return LY_ENOTFOUND if not found, @p match set to NULL.
+ * @return LY_ERR value if another error occurred.
+ */
+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);
+
+/**
+ * @brief Search in the given siblings (NOT recursively) for the first target instance.
+ * Uses hashes - should be used whenever possible for best performance.
+ *
+ * @param[in] siblings Siblings to search in including preceding and succeeding nodes.
+ * @param[in] target Target node to find.
+ * @param[out] match Found data node.
+ * @return LY_SUCCESS on success, @p match set.
+ * @return LY_ENOTFOUND if not found, @p match set to NULL.
+ * @return LY_ERR value if another error occurred.
+ */
+LY_ERR lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *target, struct lyd_node **match);
+
+/**
+ * @brief Search in the given siblings for all target instances.
+ * Uses hashes - should be used whenever possible for best performance.
+ *
+ * @param[in] siblings Siblings to search in including preceding and succeeding nodes.
+ * @param[in] target Target node to find. Key-less lists are compared based on
+ * all its descendants (both direct and indirect).
+ * @param[out] set Found nodes in a set in case of success.
+ * @return LY_SUCCESS on success.
+ * @return LY_ENOTFOUND if no matching siblings found.
+ * @return LY_ERR value if another error occurred.
+ */
+LY_ERR lyd_find_sibling_set(const struct lyd_node *siblings, const struct lyd_node *target, struct ly_set **set);
+
+/**
+ * @brief Search in the given siblings for the first schema instance.
+ * Uses hashes - should be used whenever possible for best performance.
+ *
+ * @param[in] siblings Siblings to search in including preceding and succeeding nodes.
+ * @param[in] schema Schema node of the data node to find.
+ * @param[in] key_or_value Expected value depends on the type of \p schema:
+ *              LYS_CONTAINER:
+ *              LYS_LEAF:
+ *              LYS_ANYXML:
+ *              LYS_ANYDATA:
+ *              LYS_NOTIF:
+ *              LYS_RPC:
+ *              LYS_ACTION:
+ *                  NULL should be always set, will be ignored.
+ *              LYS_LEAFLIST:
+ *                  Searched instance value.
+ *              LYS_LIST:
+ *                  Searched instance all key values in the form of "[key1='val1'][key2='val2']...".
+ *                  The keys do not have to be ordered.
+ * @param[out] match Found data node.
+ * @return LY_SUCCESS on success, @p match set.
+ * @return LY_ENOTFOUND if not found, @p match set to NULL.
+ * @return LY_EINVAL if @p schema is a key-less list.
+ * @return LY_ERR value if another error occurred.
+ */
+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);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 370c73f..36c9d08 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -185,8 +185,8 @@
 }
 
 API const struct lysc_node *
-lys_child(const struct lysc_node *parent, const struct lys_module *module,
-          const char *name, size_t name_len, uint16_t nodetype, int options)
+lys_find_child(const struct lysc_node *parent, const struct lys_module *module, const char *name, size_t name_len,
+               uint16_t nodetype, int options)
 {
     const struct lysc_node *node = NULL;
 
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 8f8b58a..0182dea 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -1937,16 +1937,16 @@
  * @param[in] options [ORed options](@ref sgetnextflags).
  * @return Found node if any.
  */
-const struct lysc_node *lys_child(const struct lysc_node *parent, const struct lys_module *module,
-                                  const char *name, size_t name_len, uint16_t nodetype, int options);
+const struct lysc_node *lys_find_child(const struct lysc_node *parent, const struct lys_module *module,
+                                       const char *name, size_t name_len, uint16_t nodetype, int options);
 
 /**
  * @brief Make the specific module implemented.
  *
  * @param[in] mod Module to make implemented. It is not an error
  * to provide already implemented module, it just does nothing.
- * @return LY_SUCCESS or LY_EDENIED in case the context contains some other revision of the
- * same module which is already implemented.
+ * @return LY_SUCCESS on success.
+ * @return LY_EDENIED in case the context contains some other revision of the same module which is already implemented.
  */
 LY_ERR lys_set_implemented(struct lys_module *mod);
 
@@ -1957,8 +1957,8 @@
  * @param[in] node Schema node to check.
  * @param[in] recursive - 0 to check if-feature only in the \p node schema node,
  * - 1 to check if-feature in all ascendant schema nodes until there is a node possibly having an instance in a data tree
- * @return - NULL if enabled,
- * - pointer to the node with the unsatisfied (disabling) if-feature expression.
+ * @return NULL if enabled,
+ * @return pointer to the node with the unsatisfied (disabling) if-feature expression.
  */
 const struct lysc_iffeature *lysc_node_is_disabled(const struct lysc_node *node, int recursive);
 
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 54c39af..f18074c 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -2493,7 +2493,7 @@
                 lys_set_implemented_internal((struct lys_module*)mod, 2);
             }
 
-            dst_node = lys_child(dst_node, mod, dst, dst_len, 0, LYS_GETNEXT_NOSTATECHECK);
+            dst_node = lys_find_child(dst_node, mod, dst, dst_len, 0, LYS_GETNEXT_NOSTATECHECK);
             if (!dst_node) {
                 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
                        "Invalid leafref path predicate \"%.*s\" - unable to find node \"%.*s\" in the rel-path-keyexpr.",
@@ -2711,7 +2711,7 @@
             lys_set_implemented_internal((struct lys_module*)mod, 2);
         }
 
-        node = lys_child(parent, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
+        node = lys_find_child(parent, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
         if (!node) {
             LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
                    "Invalid leafref path - unable to find \"%.*s\".", id - leafref->path, leafref->path);
@@ -4089,7 +4089,7 @@
         }
 
         /* key node must be present */
-        key = (struct lysc_node_leaf*)lys_child(node, node->module, keystr, len, LYS_LEAF, LYS_GETNEXT_NOCHOICE | LYS_GETNEXT_NOSTATECHECK);
+        key = (struct lysc_node_leaf*)lys_find_child(node, node->module, keystr, len, LYS_LEAF, LYS_GETNEXT_NOCHOICE | LYS_GETNEXT_NOSTATECHECK);
         if (!(key)) {
             LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
                    "The list's key \"%.*s\" not found.", len, keystr);
@@ -4234,7 +4234,7 @@
                prefix_len, prefix);
         return LY_EVALID;
     }
-    ch->dflt = (struct lysc_node_case*)lys_child(node, node->module, name, 0, LYS_CASE, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCASE);
+    ch->dflt = (struct lysc_node_case*)lys_find_child(node, node->module, name, 0, LYS_CASE, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCASE);
     if (!ch->dflt) {
         LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
                "Default case \"%s\" not found.", dflt);
@@ -4285,7 +4285,7 @@
         mod = ctx->mod;
     }
     /* get the default case */
-    cs = (struct lysc_node_case*)lys_child((struct lysc_node*)ch, mod, name, 0, LYS_CASE, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCASE);
+    cs = (struct lysc_node_case*)lys_find_child((struct lysc_node*)ch, mod, name, 0, LYS_CASE, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCASE);
     if (!cs) {
         LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
                "Invalid deviation adding \"default\" property \"%s\" of choice - the specified case does not exists.", dflt);
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 4bf97aa..3fd214a 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -108,7 +108,7 @@
             current_nodetype = LYS_INOUT;
         } else {
 getnext:
-            context_node = lys_child(context_node, mod, name, name_len, 0,
+            context_node = lys_find_child(context_node, mod, name, name_len, 0,
                                      getnext_extra_flag | LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
             if (!context_node) {
                 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
diff --git a/src/validation.c b/src/validation.c
index 618e096..e2deb7a 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -516,7 +516,6 @@
 lyd_validate_data(const struct lyd_node **trees, const struct lys_module **modules, int mod_count, struct ly_ctx *ctx,
                   int options)
 {
-    LY_ERR ret;
     uint32_t i = 0, j;
     const struct lys_module *mod;
     struct lyd_node *tree;