data tree CHANGE lyd_attr -> lyd_meta

Also generic tree structures prepared.
diff --git a/src/common.h b/src/common.h
index a556e5a..bcc2426 100644
--- a/src/common.h
+++ b/src/common.h
@@ -237,6 +237,7 @@
 #define LY_VCODE_DUPCASE        LYVE_DATA, "Data for both cases \"%s\" and \"%s\" exist."
 #define LY_VCODE_NOIFF          LYVE_DATA, "Data are disabled by \"%s\" schema node if-feature."
 #define LY_VCODE_INSTATE        LYVE_DATA, "Invalid state data node \"%s\" found."
+#define LY_VCODE_NOKEY          LYVE_DATA, "List instance is missing its key \"%s\"."
 
 /******************************************************************************
  * Context
diff --git a/src/parser_xml.c b/src/parser_xml.c
index f5c8cb8..28238bf 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -47,7 +47,7 @@
 #define LYD_PARSER_BUFSIZE 4078
     char path[LYD_PARSER_BUFSIZE];   /**< buffer for the generated path */
     struct ly_set incomplete_type_validation; /**< set of nodes validated with LY_EINCOMPLETE result */
-    struct ly_set incomplete_type_validation_attrs; /**< set of attributes validated with LY_EINCOMPLETE result */
+    struct ly_set incomplete_type_validation_meta; /**< set of metdata validated with LY_EINCOMPLETE result */
     struct ly_set when_check;        /**< set of nodes with "when" conditions */
 };
 
@@ -133,7 +133,7 @@
 }
 
 static LY_ERR
-lydxml_attributes(struct lyd_xml_ctx *ctx, struct ly_set *attrs_data, const struct lysc_node *sparent, struct lyd_attr **attr)
+lydxml_metadata(struct lyd_xml_ctx *ctx, struct ly_set *attrs_data, const struct lysc_node *sparent, struct lyd_meta **meta)
 {
     LY_ERR ret = LY_EVALID, rc;
     const struct lyxml_ns *ns;
@@ -146,7 +146,7 @@
             /* in XML, all attributes must be prefixed
              * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
             if (ctx->options & LYD_OPT_STRICT) {
-                LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML attribute \"%.*s\".",
+                LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
                        attr_data->name_len, attr_data->name);
             }
 skip_attr:
@@ -169,17 +169,17 @@
             /* module is not implemented or not present in the schema */
             if (ctx->options & LYD_OPT_STRICT) {
                 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
-                       "Unknown (or not implemented) YANG module with namespace \"%s\" for attribute \"%.*s%s%.*s\".",
+                       "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
                        ns, attr_data->prefix_len, attr_data->prefix, attr_data->prefix_len ? ":" : "", attr_data->name_len,
                        attr_data->name);
             }
             goto skip_attr;
         }
 
-        rc = lyd_create_attr(NULL, attr, mod, attr_data->name, attr_data->name_len, attr_data->value,
+        rc = lyd_create_meta(NULL, meta, mod, attr_data->name, attr_data->name_len, attr_data->value,
                              attr_data->value_len, &attr_data->dynamic, lydxml_resolve_prefix, ctx, LYD_XML, sparent);
         if (rc == LY_EINCOMPLETE) {
-            ly_set_add(&ctx->incomplete_type_validation_attrs, attr, LY_SET_OPT_USEASLIST);
+            ly_set_add(&ctx->incomplete_type_validation_meta, meta, LY_SET_OPT_USEASLIST);
         } else if (rc) {
             ret = rc;
             goto cleanup;
@@ -200,7 +200,7 @@
 }
 
 /**
- * @brief Parse XML elements as children YANG data node of the specified parent node.
+ * @brief Parse XML elements as YANG data node children the specified parent node.
  *
  * @param[in] ctx XML YANG data parser context.
  * @param[in] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
@@ -209,14 +209,14 @@
  * @return LY_ERR value.
  */
 static LY_ERR
-lydxml_nodes(struct lyd_xml_ctx *ctx, struct lyd_node_inner *parent, const char **data, struct lyd_node **first)
+lydxml_data_r(struct lyd_xml_ctx *ctx, struct lyd_node_inner *parent, const char **data, struct lyd_node **first)
 {
     LY_ERR ret = LY_SUCCESS;
     const char *prefix, *name;
     size_t prefix_len, name_len;
     struct ly_set attrs_data = {0};
     const struct lyxml_ns *ns;
-    struct lyd_attr *attr = NULL, *attr2;
+    struct lyd_meta *meta = NULL, *meta2;
     const struct lysc_node *snode;
     struct lys_module *mod;
     unsigned int parents_count = ctx->elements.count;
@@ -271,9 +271,9 @@
             return LY_EVALID;
         }
 
-        /* create actual attributes so that prefixes are available in the context */
+        /* create actual metadata so that prefixes are available in the context */
         if (attrs_data.count) {
-            LY_CHECK_GOTO(ret = lydxml_attributes(ctx, &attrs_data, snode, &attr), cleanup);
+            LY_CHECK_GOTO(ret = lydxml_metadata(ctx, &attrs_data, snode, &meta), cleanup);
         }
 
         if (snode->nodetype & (LYS_ACTION | LYS_NOTIF)) {
@@ -344,7 +344,13 @@
 
             /* process children */
             if (ctx->status == LYXML_ELEMENT && parents_count != ctx->elements.count) {
-                ret = lydxml_nodes(ctx, (struct lyd_node_inner *)cur, data, lyd_node_children_p(cur));
+                ret = lydxml_data_r(ctx, (struct lyd_node_inner *)cur, data, lyd_node_children_p(cur));
+                LY_CHECK_GOTO(ret, cleanup);
+            }
+
+            if (snode->nodetype == LYS_LIST) {
+                /* check all keys exist */
+                ret = lyd_parse_check_keys(cur);
                 LY_CHECK_GOTO(ret, cleanup);
             }
 
@@ -426,18 +432,18 @@
             /* node is valid */
             cur->flags &= ~LYD_NEW;
         }
-        LY_LIST_FOR(attr, attr2) {
-            if (!strcmp(attr2->name, "default") && !strcmp(attr2->annotation->module->name, "ietf-netconf-with-defaults")
-                    && attr2->value.boolean) {
+        LY_LIST_FOR(meta, meta2) {
+            if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults")
+                    && meta2->value.boolean) {
                 /* node is default according to the metadata */
                 cur->flags |= LYD_DEFAULT;
             }
         }
 
-        /* add attributes */
-        assert(!cur->attr);
-        cur->attr = attr;
-        attr = NULL;
+        /* add metdata */
+        assert(!cur->meta);
+        cur->meta = meta;
+        meta = NULL;
 
         /* insert */
         lyd_insert_node((struct lyd_node *)parent, first, cur);
@@ -450,7 +456,7 @@
 
 cleanup:
     free(buffer);
-    lyd_free_attr(ctx->ctx, attr, 1);
+    lyd_free_meta(ctx->ctx, meta, 1);
     lyd_free_tree(cur);
     for (unsigned int u = 0; u < attrs_data.count; ++u) {
         if (((struct attr_data_s*)attrs_data.objs[u])->dynamic) {
@@ -466,7 +472,7 @@
 }
 
 LY_ERR
-lyd_parse_xml(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **tree)
+lyd_parse_xml_data(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **tree)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyd_xml_ctx xmlctx = {0};
@@ -482,7 +488,7 @@
     *tree = NULL;
 
     /* parse XML data */
-    ret = lydxml_nodes(&xmlctx, NULL, &data, tree);
+    ret = lydxml_data_r(&xmlctx, NULL, &data, tree);
     LY_CHECK_GOTO(ret, cleanup);
 
     if (!(options & LYD_OPT_PARSE_ONLY)) {
@@ -514,7 +520,7 @@
 
             /* finish incompletely validated terminal values/attributes and when conditions */
             ret = lyd_validate_unres(tree, &xmlctx.when_check, &xmlctx.incomplete_type_validation,
-                                     &xmlctx.incomplete_type_validation_attrs, LYD_XML, lydxml_resolve_prefix, ctx);
+                                     &xmlctx.incomplete_type_validation_meta, LYD_XML, lydxml_resolve_prefix, ctx);
             LY_CHECK_GOTO(ret, cleanup);
 
             /* perform final validation that assumes the data tree is final */
@@ -526,10 +532,10 @@
 cleanup:
     /* there should be no unresolved types stored */
     assert(!(options & LYD_OPT_PARSE_ONLY) || (!xmlctx.incomplete_type_validation.count
-           && !xmlctx.incomplete_type_validation_attrs.count && !xmlctx.when_check.count));
+           && !xmlctx.incomplete_type_validation_meta.count && !xmlctx.when_check.count));
 
     ly_set_erase(&xmlctx.incomplete_type_validation, NULL);
-    ly_set_erase(&xmlctx.incomplete_type_validation_attrs, NULL);
+    ly_set_erase(&xmlctx.incomplete_type_validation_meta, NULL);
     ly_set_erase(&xmlctx.when_check, NULL);
     lyxml_context_clear((struct lyxml_context *)&xmlctx);
     if (ret) {
@@ -538,3 +544,90 @@
     }
     return ret;
 }
+
+static LY_ERR
+lydxml_rpc(struct lyd_xml_ctx *ctx, const char **data, struct ly_attr **attr)
+{
+    const char *prefix, *name;
+    size_t prefix_len, name_len;
+    struct ly_set attrs_data = {0};
+    const struct lyxml_ns *ns;
+
+    LY_CHECK_RET(lyxml_get_element((struct lyxml_context *)ctx, data, &prefix, &prefix_len, &name, &name_len));
+    if (ly_strncmp("rpc", name, name_len)) {
+        /* not an rpc */
+        return LY_ENOT;
+    }
+
+    if (ctx->status == LYXML_ATTRIBUTE) {
+        LY_CHECK_RET(lydxml_attributes_parse(ctx, data, &attrs_data));
+    }
+
+    ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
+    if (!ns || strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
+        /* wrong namespace */
+        return LY_ENOT;
+    }
+
+    /* all fine, just parse the rest of the attributes */
+    if (attrs_data.count) {
+        /* TODO parse into generic attribute structure, that will also be returned */
+        //LY_CHECK_RET(lydxml_attributes(ctx, &attrs_data, NULL, meta));
+    }
+
+    return LY_SUCCESS;
+}
+
+static LY_ERR
+lydxml_action(struct lyd_xml_ctx *ctx, const char **data)
+{
+    /* TODO */
+    return LY_ENOT;
+}
+
+LY_ERR
+lyd_parse_xml_rpc(struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct ly_attr **attr,
+                  struct lyd_node **op)
+{
+    LY_ERR ret = LY_SUCCESS;
+    const char *data_p;
+    struct lyd_xml_ctx xmlctx = {0};
+
+    xmlctx.ctx = ctx;
+    xmlctx.line = 1;
+
+    /* init */
+    *tree = NULL;
+    data_p = data;
+
+    /* parse optional "rpc" element */
+    ret = lydxml_rpc(&xmlctx, &data_p, attr);
+    if (ret == LY_ENOT) {
+        /* reset data, nothing parsed */
+        data_p = data;
+    } else if (ret) {
+        goto cleanup;
+    } else {
+        /* successfully parsed */
+        data = data_p;
+
+        /* parse optional "action" element */
+        ret = lydxml_action(&xmlctx, &data_p);
+        if (ret == LY_ENOT) {
+            data_p = data;
+        } else if (ret) {
+            goto cleanup;
+        }
+    }
+
+    /* parse the rest of data tree normally */
+    ret = lydxml_data_r(&xmlctx, NULL, &data_p, tree);
+    LY_CHECK_GOTO(ret, cleanup);
+
+cleanup:
+    if (ret) {
+        lyd_free_all(*tree);
+        *tree = NULL;
+    }
+    return ret;
+}
diff --git a/src/printer_xml.c b/src/printer_xml.c
index 1dce096..44e8ff4 100644
--- a/src/printer_xml.c
+++ b/src/printer_xml.c
@@ -79,18 +79,18 @@
 xml_print_ns(struct xmlpr_ctx *ctx, const struct lyd_node *node)
 {
     struct lyd_node *next, *cur, *child;
-    struct lyd_attr *attr;
+    struct lyd_meta *meta;
     struct mlist *mlist = NULL, *miter;
     const struct lys_module *wdmod = NULL;
 
-    /* add node attribute modules */
-    for (attr = node->attr; attr; attr = attr->next) {
+    /* add node metadata modules */
+    for (meta = node->meta; meta; meta = meta->next) {
         if (!strcmp(node->schema->name, "filter") &&
                 (!strcmp(node->schema->module->name, "ietf-netconf") ||
                  !strcmp(node->schema->module->name, "notifications"))) {
             /* exception for NETCONF's filter attributes */
             continue;
-        } else if (modlist_add(&mlist, attr->annotation->module)) {
+        } else if (modlist_add(&mlist, meta->annotation->module)) {
             goto print;
         }
     }
@@ -123,14 +123,14 @@
 
         LY_LIST_FOR(((struct lyd_node_inner*)node)->child, child) {
             LYD_TREE_DFS_BEGIN(child, next, cur) {
-                for (attr = cur->attr; attr; attr = attr->next) {
+                for (meta = cur->meta; meta; meta = meta->next) {
                     if (!strcmp(cur->schema->name, "filter") &&
                             (!strcmp(cur->schema->module->name, "ietf-netconf") ||
                              !strcmp(cur->schema->module->name, "notifications"))) {
                         /* exception for NETCONF's filter attributes */
                         continue;
                     } else {
-                        /* TODO annotations r = modlist_add(&mlist, lys_main_module(attr->annotation->module)); */
+                        /* TODO annotations r = modlist_add(&mlist, lys_main_module(meta->annotation->module)); */
                     }
                 }
             LYD_TREE_DFS_END(child, next, cur)}
@@ -169,9 +169,9 @@
  * TODO
  */
 static LY_ERR
-xml_print_attrs(struct xmlpr_ctx *ctx, const struct lyd_node *node)
+xml_print_meta(struct xmlpr_ctx *ctx, const struct lyd_node *node)
 {
-    struct lyd_attr *attr;
+    struct lyd_meta *meta;
     const struct lys_module *wdmod = NULL;
 #if 0
     const char **prefs, **nss;
@@ -205,8 +205,8 @@
         rpc_filter = 1;
     }
 #endif
-    for (attr = node->attr; attr; attr = attr->next) {
-        const char *value = attr->value.realtype->plugin->print(&attr->value, LYD_XML, xml_print_get_prefix, &ns_list, &dynamic);
+    for (meta = node->meta; meta; meta = meta->next) {
+        const char *value = meta->value.realtype->plugin->print(&meta->value, LYD_XML, xml_print_get_prefix, &ns_list, &dynamic);
 
         /* print namespaces connected with the values's prefixes */
         for (u = 0; u < ns_list.count; ++u) {
@@ -218,9 +218,9 @@
 #if 0
         if (rpc_filter) {
             /* exception for NETCONF's filter's attributes */
-            if (!strcmp(attr->name, "select")) {
+            if (!strcmp(meta->name, "select")) {
                 /* xpath content, we have to convert the JSON format into XML first */
-                xml_expr = transform_json2xml(node->schema->module, attr->value_str, 0, &prefs, &nss, &ns_count);
+                xml_expr = transform_json2xml(node->schema->module, meta->value_str, 0, &prefs, &nss, &ns_count);
                 if (!xml_expr) {
                     /* error */
                     return EXIT_FAILURE;
@@ -232,10 +232,10 @@
                 free(prefs);
                 free(nss);
             }
-            ly_print(out, " %s=\"", attr->name);
+            ly_print(out, " %s=\"", meta->name);
         } else {
 #endif
-            ly_print(ctx->out, " %s:%s=\"", attr->annotation->module->prefix, attr->name);
+            ly_print(ctx->out, " %s:%s=\"", meta->annotation->module->prefix, meta->name);
 #if 0
         }
 #endif
@@ -276,7 +276,7 @@
         ctx->toplevel = 0;
     }
 
-    LY_CHECK_RET(xml_print_attrs(ctx, node));
+    LY_CHECK_RET(xml_print_meta(ctx, node));
 
     return LY_SUCCESS;
 }
diff --git a/src/tree.h b/src/tree.h
index 0f02120..bf86260 100644
--- a/src/tree.h
+++ b/src/tree.h
@@ -15,6 +15,8 @@
 #ifndef LY_TREE_H_
 #define LY_TREE_H_
 
+#include "tree_data.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -117,6 +119,33 @@
          (ELEM) = (NEXT))
 
 /**
+ * @brief Generic tree node structure.
+ */
+struct ly_node {
+    LYD_FORMAT format;
+    union {
+        struct {
+            const struct lysc_node *schema;
+            struct lyd_meta *meta;
+        } sch;
+        struct {
+            const char *name;
+            struct ly_attr *attr;
+        } xml;
+    };
+    const char *value;
+};
+
+/**
+ * @brief Generic attribute structure.
+ */
+struct ly_attr {
+    struct ly_attr *next;
+    const char *name;
+    const char *value;
+};
+
+/**
  * @brief YANG built-in types
  */
 typedef enum
@@ -149,36 +178,6 @@
  */
 extern const char* ly_data_type2str[LY_DATA_TYPE_COUNT];
 
-/**
- * @brief Callback provided by the data/schema parsers to type plugins to resolve (format-specific) mapping between prefixes used
- * in the value strings to the YANG schemas.
- *
- * Reverse function to ly_clb_get_prefix.
- *
- * XML uses XML namespaces, JSON uses schema names as prefixes, YIN/YANG uses prefixes of the imports.
- *
- * @param[in] ctx libyang context to find the schema.
- * @param[in] prefix Prefix found in the value string
- * @param[in] prefix_len Length of the @p prefix.
- * @param[in] private Internal data needed by the callback.
- * @return Pointer to the YANG schema identified by the provided prefix or NULL if no mapping found.
- */
-typedef const struct lys_module *(*ly_clb_resolve_prefix)(struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *private);
-
-/**
- * @brief Callback provided by the data/schema printers to type plugins to resolve (format-specific) mapping between YANG module of a data object
- * to prefixes used in the value strings.
- *
- * Reverse function to ly_clb_resolve_prefix.
- *
- * XML uses XML namespaces, JSON uses schema names as prefixes, YIN/YANG uses prefixes of the imports.
- *
- * @param[in] mod YANG module of the object.
- * @param[in] private Internal data needed by the callback.
- * @return String representing prefix for the object of the given YANG module @p mod.
- */
-typedef const char *(*ly_clb_get_prefix)(const struct lys_module *mod, void *private);
-
 /** @} */
 
 #ifdef __cplusplus
diff --git a/src/tree_data.c b/src/tree_data.c
index 9ab42ef..634ede6 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -112,7 +112,7 @@
 }
 
 LY_ERR
-lyd_value_parse_attr(struct ly_ctx *ctx, struct lyd_attr *attr, const char *value, size_t value_len, int *dynamic,
+lyd_value_parse_meta(struct ly_ctx *ctx, struct lyd_meta *meta, const char *value, size_t value_len, int *dynamic,
                      int second, ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
                      const struct lysc_node *ctx_snode, const struct lyd_node *tree)
 {
@@ -122,15 +122,15 @@
     int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
             (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (tree ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
 
-    assert(ctx && attr && ((tree && attr->parent) || ctx_snode));
+    assert(ctx && meta && ((tree && meta->parent) || ctx_snode));
 
-    ant = attr->annotation->data;
+    ant = meta->annotation->data;
 
     if (!second) {
-        attr->value.realtype = ant->type;
+        meta->value.realtype = ant->type;
     }
     ret = ant->type->plugin->store(ctx, ant->type, value, value_len, options, get_prefix, parser, format,
-                                  tree ? (void *)attr->parent : (void *)ctx_snode, tree, &attr->value, NULL, &err);
+                                  tree ? (void *)meta->parent : (void *)ctx_snode, tree, &meta->value, NULL, &err);
     if (ret && (ret != LY_EINCOMPLETE)) {
         if (err) {
             ly_err_print(err);
@@ -262,11 +262,11 @@
 }
 
 API const char *
-lyd_attr2str(const struct lyd_attr *attr, int *dynamic)
+lyd_meta2str(const struct lyd_meta *meta, int *dynamic)
 {
-    LY_CHECK_ARG_RET(attr ? attr->parent->schema->module->ctx : NULL, attr, dynamic, NULL);
+    LY_CHECK_ARG_RET(meta ? meta->parent->schema->module->ctx : NULL, meta, dynamic, NULL);
 
-    return attr->value.realtype->plugin->print(&attr->value, LYD_JSON, json_print_get_prefix, NULL, dynamic);
+    return meta->value.realtype->plugin->print(&meta->value, LYD_JSON, json_print_get_prefix, NULL, dynamic);
 }
 
 API struct lyd_node *
@@ -306,7 +306,7 @@
 
     switch (format) {
     case LYD_XML:
-        lyd_parse_xml(ctx, data, options, &result);
+        lyd_parse_xml_data(ctx, data, options, &result);
         break;
 #if 0
     case LYD_JSON:
@@ -818,6 +818,8 @@
 /**
  * @brief Insert node after a sibling.
  *
+ * Handles inserting into NP containers and key-less lists.
+ *
  * @param[in] sibling Sibling to insert after.
  * @param[in] node Node to insert.
  */
@@ -845,11 +847,15 @@
     }
     node->parent = sibling->parent;
 
-    if (!(node->flags & LYD_DEFAULT)) {
-        /* remove default flags from NP containers */
-        for (par = node->parent; par && (par->flags & LYD_DEFAULT); par = par->parent) {
+    for (par = node->parent; par; par = par->parent) {
+        if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
+            /* remove default flags from NP containers */
             par->flags &= ~LYD_DEFAULT;
         }
+        if ((par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
+            /* rehash key-less list */
+            lyd_hash((struct lyd_node *)par);
+        }
     }
 
     /* insert into hash table */
@@ -859,6 +865,8 @@
 /**
  * @brief Insert node before a sibling.
  *
+ * Handles inserting into NP containers and key-less lists.
+ *
  * @param[in] sibling Sibling to insert before.
  * @param[in] node Node to insert.
  */
@@ -882,11 +890,15 @@
     }
     node->parent = sibling->parent;
 
-    if (!(node->flags & LYD_DEFAULT)) {
-        /* remove default flags from NP containers */
-        for (par = node->parent; par && (par->flags & LYD_DEFAULT); par = par->parent) {
+    for (par = node->parent; par; par = par->parent) {
+        if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
+            /* remove default flags from NP containers */
             par->flags &= ~LYD_DEFAULT;
         }
+        if ((par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
+            /* rehash key-less list */
+            lyd_hash((struct lyd_node *)par);
+        }
     }
 
     /* insert into hash table */
@@ -896,6 +908,8 @@
 /**
  * @brief Insert node as the last child of a parent.
  *
+ * Handles inserting into NP containers and key-less lists.
+ *
  * @param[in] parent Parent to insert into.
  * @param[in] node Node to insert.
  */
@@ -918,11 +932,15 @@
     }
     node->parent = par;
 
-    if (!(node->flags & LYD_DEFAULT)) {
-        /* remove default flags from NP containers */
-        for (; par && (par->flags & LYD_DEFAULT); par = par->parent) {
+    for (; par; par = par->parent) {
+        if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
+            /* remove default flags from NP containers */
             par->flags &= ~LYD_DEFAULT;
         }
+        if ((par->schema->nodetype == LYS_LIST) && (par->schema->flags & LYS_KEYLESS)) {
+            /* rehash key-less list */
+            lyd_hash((struct lyd_node *)par);
+        }
     }
 
     /* insert into hash table */
@@ -933,6 +951,8 @@
 lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling, struct lyd_node *node)
 {
     struct lyd_node *anchor;
+    const struct lysc_node *skey = NULL;
+    int has_keys;
 
     assert((parent || first_sibling) && node && node->hash);
 
@@ -951,6 +971,24 @@
             } else {
                 lyd_insert_last_node(parent, node);
             }
+
+            /* hash list if all its keys were added */
+            assert(parent->schema->nodetype == LYS_LIST);
+            anchor = (struct lyd_node *)lyd_node_children(parent);
+            has_keys = 1;
+            while ((skey = lys_getnext(skey, parent->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
+                if (!anchor || (anchor->schema != skey)) {
+                    /* key missing */
+                    has_keys = 0;
+                    break;
+                }
+
+                anchor = anchor->next;
+            }
+            if (has_keys) {
+                lyd_hash(parent);
+            }
+
         } else {
             /* last child */
             lyd_insert_last_node(parent, node);
@@ -1236,16 +1274,16 @@
 }
 
 LY_ERR
-lyd_create_attr(struct lyd_node *parent, struct lyd_attr **attr, const struct lys_module *mod, const char *name,
+lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, 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, const struct lysc_node *ctx_snode)
 {
     LY_ERR ret;
     struct lysc_ext_instance *ant = NULL;
-    struct lyd_attr *at, *last;
+    struct lyd_meta *mt, *last;
     uint32_t v;
 
-    assert((parent || attr) && mod);
+    assert((parent || meta) && mod);
 
     LY_ARRAY_FOR(mod->compiled->exts, v) {
         if (mod->compiled->exts[v].def->plugin == lyext_plugins_internal[LYEXT_PLUGIN_INTERNAL_ANNOTATION].plugin &&
@@ -1262,28 +1300,28 @@
         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(mod->ctx, at, value, value_len, dynamic, 0, get_prefix, prefix_data, format, ctx_snode, NULL);
+    mt = calloc(1, sizeof *mt);
+    LY_CHECK_ERR_RET(!mt, LOGMEM(mod->ctx), LY_EMEM);
+    mt->parent = parent;
+    mt->annotation = ant;
+    ret = lyd_value_parse_meta(mod->ctx, mt, value, value_len, dynamic, 0, get_prefix, prefix_data, format, ctx_snode, NULL);
     if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
-        free(at);
+        free(mt);
         return ret;
     }
-    at->name = lydict_insert(mod->ctx, name, name_len);
+    mt->name = lydict_insert(mod->ctx, name, name_len);
 
     /* insert as the last attribute */
     if (parent) {
-        if (parent->attr) {
-            for (last = parent->attr; last->next; last = last->next);
-            last->next = at;
+        if (parent->meta) {
+            for (last = parent->meta; last->next; last = last->next);
+            last->next = mt;
         } else {
-            parent->attr = at;
+            parent->meta = mt;
         }
-    } else if (*attr) {
-        for (last = *attr; last->next; last = last->next);
-        last->next = at;
+    } else if (*meta) {
+        for (last = *meta; last->next; last = last->next);
+        last->next = mt;
     }
 
     /* remove default flags from NP containers */
@@ -1292,8 +1330,8 @@
         parent = (struct lyd_node *)parent->parent;
     }
 
-    if (attr) {
-        *attr = at;
+    if (meta) {
+        *meta = mt;
     }
     return ret;
 }
diff --git a/src/tree_data.h b/src/tree_data.h
index 8621539..34ddd46 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -207,21 +207,21 @@
 };
 
 /**
- * @brief Attribute structure.
+ * @brief Metadata structure.
  *
- * The structure provides information about attributes of a data element. Such attributes must map to
+ * The structure provides information about metadata of a data element. Such attributes must map to
  * annotations as specified in RFC 7952. The only exception is the filter type (in NETCONF get operations)
  * and edit-config's operation attributes. In XML, they are represented as standard XML attributes. In JSON,
  * they are represented as JSON elements starting with the '@' character (for more information, see the
  * YANG metadata RFC.
  *
  */
-struct lyd_attr {
-    struct lyd_node *parent;         /**< data node where the attribute is placed */
-    struct lyd_attr *next;           /**< pointer to the next attribute of the same element */
-    struct lysc_ext_instance *annotation; /**< pointer to the attribute/annotation's definition */
-    const char *name;                /**< attribute name */
-    struct lyd_value value;          /**< attribute's value representation */
+struct lyd_meta {
+    struct lyd_node *parent;         /**< data node where the metadata is placed */
+    struct lyd_meta *next;           /**< pointer to the next metadata of the same element */
+    struct lysc_ext_instance *annotation; /**< pointer to the annotation's definition */
+    const char *name;                /**< metadata name */
+    struct lyd_value value;          /**< metadata value representation */
 };
 
 
@@ -258,6 +258,36 @@
 /** @} */
 
 /**
+ * @brief Callback provided by the data/schema parsers to type plugins to resolve (format-specific) mapping between prefixes used
+ * in the value strings to the YANG schemas.
+ *
+ * Reverse function to ly_clb_get_prefix.
+ *
+ * XML uses XML namespaces, JSON uses schema names as prefixes, YIN/YANG uses prefixes of the imports.
+ *
+ * @param[in] ctx libyang context to find the schema.
+ * @param[in] prefix Prefix found in the value string
+ * @param[in] prefix_len Length of the @p prefix.
+ * @param[in] private Internal data needed by the callback.
+ * @return Pointer to the YANG schema identified by the provided prefix or NULL if no mapping found.
+ */
+typedef const struct lys_module *(*ly_clb_resolve_prefix)(struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *private);
+
+/**
+ * @brief Callback provided by the data/schema printers to type plugins to resolve (format-specific) mapping between YANG module of a data object
+ * to prefixes used in the value strings.
+ *
+ * Reverse function to ly_clb_resolve_prefix.
+ *
+ * XML uses XML namespaces, JSON uses schema names as prefixes, YIN/YANG uses prefixes of the imports.
+ *
+ * @param[in] mod YANG module of the object.
+ * @param[in] private Internal data needed by the callback.
+ * @return String representing prefix for the object of the given YANG module @p mod.
+ */
+typedef const char *(*ly_clb_get_prefix)(const struct lys_module *mod, void *private);
+
+/**
  * @brief Generic structure for a data node.
  */
 struct lyd_node {
@@ -274,7 +304,7 @@
                                           never NULL. If there is no sibling node, pointer points to the node
                                           itself. In case of the first node, this pointer points to the last
                                           node in the list. */
-    struct lyd_attr *attr;           /**< pointer to the list of attributes of this node */
+    struct lyd_meta *meta;           /**< pointer to the list of metadata of this node */
 
 #ifdef LY_ENABLED_LYD_PRIV
     void *priv;                      /**< private user data, not used by libyang */
@@ -297,7 +327,7 @@
                                           never NULL. If there is no sibling node, pointer points to the node
                                           itself. In case of the first node, this pointer points to the last
                                           node in the list. */
-    struct lyd_attr *attr;           /**< pointer to the list of attributes of this node */
+    struct lyd_meta *meta;           /**< pointer to the list of metadata of this node */
 
 #ifdef LY_ENABLED_LYD_PRIV
     void *priv;                      /**< private user data, not used by libyang */
@@ -324,7 +354,7 @@
                                           never NULL. If there is no sibling node, pointer points to the node
                                           itself. In case of the first node, this pointer points to the last
                                           node in the list. */
-    struct lyd_attr *attr;           /**< pointer to the list of attributes of this node */
+    struct lyd_meta *meta;           /**< pointer to the list of metadata of this node */
 
 #ifdef LY_ENABLED_LYD_PRIV
     void *priv;                      /**< private user data, not used by libyang */
@@ -349,7 +379,7 @@
                                           never NULL. If there is no sibling node, pointer points to the node
                                           itself. In case of the first node, this pointer points to the last
                                           node in the list. */
-    struct lyd_attr *attr;           /**< pointer to the list of attributes of this node */
+    struct lyd_meta *meta;           /**< pointer to the list of attributes of this node */
 
 #ifdef LY_ENABLED_LYD_PRIV
     void *priv;                      /**< private user data, not used by libyang */
@@ -374,16 +404,13 @@
  * Default parser behavior:
  * - complete input file is always parsed. In case of XML, even not well-formed XML document (multiple top-level
  * elements) is parsed in its entirety,
- * - parser silently ignores data without matching schema node definition. If the caller wants to stop
- * parsing in case of presence of unknown data, the #LYD_OPT_STRICT can be used. The strict mode is useful for
- * NETCONF servers, since NETCONF clients should always send data according to the capabilities announced by the server.
- * On the other hand, the default non-strict mode is useful for clients receiving data from NETCONF server since
- * clients are not required to understand everything the server does. Of course, the optimal strategy for clients is
- * to use filtering to get only the required data. Having an unknown element of the known namespace is always an error.
+ * - parser silently ignores data without matching schema node definition,
+ * - list instances are checked whether they have all the keys, error is raised if not.
  *
  * Default parser validation behavior:
  * - the provided data are expected to provide complete datastore content (both the configuration and state data)
  * and performs data validation according to all YANG rules, specifics follow,
+ * - list instances are expected to have all the keys (it is not checked),
  * - instantiated (status) obsolete data print a warning,
  * - all types are fully resolved (leafref/instance-identifier targets, unions) and must be valid (lists have
  * all the keys, leaf(-lists) correct values),
@@ -401,8 +428,6 @@
                                 \<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_NO_STATE | LYD_OPT_EMPTY_INST /**< Content of
-                                the NETCONF \<edit-config\>'s config element. */
 
 #define LYD_OPT_PARSE_ONLY      0x0001 /**< Data will be only parsed and no validation will be performed. When statements
                                             are kept unevaluated, union types may not be fully resolved, if-feature
@@ -412,8 +437,7 @@
                                             data are not valid, using this flag may lead to some unexpected behavior!
                                             This flag can be used only with #LYD_OPT_PARSE_ONLY. */
 #define LYD_OPT_STRICT          0x0004 /**< Instead of silently ignoring data without schema definition raise an error. */
-#define LYD_OPT_EMPTY_INST      0x0008 /**< Allow leaf/leaf-list instances without values and lists without keys. */
-#define LYD_OPT_NO_STATE        0x0010 /**< Forbid state data in the parsed data. */
+#define LYD_OPT_NO_STATE        0x0008 /**< Forbid state data in the parsed data. */
 
 #define LYD_OPT_MASK            0xFFFF /**< Mask for all the parser options. */
 
@@ -696,14 +720,14 @@
 void lyd_free_tree(struct lyd_node *node);
 
 /**
- * @brief Destroy data attribute.
+ * @brief Destroy metadata.
  *
- * @param[in] ctx Context where the attribute was created.
- * @param[in] attr Attribute to destroy
- * @param[in] recursive Zero to destroy only the attribute (the attribute list is corrected),
- * non-zero to destroy also all the subsequent attributes in the list.
+ * @param[in] ctx Context where the metadata was created.
+ * @param[in] meta Metadata to destroy
+ * @param[in] recursive Zero to destroy only the metadata (the metadata list is corrected),
+ * non-zero to destroy also all the subsequent metadata in the list.
  */
-void lyd_free_attr(struct ly_ctx *ctx, struct lyd_attr *attr, int recursive);
+void lyd_free_meta(struct ly_ctx *ctx, struct lyd_meta *meta, int recursive);
 
 /**
  * @brief Check type restrictions applicable to the particular leaf/leaf-list with the given string @p value.
@@ -837,13 +861,13 @@
 const char *lyd_value2str(const struct lyd_node_term *node, int *dynamic);
 
 /**
- * @brief Get string value of an attribute \p attr.
+ * @brief Get string value of a metadata \p meta.
  *
- * @param[in] attr Attribute with the value.
+ * @param[in] meta Metadata with the value.
  * @param[out] dynamic Whether the string value was dynmically allocated.
- * @return String value of @p attr, if @p dynamic, needs to be freed.
+ * @return String value of @p meta, if @p dynamic, needs to be freed.
  */
-const char *lyd_attr2str(const struct lyd_attr *attr, int *dynamic);
+const char *lyd_meta2str(const struct lyd_meta *meta, int *dynamic);
 
 /**
  * @brief Types of the different data paths.
diff --git a/src/tree_data_free.c b/src/tree_data_free.c
index aea9f7b..7aa63ae 100644
--- a/src/tree_data_free.c
+++ b/src/tree_data_free.c
@@ -43,45 +43,45 @@
 }
 
 API void
-lyd_free_attr(struct ly_ctx *ctx, struct lyd_attr *attr, int recursive)
+lyd_free_meta(struct ly_ctx *ctx, struct lyd_meta *meta, int recursive)
 {
-    struct lyd_attr *iter;
+    struct lyd_meta *iter;
 
     LY_CHECK_ARG_RET(NULL, ctx, );
-    if (!attr) {
+    if (!meta) {
         return;
     }
 
-    if (attr->parent) {
-        if (attr->parent->attr == attr) {
+    if (meta->parent) {
+        if (meta->parent->meta == meta) {
             if (recursive) {
-                attr->parent->attr = NULL;
+                meta->parent->meta = NULL;
             } else {
-                attr->parent->attr = attr->next;
+                meta->parent->meta = meta->next;
             }
         } else {
-            for (iter = attr->parent->attr; iter->next != attr; iter = iter->next);
+            for (iter = meta->parent->meta; iter->next != meta; iter = iter->next);
             if (iter->next) {
                 if (recursive) {
                     iter->next = NULL;
                 } else {
-                    iter->next = attr->next;
+                    iter->next = meta->next;
                 }
             }
         }
     }
 
     if (!recursive) {
-        attr->next = NULL;
+        meta->next = NULL;
     }
 
-    for(iter = attr; iter; ) {
-        attr = iter;
+    for(iter = meta; iter; ) {
+        meta = iter;
         iter = iter->next;
 
-        FREE_STRING(ctx, attr->name);
-        attr->value.realtype->plugin->free(ctx, &attr->value);
-        free(attr);
+        FREE_STRING(ctx, meta->name);
+        meta->value.realtype->plugin->free(ctx, &meta->value);
+        free(meta);
     }
 }
 
@@ -129,8 +129,8 @@
         ((struct lysc_node_leaf*)node->schema)->type->plugin->free(ctx, &((struct lyd_node_term*)node)->value);
     }
 
-    /* free the node's attributes */
-    lyd_free_attr(ctx, node->attr, 1);
+    /* free the node's metadata */
+    lyd_free_meta(ctx, node->meta, 1);
 
     /* unlink only the nodes from the first level, nodes in subtree are freed all, so no unlink is needed */
     if (top) {
diff --git a/src/tree_data_helpers.c b/src/tree_data_helpers.c
index 38e0d3d..90f5736 100644
--- a/src/tree_data_helpers.c
+++ b/src/tree_data_helpers.c
@@ -124,3 +124,24 @@
 
     return mod;
 }
+
+LY_ERR
+lyd_parse_check_keys(struct lyd_node *node)
+{
+    const struct lysc_node *skey = NULL;
+    const struct lyd_node *key;
+
+    assert(node->schema->nodetype == LYS_LIST);
+
+    key = lyd_node_children(node);
+    while ((skey = lys_getnext(skey, node->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
+        if (!key || (key->schema != skey)) {
+            LOGVAL(node->schema->module->ctx, LY_VLOG_LYD, node, LY_VCODE_NOKEY, skey->name);
+            return LY_EVALID;
+        }
+
+        key = key->next;
+    }
+
+    return LY_SUCCESS;
+}
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index 4600c3e..2d92f2e 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -124,8 +124,9 @@
 
 /**
  * @brief Insert a node into parent/siblings. In case a key is being inserted into a list, the correct position
- * is found and inserted into. Also, in case we are inserting into top-level siblings, insert it as
- * the last sibling of all the module data siblings. Otherwise it is inserted at the very last place.
+ * is found, inserted into, and if it is the last key, parent list hash is calculated. Also, in case we are inserting
+ * into top-level siblings, insert it as the last sibling of all the module data siblings. Otherwise it is inserted at
+ * the very last place.
  *
  * @param[in] parent Parent to insert into, NULL for top-level sibling.
  * @param[in,out] first_sibling First sibling, NULL if no top-level sibling exist yet. Can be also NULL if @p parent is set.
@@ -137,8 +138,8 @@
  * @brief Create and insert an attribute (last) into a parent.
  *
  * @param[in] parent Parent of the attribute, can be NULL.
- * @param[in,out] attr Attribute list to add at its end if @p parent is NULL, returned created attribute.
- * @param[in] mod Attribute module (with the annotation definition).
+ * @param[in,out] meta Metadata list to add at its end if @p parent is NULL, returned created attribute.
+ * @param[in] mod Metadata module (with the annotation definition).
  * @param[in] name Attribute name.
  * @param[in] name_len Length of @p name, must be set correctly.
  * @param[in] value String value to be parsed.
@@ -152,7 +153,7 @@
  * @return LY_EINCOMPLETE in case data tree is needed to finish the validation.
  * @return LY_ERR value if an error occurred.
  */
-LY_ERR lyd_create_attr(struct lyd_node *parent, struct lyd_attr **attr, const struct lys_module *mod, const char *name,
+LY_ERR lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, 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, const struct lysc_node *ctx_snode);
 
@@ -178,10 +179,10 @@
                        ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node *tree);
 
 /**
- * @brief Validate, canonize and store the given @p value into the attribute according to the metadata annotation type's rules.
+ * @brief Validate, canonize and store the given @p value into the metadata according to the annotation type's rules.
  *
  * @param[in] ctx libyang context.
- * @param[in] attr Data attribute for the @p value.
+ * @param[in] meta Metadata for the @p value.
  * @param[in] value String value to be parsed, must not be NULL.
  * @param[in] value_len Length of the give @p value, must be set correctly.
  * @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
@@ -197,7 +198,7 @@
  * @return LY_EINCOMPLETE in case the @p trees is not provided and it was needed to finish the validation.
  * @return LY_ERR value if an error occurred.
  */
-LY_ERR lyd_value_parse_attr(struct ly_ctx *ctx, struct lyd_attr *attr, const char *value, size_t value_len, int *dynamic,
+LY_ERR lyd_value_parse_meta(struct ly_ctx *ctx, struct lyd_meta *meta, const char *value, size_t value_len, int *dynamic,
                             int second, ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
                             const struct lysc_node *ctx_snode, const struct lyd_node *tree);
 
@@ -205,12 +206,31 @@
  * @brief Parse XML string as YANG data tree.
  *
  * @param[in] ctx libyang context
- * @param[in] data Pointer to the XML string representation of the YANG data to parse.
+ * @param[in] data Pointer to the XML data to parse.
  * @param[in] options @ref dataparseroptions
  * @param[out] tree Parsed data tree. Note that NULL can be a valid result.
- * @reutn LY_ERR value.
+ * @return LY_ERR value.
  */
-LY_ERR lyd_parse_xml(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **tree);
+LY_ERR lyd_parse_xml_data(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **tree);
+
+/**
+ * @brief Parse XML string as YANG RPC/action invocation.
+ *
+ * Optional \<rpc\> envelope element, if present, is [checked](https://tools.ietf.org/html/rfc6241#section-4.1) and all
+ * its XML attributes returned. In that case an RPC is expected to be parsed.
+ *
+ * Can be followed by optional \<action\> envelope element, which is also
+ * [checked](https://tools.ietf.org/html/rfc7950#section-7.15.2) and then an action is expected to be parsed.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] data Pointer to the XML data to parse.
+ * @param[out] tree Parsed RPC/action data tree.
+ * @param[out] attr Any found attributes on the rpc envelope.
+ * @param[out] op Pointer to the actual operation. Useful mainly for action.
+ * @return LY_ERR value.
+ */
+LY_ERR lyd_parse_xml_rpc(struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct ly_attr **attr,
+                         struct lyd_node **op);
 
 /**
  * @defgroup datahash Data nodes hash manipulation
@@ -310,4 +330,12 @@
  */
 const struct lys_module *lyd_data_next_module(struct lyd_node **next, struct lyd_node **first);
 
+/**
+ * @brief Check that a list has all its keys.
+ *
+ * @param[in] node List to check.
+ * @return LY_ERR value.
+ */
+LY_ERR lyd_parse_check_keys(struct lyd_node *node);
+
 #endif /* LY_TREE_DATA_INTERNAL_H_ */
diff --git a/src/validation.c b/src/validation.c
index 5aee11f..b8168dd 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -125,7 +125,7 @@
 }
 
 LY_ERR
-lyd_validate_unres(struct lyd_node **tree, struct ly_set *node_when, struct ly_set *node_types, struct ly_set *attr_types,
+lyd_validate_unres(struct lyd_node **tree, struct ly_set *node_when, struct ly_set *node_types, struct ly_set *meta_types,
                    LYD_FORMAT format, ly_clb_resolve_prefix get_prefix_clb, void *parser_data)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -196,21 +196,21 @@
         } while (u);
     }
 
-    if (attr_types && attr_types->count) {
-        /* ... and attribute values */
-        u = attr_types->count;
+    if (meta_types && meta_types->count) {
+        /* ... and metadata values */
+        u = meta_types->count;
         do {
             --u;
 
-            struct lyd_attr *attr = (struct lyd_attr *)attr_types->objs[u];
+            struct lyd_meta *meta = (struct lyd_meta *)meta_types->objs[u];
 
-            /* validate and store the value of the node */
-            ret = lyd_value_parse_attr(attr->parent->schema->module->ctx, attr, attr->value.original,
-                                    strlen(attr->value.original), 0, 1, get_prefix_clb, parser_data, format, NULL, *tree);
+            /* validate and store the value of the metadata */
+            ret = lyd_value_parse_meta(meta->parent->schema->module->ctx, meta, meta->value.original,
+                                       strlen(meta->value.original), 0, 1, get_prefix_clb, parser_data, format, NULL, *tree);
             LY_CHECK_RET(ret);
 
             /* remove this attr from the set */
-            ly_set_rm_index(attr_types, u, NULL);
+            ly_set_rm_index(meta_types, u, NULL);
         } while (u);
     }
 
@@ -948,8 +948,8 @@
     LY_ERR ret = LY_SUCCESS;
     struct lyd_node *first, *next, *node, **first2;
     const struct lys_module *mod;
-    const struct lyd_attr *attr;
-    struct ly_set type_check = {0}, type_attr_check = {0}, when_check = {0};
+    const struct lyd_meta *meta;
+    struct ly_set type_check = {0}, type_meta_check = {0}, when_check = {0};
     uint32_t i = 0;
 
     LY_CHECK_ARG_RET(NULL, tree, *tree || ctx || (modules && mod_count), LY_EINVAL);
@@ -989,9 +989,9 @@
             LYD_TREE_DFS_BEGIN(first, next, node) {
                 /* skip added default nodes */
                 if ((node->flags & (LYD_DEFAULT | LYD_NEW)) != (LYD_DEFAULT | LYD_NEW)) {
-                    LY_LIST_FOR(node->attr, attr) {
-                        /* attribute type resolution */
-                        ly_set_add(&type_attr_check, (void *)attr, LY_SET_OPT_USEASLIST);
+                    LY_LIST_FOR(node->meta, meta) {
+                        /* metadata type resolution */
+                        ly_set_add(&type_meta_check, (void *)meta, LY_SET_OPT_USEASLIST);
                     }
 
                     if (node->schema->nodetype & LYD_NODE_TERM) {
@@ -1019,7 +1019,7 @@
         }
 
         /* finish incompletely validated terminal values/attributes and when conditions */
-        ret = lyd_validate_unres(tree, &when_check, &type_check, &type_attr_check, LYD_JSON, lydjson_resolve_prefix, NULL);
+        ret = lyd_validate_unres(tree, &when_check, &type_check, &type_meta_check, LYD_JSON, lydjson_resolve_prefix, NULL);
         LY_CHECK_GOTO(ret, cleanup);
 
         /* perform final validation that assumes the data tree is final */
@@ -1029,7 +1029,7 @@
 
 cleanup:
     ly_set_erase(&type_check, NULL);
-    ly_set_erase(&type_attr_check, NULL);
+    ly_set_erase(&type_meta_check, NULL);
     ly_set_erase(&when_check, NULL);
     return ret;
 }
diff --git a/src/validation.h b/src/validation.h
index a99a1e5..a84999e 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -26,13 +26,13 @@
  * @param[in,out] tree Data tree, is updated if some nodes are autodeleted.
  * @param[in] node_when Set with nodes with "when" conditions, can be NULL.
  * @param[in] node_types Set with nodes with unresolved types, can be NULL
- * @param[in] attr_types Set with attributes with unresolved types, can be NULL.
+ * @param[in] meta_types Set with metdata with unresolved types, can be NULL.
  * @param[in] format Format of the unresolved data.
  * @param[in] get_prefix_clb Format-specific getter to resolve prefixes.
  * @param[in] parser_data Parser's data for @p get_prefix_clb.
  * @return LY_ERR value.
  */
-LY_ERR lyd_validate_unres(struct lyd_node **tree, struct ly_set *node_when, struct ly_set *node_types, struct ly_set *attr_types,
+LY_ERR lyd_validate_unres(struct lyd_node **tree, struct ly_set *node_when, struct ly_set *node_types, struct ly_set *meta_types,
                           LYD_FORMAT format, ly_clb_resolve_prefix get_prefix_clb, void *parser_data);
 
 /**
diff --git a/src/xpath.c b/src/xpath.c
index 7a5f430..f9a8009 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -214,9 +214,9 @@
                     }
                 }
                 break;
-            case LYXP_NODE_ATTR:
-                LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ATTR %s = %s", i + 1, item->pos, set->val.attrs[i].attr->name,
-                       set->val.attrs[i].attr->value);
+            case LYXP_NODE_META:
+                LOGDBG(LY_LDGXPATH, "\t%d (pos %u): META %s = %s", i + 1, item->pos, set->val.meta[i].meta->name,
+                       set->val.meta[i].meta->value);
                 break;
             }
         }
@@ -515,8 +515,8 @@
     case LYXP_NODE_ELEM:
     case LYXP_NODE_TEXT:
         return cast_string_elem(set->val.nodes[0].node, 0, set->root_type, str);
-    case LYXP_NODE_ATTR:
-        *str = (char *)lyd_attr2str(set->val.attrs[0].attr, &dynamic);
+    case LYXP_NODE_META:
+        *str = (char *)lyd_meta2str(set->val.meta[0].meta, &dynamic);
         if (!dynamic) {
             *str = strdup(*str);
             if (!*str) {
@@ -1397,8 +1397,8 @@
         if (!set->val.nodes[i].pos) {
             tmp_node = NULL;
             switch (set->val.nodes[i].type) {
-            case LYXP_NODE_ATTR:
-                tmp_node = set->val.attrs[i].attr->parent;
+            case LYXP_NODE_META:
+                tmp_node = set->val.meta[i].meta->parent;
                 if (!tmp_node) {
                     LOGINT_RET(root->schema->module->ctx);
                 }
@@ -1421,22 +1421,22 @@
 }
 
 /**
- * @brief Get unique @p attr position in the parent attributes.
+ * @brief Get unique @p meta position in the parent metadata.
  *
- * @param[in] attr Attr to use.
- * @return Attribute position.
+ * @param[in] meta Metadata to use.
+ * @return Metadata position.
  */
 static uint16_t
-get_attr_pos(struct lyd_attr *attr)
+get_meta_pos(struct lyd_meta *meta)
 {
     uint16_t pos = 0;
-    struct lyd_attr *attr2;
+    struct lyd_meta *meta2;
 
-    for (attr2 = attr->parent->attr; attr2 && (attr2 != attr); attr2 = attr2->next) {
+    for (meta2 = meta->parent->meta; meta2 && (meta2 != meta); meta2 = meta2->next) {
         ++pos;
     }
 
-    assert(attr2);
+    assert(meta2);
     return pos;
 }
 
@@ -1450,7 +1450,7 @@
 static int
 set_sort_compare(struct lyxp_set_node *item1, struct lyxp_set_node *item2)
 {
-    uint32_t attr_pos1 = 0, attr_pos2 = 0;
+    uint32_t meta_pos1 = 0, meta_pos2 = 0;
 
     if (item1->pos < item2->pos) {
         return -1;
@@ -1474,39 +1474,39 @@
         }
     }
 
-    /* we need attr positions now */
-    if (item1->type == LYXP_NODE_ATTR) {
-        attr_pos1 = get_attr_pos((struct lyd_attr *)item1->node);
+    /* we need meta positions now */
+    if (item1->type == LYXP_NODE_META) {
+        meta_pos1 = get_meta_pos((struct lyd_meta *)item1->node);
     }
-    if (item2->type == LYXP_NODE_ATTR) {
-        attr_pos2 = get_attr_pos((struct lyd_attr *)item2->node);
+    if (item2->type == LYXP_NODE_META) {
+        meta_pos2 = get_meta_pos((struct lyd_meta *)item2->node);
     }
 
-    /* 1st ROOT - 2nd ROOT, 1st ELEM - 2nd ELEM, 1st TEXT - 2nd TEXT, 1st ATTR - =pos= - 2nd ATTR */
+    /* 1st ROOT - 2nd ROOT, 1st ELEM - 2nd ELEM, 1st TEXT - 2nd TEXT, 1st META - =pos= - 2nd META */
     /* check for duplicates */
     if (item1->node == item2->node) {
-        assert((item1->type == item2->type) && ((item1->type != LYXP_NODE_ATTR) || (attr_pos1 == attr_pos2)));
+        assert((item1->type == item2->type) && ((item1->type != LYXP_NODE_META) || (meta_pos1 == meta_pos2)));
         return 0;
     }
 
-    /* 1st ELEM - 2nd TEXT, 1st ELEM - any pos - 2nd ATTR */
+    /* 1st ELEM - 2nd TEXT, 1st ELEM - any pos - 2nd META */
     /* elem is always first, 2nd node is after it */
     if (item1->type == LYXP_NODE_ELEM) {
         assert(item2->type != LYXP_NODE_ELEM);
         return -1;
     }
 
-    /* 1st TEXT - 2nd ELEM, 1st TEXT - any pos - 2nd ATTR, 1st ATTR - any pos - 2nd ELEM, 1st ATTR - >pos> - 2nd ATTR */
+    /* 1st TEXT - 2nd ELEM, 1st TEXT - any pos - 2nd META, 1st META - any pos - 2nd ELEM, 1st META - >pos> - 2nd META */
     /* 2nd is before 1st */
     if (((item1->type == LYXP_NODE_TEXT)
-            && ((item2->type == LYXP_NODE_ELEM) || (item2->type == LYXP_NODE_ATTR)))
-            || ((item1->type == LYXP_NODE_ATTR) && (item2->type == LYXP_NODE_ELEM))
-            || (((item1->type == LYXP_NODE_ATTR) && (item2->type == LYXP_NODE_ATTR))
-            && (attr_pos1 > attr_pos2))) {
+            && ((item2->type == LYXP_NODE_ELEM) || (item2->type == LYXP_NODE_META)))
+            || ((item1->type == LYXP_NODE_META) && (item2->type == LYXP_NODE_ELEM))
+            || (((item1->type == LYXP_NODE_META) && (item2->type == LYXP_NODE_META))
+            && (meta_pos1 > meta_pos2))) {
         return 1;
     }
 
-    /* 1st ATTR - any pos - 2nd TEXT, 1st ATTR <pos< - 2nd ATTR */
+    /* 1st META - any pos - 2nd TEXT, 1st META <pos< - 2nd META */
     /* 2nd is after 1st */
     return -1;
 }
@@ -3867,7 +3867,7 @@
 {
     const struct lyd_node *node;
     struct lysc_node_leaf *sleaf;
-    struct lyd_attr *attr = NULL;
+    struct lyd_meta *meta = NULL;
     const char *val;
     int i, dynamic;
     LY_ERR rc = LY_SUCCESS;
@@ -3901,8 +3901,8 @@
     case LYXP_NODE_TEXT:
         node = set->val.nodes[0].node;
         break;
-    case LYXP_NODE_ATTR:
-        node = set->val.attrs[0].attr->parent;
+    case LYXP_NODE_META:
+        node = set->val.meta[0].meta->parent;
         break;
     default:
         /* nothing to do with roots */
@@ -3910,25 +3910,25 @@
         return LY_SUCCESS;
     }
 
-    /* find lang attribute */
+    /* find lang metadata */
     for (; node; node = (struct lyd_node *)node->parent) {
-        for (attr = node->attr; attr; attr = attr->next) {
+        for (meta = node->meta; meta; meta = meta->next) {
             /* annotations */
-            if (attr->name && !strcmp(attr->name, "lang") && !strcmp(attr->annotation->module->name, "xml")) {
+            if (meta->name && !strcmp(meta->name, "lang") && !strcmp(meta->annotation->module->name, "xml")) {
                 break;
             }
         }
 
-        if (attr) {
+        if (meta) {
             break;
         }
     }
 
     /* compare languages */
-    if (!attr) {
+    if (!meta) {
         set_fill_boolean(set, 0);
     } else {
-        val = lyd_attr2str(attr, &dynamic);
+        val = lyd_meta2str(meta, &dynamic);
         for (i = 0; args[0]->val.str[i]; ++i) {
             if (tolower(args[0]->val.str[i]) != tolower(val[i])) {
                 set_fill_boolean(set, 0);
@@ -4044,8 +4044,8 @@
     case LYXP_NODE_ELEM:
         set_fill_string(set, item->node->schema->name, strlen(item->node->schema->name));
         break;
-    case LYXP_NODE_ATTR:
-        set_fill_string(set, ((struct lyd_attr *)item->node)->name, strlen(((struct lyd_attr *)item->node)->name));
+    case LYXP_NODE_META:
+        set_fill_string(set, ((struct lyd_meta *)item->node)->name, strlen(((struct lyd_meta *)item->node)->name));
         break;
     }
 
@@ -4119,9 +4119,9 @@
         mod = item->node->schema->module;
         name = item->node->schema->name;
         break;
-    case LYXP_NODE_ATTR:
-        mod = ((struct lyd_attr *)item->node)->annotation->module;
-        name = ((struct lyd_attr *)item->node)->name;
+    case LYXP_NODE_META:
+        mod = ((struct lyd_meta *)item->node)->annotation->module;
+        name = ((struct lyd_meta *)item->node)->name;
         break;
     }
 
@@ -4208,12 +4208,12 @@
         set_fill_string(set, "", 0);
         break;
     case LYXP_NODE_ELEM:
-    case LYXP_NODE_ATTR:
+    case LYXP_NODE_META:
         if (item->type == LYXP_NODE_ELEM) {
             mod = item->node->schema->module;
-        } else { /* LYXP_NODE_ATTR */
+        } else { /* LYXP_NODE_META */
             /* annotations */
-            mod = ((struct lyd_attr *)item->node)->annotation->module;
+            mod = ((struct lyd_meta *)item->node)->annotation->module;
         }
 
         set_fill_string(set, mod->ns, strlen(mod->ns));
@@ -5001,7 +5001,7 @@
         case LYXP_NODE_ROOT:
         case LYXP_NODE_ROOT_CONFIG:
         case LYXP_NODE_TEXT:
-        case LYXP_NODE_ATTR:
+        case LYXP_NODE_META:
             set_remove_node(set, i);
             break;
         }
@@ -5551,7 +5551,7 @@
     rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
     LY_CHECK_RET(rc);
 
-    /* replace the original nodes (and throws away all text and attr nodes, root is replaced by a child) */
+    /* replace the original nodes (and throws away all text and meta nodes, root is replaced by a child) */
     rc = moveto_node(set, "*", 1);
     LY_CHECK_RET(rc);
 
@@ -5735,7 +5735,7 @@
     uint32_t i;
     int replaced, all = 0;
     const struct lys_module *moveto_mod;
-    struct lyd_attr *sub;
+    struct lyd_meta *sub;
     LY_ERR rc;
 
     if (!set || (set->type == LYXP_SET_EMPTY)) {
@@ -5760,7 +5760,7 @@
         /* only attributes of an elem (not dummy) can be in the result, skip all the rest;
          * our attributes are always qualified */
         if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
-            for (sub = set->val.nodes[i].node->attr; sub; sub = sub->next) {
+            for (sub = set->val.nodes[i].node->meta; sub; sub = sub->next) {
 
                 /* check "namespace" */
                 if (moveto_mod && (sub->annotation->module != moveto_mod)) {
@@ -5770,12 +5770,12 @@
                 if (all || (!strncmp(sub->name, qname, qname_len) && !sub->name[qname_len])) {
                     /* match */
                     if (!replaced) {
-                        set->val.attrs[i].attr = sub;
-                        set->val.attrs[i].type = LYXP_NODE_ATTR;
+                        set->val.meta[i].meta = sub;
+                        set->val.meta[i].type = LYXP_NODE_META;
                         /* pos does not change */
                         replaced = 1;
                     } else {
-                        set_insert_node(set, (struct lyd_node *)sub, set->val.nodes[i].pos, LYXP_NODE_ATTR, i + 1);
+                        set_insert_node(set, (struct lyd_node *)sub, set->val.nodes[i].pos, LYXP_NODE_META, i + 1);
                     }
                     ++i;
                 }
@@ -5850,7 +5850,7 @@
 {
     uint32_t i;
     int replaced, all = 0;
-    struct lyd_attr *sub;
+    struct lyd_meta *sub;
     const struct lys_module *moveto_mod;
     struct lyxp_set *set_all_desc = NULL;
     LY_ERR rc;
@@ -5895,7 +5895,7 @@
         /* only attributes of an elem can be in the result, skip all the rest,
          * we have all attributes qualified in lyd tree */
         if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
-            for (sub = set->val.nodes[i].node->attr; sub; sub = sub->next) {
+            for (sub = set->val.nodes[i].node->meta; sub; sub = sub->next) {
                 /* check "namespace" */
                 if (moveto_mod && (sub->annotation->module != moveto_mod)) {
                     continue;
@@ -5904,12 +5904,12 @@
                 if (all || (!strncmp(sub->name, qname, qname_len) && !sub->name[qname_len])) {
                     /* match */
                     if (!replaced) {
-                        set->val.attrs[i].attr = sub;
-                        set->val.attrs[i].type = LYXP_NODE_ATTR;
+                        set->val.meta[i].meta = sub;
+                        set->val.meta[i].type = LYXP_NODE_META;
                         /* pos does not change */
                         replaced = 1;
                     } else {
-                        set_insert_node(set, (struct lyd_node *)sub, set->val.attrs[i].pos, LYXP_NODE_ATTR, i + 1);
+                        set_insert_node(set, (struct lyd_node *)sub, set->val.meta[i].pos, LYXP_NODE_META, i + 1);
                     }
                     ++i;
                 }
@@ -6038,7 +6038,7 @@
         set_insert_node(&ret_set, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, ret_set.used);
 
         /* do not touch attributes and text nodes */
-        if ((set->val.nodes[i].type == LYXP_NODE_TEXT) || (set->val.nodes[i].type == LYXP_NODE_ATTR)) {
+        if ((set->val.nodes[i].type == LYXP_NODE_TEXT) || (set->val.nodes[i].type == LYXP_NODE_META)) {
             continue;
         }
 
@@ -6173,8 +6173,8 @@
             new_node = (struct lyd_node *)node->parent;
         } else if (set->val.nodes[i].type == LYXP_NODE_TEXT) {
             new_node = node;
-        } else if (set->val.nodes[i].type == LYXP_NODE_ATTR) {
-            new_node = set->val.attrs[i].attr->parent;
+        } else if (set->val.nodes[i].type == LYXP_NODE_META) {
+            new_node = set->val.meta[i].meta->parent;
             if (!new_node) {
                 LOGINT_RET(set->ctx);
             }
diff --git a/src/xpath.h b/src/xpath.h
index d645920..117ca36 100644
--- a/src/xpath.h
+++ b/src/xpath.h
@@ -134,9 +134,9 @@
     LYXP_NODE_ROOT_CONFIG,      /* <running> data context, no state data (node value first top-level node) */
 
     /* XML elements */
-    LYXP_NODE_ELEM,             /* XML element (most common) */
-    LYXP_NODE_TEXT,             /* XML text element (extremely specific use, unlikely to be ever needed) */
-    LYXP_NODE_ATTR              /* XML attribute (in YANG cannot happen, do not use for the context node) */
+    LYXP_NODE_ELEM,             /* YANG data element (most common) */
+    LYXP_NODE_TEXT,             /* YANG data text element (extremely specific use, unlikely to be ever needed) */
+    LYXP_NODE_META              /* YANG metadata (do not use for the context node) */
 };
 
 /**
@@ -224,11 +224,11 @@
              * >=3 - scnode is not in context because we are in a predicate and this scnode was used/will be used later */
             int32_t in_ctx;
         } *scnodes;
-        struct lyxp_set_attr {
-            struct lyd_attr *attr;
+        struct lyxp_set_meta {
+            struct lyd_meta *meta;
             enum lyxp_node_type type;
-            uint32_t pos; /* if node_type is LYXP_SET_NODE_ATTR, it is the parent node position */
-        } *attrs;
+            uint32_t pos; /* if node_type is LYXP_SET_NODE_META, it is the parent node position */
+        } *meta;
         char *str;
         long double num;
         int bool;
diff --git a/tests/src/test_parser_xml.c b/tests/src/test_parser_xml.c
index dcf6970..b5c3f4c 100644
--- a/tests/src/test_parser_xml.c
+++ b/tests/src/test_parser_xml.c
@@ -114,7 +114,7 @@
     struct lyd_node *tree;
     struct lyd_node_term *leaf;
 
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("foo", tree->schema->name);
@@ -131,7 +131,7 @@
 
     /* make foo2 explicit */
     data = "<foo2 xmlns=\"urn:tests:a\">default-val</foo2>";
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("foo2", tree->schema->name);
@@ -143,7 +143,7 @@
 
     /* parse foo2 but make it implicit */
     data = "<foo2 xmlns=\"urn:tests:a\" xmlns:wd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" wd:default=\"true\">default-val</foo2>";
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     assert_int_equal(LYS_LEAF, tree->schema->nodetype);
     assert_string_equal("foo2", tree->schema->name);
@@ -167,7 +167,7 @@
     struct lyd_node *tree;
     struct lyd_node_any *any;
 
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     assert_int_equal(LYS_ANYDATA, tree->schema->nodetype);
     assert_string_equal("any", tree->schema->name);
@@ -190,7 +190,7 @@
     struct lyd_node_term *leaf;
 
     /* check hashes */
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     assert_int_equal(LYS_LIST, tree->schema->nodetype);
     assert_string_equal("l1", tree->schema->name);
@@ -200,9 +200,27 @@
     }
     lyd_free_all(tree);
 
+    /* missing keys */
+    data = "<l1 xmlns=\"urn:tests:a\"><c>c</c><b>b</b></l1>";
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    logbuf_assert("List instance is missing its key \"a\". /a:l1[b='b'][c='c']");
+
+    data = "<l1 xmlns=\"urn:tests:a\"><a>a</a></l1>";
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    logbuf_assert("List instance is missing its key \"b\". /a:l1[a='a']");
+
+    data = "<l1 xmlns=\"urn:tests:a\"><b>b</b><a>a</a></l1>";
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    logbuf_assert("List instance is missing its key \"c\". /a:l1[a='a'][b='b']");
+
+    /* key duplicate */
+    data = "<l1 xmlns=\"urn:tests:a\"><c>c</c><b>b</b><a>a</a><c>d</c></l1>";
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    logbuf_assert("Duplicate instance of \"c\". /a:l1[a='a'][b='b'][c='d'][c='c']/c");
+
     /* keys order */
     data = "<l1 xmlns=\"urn:tests:a\"><d>d</d><a>a</a><c>c</c><b>b</b></l1>";
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     assert_int_equal(LYS_LIST, tree->schema->nodetype);
     assert_string_equal("l1", tree->schema->name);
@@ -219,7 +237,7 @@
     lyd_free_all(tree);
 
     data = "<l1 xmlns=\"urn:tests:a\"><c>c</c><b>b</b><a>a</a></l1>";
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     assert_int_equal(LYS_LIST, tree->schema->nodetype);
     assert_string_equal("l1", tree->schema->name);
@@ -234,7 +252,7 @@
     logbuf_clean();
     lyd_free_all(tree);
 
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_OPT_STRICT, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_OPT_STRICT, &tree));
     logbuf_assert("Invalid position of the key \"b\" in a list. Line number 1.");
 
     *state = NULL;
@@ -249,7 +267,7 @@
     struct lyd_node *tree;
     struct lyd_node_inner *cont;
 
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     assert_int_equal(LYS_CONTAINER, tree->schema->nodetype);
     assert_string_equal("c", tree->schema->name);
@@ -258,7 +276,7 @@
     lyd_free_all(tree);
 
     data = "<cp xmlns=\"urn:tests:a\"/>";
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     assert_int_equal(LYS_CONTAINER, tree->schema->nodetype);
     assert_string_equal("cp", tree->schema->name);
diff --git a/tests/src/test_validation.c b/tests/src/test_validation.c
index 4d4c614..d81ea74 100644
--- a/tests/src/test_validation.c
+++ b/tests/src/test_validation.c
@@ -221,6 +221,12 @@
                 "leaf-list ll {"
                     "type string;"
                 "}"
+                "leaf-list ll2 {"
+                    "type enumeration {"
+                        "enum one;"
+                        "enum two;"
+                    "}"
+                "}"
             "}"
         "}";
     const char *schema_f =
@@ -402,19 +408,19 @@
     struct lyd_node *tree;
 
     data = "<c xmlns=\"urn:tests:a\">hey</c>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("When condition \"/cont/b = 'val_b'\" not satisfied. /a:c");
 
     data = "<cont xmlns=\"urn:tests:a\"><b>val_b</b></cont><c xmlns=\"urn:tests:a\">hey</c>";
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     assert_string_equal("c", tree->next->schema->name);
     assert_int_equal(LYD_WHEN_TRUE, tree->next->flags);
     lyd_free_all(tree);
 
     data = "<cont xmlns=\"urn:tests:a\"><a>val</a><b>val_b</b></cont><c xmlns=\"urn:tests:a\">val_c</c>";
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     assert_string_equal("a", lyd_node_children(tree)->schema->name);
     assert_int_equal(LYD_WHEN_TRUE, lyd_node_children(tree)->flags);
@@ -434,22 +440,22 @@
     struct lyd_node *tree;
 
     data = "<d xmlns=\"urn:tests:b\"/>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Mandatory node \"choic\" instance does not exist. /b:choic");
 
     data = "<l xmlns=\"urn:tests:b\">string</l><d xmlns=\"urn:tests:b\"/>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Mandatory node \"c\" instance does not exist. /b:c");
 
     data = "<a xmlns=\"urn:tests:b\">string</a>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Mandatory node \"c\" instance does not exist. /b:c");
 
     data = "<a xmlns=\"urn:tests:b\">string</a><c xmlns=\"urn:tests:b\">string2</c>";
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     lyd_free_siblings(tree);
 
@@ -465,14 +471,14 @@
     struct lyd_node *tree;
 
     data = "<d xmlns=\"urn:tests:c\"/>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Too few \"l\" instances. /c:choic/b/l");
 
     data =
     "<l xmlns=\"urn:tests:c\">val1</l>"
     "<l xmlns=\"urn:tests:c\">val2</l>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Too few \"l\" instances. /c:choic/b/l");
 
@@ -480,7 +486,7 @@
     "<l xmlns=\"urn:tests:c\">val1</l>"
     "<l xmlns=\"urn:tests:c\">val2</l>"
     "<l xmlns=\"urn:tests:c\">val3</l>";
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     lyd_free_siblings(tree);
 
@@ -493,7 +499,7 @@
     "<lt xmlns=\"urn:tests:c\"><k>val3</k></lt>"
     "<lt xmlns=\"urn:tests:c\"><k>val4</k></lt>"
     "<lt xmlns=\"urn:tests:c\"><k>val5</k></lt>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Too many \"lt\" instances. /c:lt");
 
@@ -516,7 +522,7 @@
     "<lt xmlns=\"urn:tests:d\">"
         "<k>val2</k>"
     "</lt>";
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     lyd_free_siblings(tree);
 
@@ -529,7 +535,7 @@
         "<k>val2</k>"
         "<l1>not-same</l1>"
     "</lt>";
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     lyd_free_siblings(tree);
 
@@ -542,7 +548,7 @@
         "<k>val2</k>"
         "<l1>same</l1>"
     "</lt>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Unique data leaf(s) \"l1\" not satisfied in \"/d:lt[k='val1']\" and \"/d:lt[k='val2']\". /d:lt[k='val2']");
 
@@ -580,7 +586,7 @@
         "<k>val8</k>"
         "<l1>8</l1>"
     "</lt>";
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     lyd_free_siblings(tree);
 
@@ -614,7 +620,7 @@
     "<lt xmlns=\"urn:tests:d\">"
         "<k>val8</k>"
     "</lt>";
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     lyd_free_siblings(tree);
 
@@ -648,7 +654,7 @@
         "<k>val8</k>"
         "<l1>8</l1>"
     "</lt>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Unique data leaf(s) \"l1\" not satisfied in \"/d:lt[k='val7']\" and \"/d:lt[k='val2']\". /d:lt[k='val2']");
 
@@ -720,7 +726,7 @@
             "<l3>3</l3>"
         "</lt3>"
     "</lt2>";
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY | LYD_OPT_STRICT, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY | LYD_OPT_STRICT, &tree));
     assert_non_null(tree);
     lyd_free_siblings(tree);
 
@@ -781,7 +787,7 @@
             "<l3>3</l3>"
         "</lt3>"
     "</lt2>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Unique data leaf(s) \"l3\" not satisfied in \"/d:lt2[k='val2']/lt3[kk='val3']\" and"
                   " \"/d:lt2[k='val2']/lt3[kk='val1']\". /d:lt2[k='val2']/lt3[kk='val1']");
@@ -822,7 +828,7 @@
         "</cont>"
         "<l4>5</l4>"
     "</lt2>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Unique data leaf(s) \"cont/l2 l4\" not satisfied in \"/d:lt2[k='val4']\" and \"/d:lt2[k='val2']\". /d:lt2[k='val2']");
 
@@ -870,7 +876,7 @@
         "<l5>3</l5>"
         "<l6>3</l6>"
     "</lt2>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Unique data leaf(s) \"l5 l6\" not satisfied in \"/d:lt2[k='val5']\" and \"/d:lt2[k='val3']\". /d:lt2[k='val3']");
 
@@ -886,51 +892,51 @@
     struct lyd_node *tree;
 
     data = "<d xmlns=\"urn:tests:e\">25</d><d xmlns=\"urn:tests:e\">50</d>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Duplicate instance of \"d\". /e:d");
 
     data = "<lt xmlns=\"urn:tests:e\"><k>A</k></lt><lt xmlns=\"urn:tests:e\"><k>B</k></lt><lt xmlns=\"urn:tests:e\"><k>A</k></lt>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Duplicate instance of \"lt\". /e:lt[k='A']");
 
     data = "<ll xmlns=\"urn:tests:e\">A</ll><ll xmlns=\"urn:tests:e\">B</ll><ll xmlns=\"urn:tests:e\">B</ll>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Duplicate instance of \"ll\". /e:ll[.='B']");
 
     data = "<cont xmlns=\"urn:tests:e\"></cont><cont xmlns=\"urn:tests:e\"/>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Duplicate instance of \"cont\". /e:cont");
 
     /* same tests again but using hashes */
     data = "<cont xmlns=\"urn:tests:e\"><d>25</d><d>50</d><ll>1</ll><ll>2</ll><ll>3</ll><ll>4</ll></cont>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Duplicate instance of \"d\". /e:cont/d");
 
     data = "<cont xmlns=\"urn:tests:e\"><ll>1</ll><ll>2</ll><ll>3</ll><ll>4</ll>"
         "<lt><k>a</k></lt><lt><k>b</k></lt><lt><k>c</k></lt><lt><k>d</k></lt><lt><k>c</k></lt></cont>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Duplicate instance of \"lt\". /e:cont/lt[k='c']");
 
     data = "<cont xmlns=\"urn:tests:e\"><ll>1</ll><ll>2</ll><ll>3</ll><ll>4</ll>"
         "<ll>a</ll><ll>b</ll><ll>c</ll><ll>d</ll><ll>d</ll></cont>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Duplicate instance of \"ll\". /e:cont/ll[.='d']");
 
     /* cases */
     data = "<l xmlns=\"urn:tests:e\">a</l><l xmlns=\"urn:tests:e\">b</l><l xmlns=\"urn:tests:e\">c</l><l xmlns=\"urn:tests:e\">b</l>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Duplicate instance of \"l\". /e:l[.='b']");
 
     data = "<l xmlns=\"urn:tests:e\">a</l><l xmlns=\"urn:tests:e\">b</l><l xmlns=\"urn:tests:e\">c</l><a xmlns=\"urn:tests:e\">aa</a>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Data for both cases \"a\" and \"b\" exist. /e:choic");
 
@@ -1106,7 +1112,7 @@
     "<cont xmlns=\"urn:tests:g\">"
         "<d>51</d>"
     "</cont>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Data are disabled by \"cont\" schema node if-feature. /g:cont");
 
@@ -1125,7 +1131,7 @@
             "<e>val</e>"
         "</cont2>"
     "</cont>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Data are disabled by \"cont2\" schema node if-feature. /g:cont/cont2");
 
@@ -1133,14 +1139,14 @@
     "<cont xmlns=\"urn:tests:g\">"
         "<a>val</a>"
     "</cont>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Data are disabled by \"choic\" schema node if-feature. /g:cont/a");
 
     /* enable f3 */
     assert_int_equal(lys_feature_enable(mod, "f3"), LY_SUCCESS);
 
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     lyd_free_siblings(tree);
 
@@ -1149,14 +1155,14 @@
     "<cont xmlns=\"urn:tests:g\">"
         "<l>val</l>"
     "</cont>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_null(tree);
     logbuf_assert("Data are disabled by \"b\" schema node if-feature. /g:cont/l");
 
     /* enable f2 */
     assert_int_equal(lys_feature_enable(mod, "f2"), LY_SUCCESS);
 
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY, &tree));
     assert_non_null(tree);
     lyd_free_siblings(tree);
 
@@ -1173,7 +1179,7 @@
             "<e>val</e>"
         "</cont2>"
     "</cont>";
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_OPT_PARSE_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_OPT_PARSE_ONLY, &tree));
     assert_non_null(tree);
 
     assert_int_equal(LY_EVALID, lyd_validate(&tree, NULL, LYD_VALOPT_DATA_ONLY));
@@ -1207,15 +1213,15 @@
             "<l>val</l>"
         "</cont2>"
     "</cont>";
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_OPT_PARSE_ONLY | LYD_OPT_NO_STATE, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_OPT_PARSE_ONLY | LYD_OPT_NO_STATE, &tree));
     assert_null(tree);
     logbuf_assert("Invalid state data node \"cont2\" found. Line number 1.");
 
-    assert_int_equal(LY_EVALID, lyd_parse_xml(ctx, data, LYD_VALOPT_DATA_ONLY | LYD_VALOPT_NO_STATE, &tree));
+    assert_int_equal(LY_EVALID, lyd_parse_xml_data(ctx, data, LYD_VALOPT_DATA_ONLY | LYD_VALOPT_NO_STATE, &tree));
     assert_null(tree);
     logbuf_assert("Invalid state data node \"cont2\" found. /h:cont/cont2");
 
-    assert_int_equal(LY_SUCCESS, lyd_parse_xml(ctx, data, LYD_OPT_PARSE_ONLY, &tree));
+    assert_int_equal(LY_SUCCESS, lyd_parse_xml_data(ctx, data, LYD_OPT_PARSE_ONLY, &tree));
     assert_non_null(tree);
 
     assert_int_equal(LY_EVALID, lyd_validate(&tree, NULL, LYD_VALOPT_DATA_ONLY | LYD_VALOPT_NO_STATE));
@@ -1238,6 +1244,7 @@
         cmocka_unit_test_teardown(test_defaults, teardown_s),
         cmocka_unit_test_teardown(test_iffeature, teardown_s),
         cmocka_unit_test_teardown(test_state, teardown_s),
+        //cmocka_unit_test_teardown(test_edit, teardown_s),
     };
 
     return cmocka_run_group_tests(tests, setup, teardown);
diff --git a/tools/lint/commands.c b/tools/lint/commands.c
index b397950..90affdd 100644
--- a/tools/lint/commands.c
+++ b/tools/lint/commands.c
@@ -809,8 +809,8 @@
                 options |= LYD_OPT_GET;
             } else if (!strcmp(optarg, "getconfig")) {
                 options |= LYD_OPT_GETCONFIG;
-            } else if (!strcmp(optarg, "edit")) {
-                options |= LYD_OPT_EDIT;
+            /*} else if (!strcmp(optarg, "edit")) {
+                options |= LYD_OPT_EDIT;*/
             } else {
                 fprintf(stderr, "Invalid parser option \"%s\".\n", optarg);
                 cmd_data_help();
diff --git a/tools/lint/main_ni.c b/tools/lint/main_ni.c
index 99e7ce2..bd52fc7 100644
--- a/tools/lint/main_ni.c
+++ b/tools/lint/main_ni.c
@@ -519,8 +519,8 @@
                 options_parser |= LYD_OPT_GET;
             } else if (!strcmp(optarg, "getconfig")) {
                 options_parser |= LYD_OPT_GETCONFIG;
-            } else if (!strcmp(optarg, "edit")) {
-                options_parser |= LYD_OPT_EDIT;
+            /*} else if (!strcmp(optarg, "edit")) {
+                options_parser |= LYD_OPT_EDIT;*/
             } else if (!strcmp(optarg, "data")) {
                 /* no options */
             } else {