data parsers CHANGE refactor data type resolving

avoid code duplication and fix resolving leafrefs and unions. There
were some complex use cases where the leafrefs were not correctly
resolved because of incorrect value conversion into the target data
type.

Fixes #174
diff --git a/src/parser.c b/src/parser.c
index 740ad0b..cb53e9b 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -428,7 +428,9 @@
     char *strptr;
 
     if (!val_str || !val_str[0]) {
-        LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, "", node->schema->name);
+        if (node) {
+            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, "", node->schema->name);
+        }
         return EXIT_FAILURE;
     }
 
@@ -439,14 +441,18 @@
     /* parse the value */
     *ret = strtoll(val_str, &strptr, base);
     if (errno || (*ret < min) || (*ret > max)) {
-        LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, val_str, node->schema->name);
+        if (node) {
+            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, val_str, node->schema->name);
+        }
         return EXIT_FAILURE;
     } else if (strptr && *strptr) {
         while (isspace(*strptr)) {
             ++strptr;
         }
         if (*strptr) {
-            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, val_str, node->schema->name);
+            if (node) {
+                LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, val_str, node->schema->name);
+            }
             return EXIT_FAILURE;
         }
     }
@@ -464,7 +470,9 @@
     char *strptr;
 
     if (!val_str || !val_str[0]) {
-        LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, "", node->schema->name);
+        if (node) {
+            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, "", node->schema->name);
+        }
         return EXIT_FAILURE;
     }
 
@@ -472,14 +480,18 @@
     strptr = NULL;
     *ret = strtoull(val_str, &strptr, base);
     if (errno || (*ret > max)) {
-        LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, val_str, node->schema->name);
+        if (node) {
+            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, val_str, node->schema->name);
+        }
         return EXIT_FAILURE;
     } else if (strptr && *strptr) {
         while (isspace(*strptr)) {
             ++strptr;
         }
         if (*strptr) {
-            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, val_str, node->schema->name);
+            if (node) {
+                LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, val_str, node->schema->name);
+            }
             return EXIT_FAILURE;
         }
     }
@@ -877,15 +889,15 @@
     return EXIT_SUCCESS;
 }
 
-/*
- * type is required for LY_TYPE_DEC64, LY_TYPE_BITS
- */
-static int
-lyp_parse_value_make_canonical(struct lyd_node_leaf_list *node, struct lys_type *type)
+static void
+make_canonical(struct ly_ctx *ctx, int type, const char **value, void *data1, void *data2)
 {
     char *buf = ly_buf(), *buf_backup = NULL, *str;
-    int len, i, j;
-    int ret = EXIT_FAILURE;
+    struct lys_type_bit **bits = NULL;
+    int i, j, count;
+    int64_t num;
+    uint64_t unum;
+    uint8_t c;
 
     /* prepare buffer for creating canonical representation */
     if (ly_buf_used && buf[0]) {
@@ -893,90 +905,74 @@
     }
     ly_buf_used++;
 
-    /* make sure that we have canonical form of the value */
-    switch (node->value_type & LY_DATA_TYPE_MASK) {
-    case LY_TYPE_INT8:
-        sprintf(buf, "%d", node->value.int8);
-        break;
-    case LY_TYPE_INT16:
-        sprintf(buf, "%d", node->value.int16);
-        break;
-    case LY_TYPE_INT32:
-        sprintf(buf, "%d", node->value.int32);
-        break;
-    case LY_TYPE_INT64:
-        sprintf(buf, "%"PRId64, node->value.int64);
-        break;
-    case LY_TYPE_UINT8:
-        sprintf(buf, "%u", node->value.uint8);
-        break;
-    case LY_TYPE_UINT16:
-        sprintf(buf, "%u", node->value.uint16);
-        break;
-    case LY_TYPE_UINT32:
-        sprintf(buf, "%u", node->value.uint32);
-        break;
-    case LY_TYPE_UINT64:
-        sprintf(buf, "%"PRIu64, node->value.uint64);
-        break;
-    case LY_TYPE_DEC64:
-        if (node->value.dec64) {
-            len = sprintf(buf, "%"PRId64" ", node->value.dec64);
-            for (i = type->info.dec64.dig, j = 1; i > 0 ; i--) {
-                if (j && i > 1 && buf[len - 2] == '0') {
-                    /* we have trailing zero to skip */
-                    buf[len - 1] = '\0';
-                } else {
-                    j = 0;
-                    buf[len - 1] = buf[len - 2];
-                }
-                len--;
-            }
-            buf[len - 1] = '.';
-        } else {
-            /* zero */
-            sprintf(buf, "0.0");
-        }
-        break;
+    switch (type) {
     case LY_TYPE_BITS:
+        bits = (struct lys_type_bit **)data1;
+        count = *((int *)data2);
         /* in canonical form, the bits are ordered by their position */
         buf[0] = '\0';
-        for (i = 0; i < type->info.bits.count; i++) {
-            if (!node->value.bit[i]) {
+        for (i = 0; i < count; i++) {
+            if (!bits[i]) {
                 /* bit not set */
                 continue;
             }
             if (buf[0]) {
                 str = strdup(buf);
-                sprintf(buf, "%s %s", str, node->value.bit[i]->name);
+                sprintf(buf, "%s %s", str, bits[i]->name);
                 free(str);
             } else {
-                sprintf(buf, "%s", node->value.bit[i]->name);
+                sprintf(buf, "%s", bits[i]->name);
             }
         }
         break;
-    case LY_TYPE_LEAFREF:
-        /* if possible, canonical form for the leafref is determined when the leafref is resolved */
-    case LY_TYPE_STRING:
-    case LY_TYPE_BOOL:
-    case LY_TYPE_ENUM:
-    case LY_TYPE_BINARY:
-    case LY_TYPE_IDENT:
-    case LY_TYPE_INST:
-    case LY_TYPE_EMPTY:
-        /* canonical representation is the same as lexical */
-        ret = EXIT_SUCCESS;
+
+    case LY_TYPE_DEC64:
+        num = *((int64_t *)data1);
+        c = *((uint8_t *)data2);
+        if (num) {
+            count = sprintf(buf, "%"PRId64" ", num);
+            for (i = c, j = 1; i > 0 ; i--) {
+                if (j && i > 1 && buf[count - 2] == '0') {
+                    /* we have trailing zero to skip */
+                    buf[count - 1] = '\0';
+                } else {
+                    j = 0;
+                    buf[count - 1] = buf[count - 2];
+                }
+                count--;
+            }
+            buf[count - 1] = '.';
+        } else {
+            /* zero */
+            sprintf(buf, "0.0");
+        }
+        break;
+
+    case LY_TYPE_INT8:
+    case LY_TYPE_INT16:
+    case LY_TYPE_INT32:
+    case LY_TYPE_INT64:
+        num = *((int64_t *)data1);
+        sprintf(buf, "%"PRId64, num);
+        break;
+
+    case LY_TYPE_UINT8:
+    case LY_TYPE_UINT16:
+    case LY_TYPE_UINT32:
+    case LY_TYPE_UINT64:
+        unum = *((uint64_t *)data1);
+        sprintf(buf, "%"PRIu64, unum);
+        break;
+
+    default:
+        /* should not be even called - just do nothing */
         goto cleanup;
-    case LY_TYPE_UNION:
-        LOGINT;
-        goto cleanup;
-    }
-    if (strcmp(buf, node->value_str)) {
-        lydict_remove(node->schema->module->ctx, node->value_str);
-        node->value_str = lydict_insert(node->schema->module->ctx, buf, 0);
     }
 
-    ret = EXIT_SUCCESS;
+    if (strcmp(buf, *value)) {
+        lydict_remove(ctx, *value);
+        *value = lydict_insert(ctx, buf, 0);
+    }
 
 cleanup:
     if (buf_backup) {
@@ -986,100 +982,111 @@
     }
     ly_buf_used--;
 
-    return ret;
+    return;
 }
 
+
 /*
- * logs directly
- *
- * resolve - whether resolve identityrefs and leafrefs (which must be in JSON form)
+ * xml  - optional for converting instance-identifier and identityref into JSON format
+ * tree - optional for resolving instance-identifiers and leafrefs
+ * leaf - optional for storing parsed data
  */
-int
-lyp_parse_value_type(struct lyd_node_leaf_list *node, struct lys_type *stype, struct lyxml_elem *xml, int resolve,
-                     int dflt)
+struct lys_type *
+lyp_parse_value(struct lys_type *type, const char **value_, struct lyxml_elem *xml, struct lyd_node *tree,
+                        struct lyd_node_leaf_list *leaf, int resolvable, int dflt)
 {
-    #define DECSIZE 21
-    struct lys_type *type = NULL;
-    const char *ptr;
+    struct lys_type *ret = NULL, *t;
+    int c, i, j, len, found = 0, hidden;
     int64_t num;
     uint64_t unum;
-    int len;
-    int c, i, j;
-    int found;
-    int ret = EXIT_FAILURE;
+    const char *ptr, *value = *value_;
+    struct lys_type_bit **bits = NULL;
+    struct lys_ident *ident;
 
-    assert(node);
+    if (leaf) {
+        leaf->value_type = type->base;
+    }
 
-switchtype:
-    switch (node->value_type & LY_DATA_TYPE_MASK) {
+    switch(type->base) {
     case LY_TYPE_BINARY:
-        if (validate_length_range(0, (node->value_str ? strlen(node->value_str) : 0), 0, 0, 0, stype,
-                                  node->value_str, (struct lyd_node *)node)) {
-            return EXIT_FAILURE;
+        if (validate_length_range(0, (value ? strlen(value) : 0), 0, 0, 0, type, value, NULL)) {
+            goto cleanup;
         }
-
-        node->value.binary = node->value_str;
         break;
 
     case LY_TYPE_BITS:
         /* locate bits structure with the bits definitions
          * since YANG 1.1 allows restricted bits, it is the first
          * bits type with some explicit bit specification */
-        for (type = stype; !type->info.bits.count; type = &type->der->type);
+        for (; !type->info.bits.count; type = &type->der->type);
 
-        /* allocate the array of  pointers to bits definition */
-        node->value.bit = calloc(type->info.bits.count, sizeof *node->value.bit);
-        if (!node->value.bit) {
-            LOGMEM;
-            return EXIT_FAILURE;
+        if (value || leaf) {
+            /* allocate the array of pointers to bits definition */
+            bits = calloc(type->info.bits.count, sizeof *bits);
+            if (!bits) {
+                LOGMEM;
+                goto cleanup;
+            }
         }
 
-        if (!node->value_str) {
+        if (!value) {
             /* no bits set */
+            if (leaf) {
+                /* store empty array */
+                leaf->value.bit = bits;
+            }
             break;
         }
 
         c = 0;
         i = 0;
-        while (node->value_str[c]) {
+        while (value[c]) {
             /* skip leading whitespaces */
-            while (isspace(node->value_str[c])) {
+            while (isspace(value[c])) {
                 c++;
             }
 
             /* get the length of the bit identifier */
-            for (len = 0; node->value_str[c] && !isspace(node->value_str[c]); c++, len++);
+            for (len = 0; value[c] && !isspace(value[c]); c++, len++);
 
             /* go back to the beginning of the identifier */
             c = c - len;
 
             /* find bit definition, identifiers appear ordered by their posititon */
             for (found = i = 0; i < type->info.bits.count; i++) {
-                if (!strncmp(type->info.bits.bit[i].name, &node->value_str[c], len)
-                        && !type->info.bits.bit[i].name[len]) {
+                if (!strncmp(type->info.bits.bit[i].name, &value[c], len) && !type->info.bits.bit[i].name[len]) {
                     /* we have match, check if the value is enabled ... */
                     for (j = 0; j < type->info.bits.bit[i].iffeature_size; j++) {
                         if (!resolve_iffeature(&type->info.bits.bit[i].iffeature[i])) {
-                            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, node->value_str, node->schema->name);
-                            LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Bit \"%s\" is disabled by its if-feature condition.",
-                                   type->info.bits.bit[i].name);
-                            free(node->value.bit);
-                            node->value.bit = NULL;
-                            return EXIT_FAILURE;
+                            if (leaf) {
+                                LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, value, leaf->schema->name);
+                                LOGVAL(LYE_SPEC, LY_VLOG_LYD, leaf,
+                                       "Bit \"%s\" is disabled by its if-feature condition.",
+                                       type->info.bits.bit[i].name);
+                            } else {
+                                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
+                                       "Bit \"%s\" is disabled by its if-feature condition.",
+                                       type->info.bits.bit[i].name);
+                            }
+                            free(bits);
+                            goto cleanup;
                         }
                     }
-
                     /* check that the value was not already set */
-                    if (node->value.bit[i]) {
-                        LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, node->value_str, node->schema->name);
-                        LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Bit \"%s\" used multiple times.",
-                               type->info.bits.bit[i].name);
-                        free(node->value.bit);
-                        node->value.bit = NULL;
-                        return EXIT_FAILURE;
+                    if (bits[i]) {
+                        if (leaf) {
+                            LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, value, leaf->schema->name);
+                            LOGVAL(LYE_SPEC, LY_VLOG_LYD, leaf, "Bit \"%s\" used multiple times.",
+                                   type->info.bits.bit[i].name);
+                        } else {
+                            LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Bit \"%s\" used multiple times.",
+                                   type->info.bits.bit[i].name);
+                        }
+                        free(bits);
+                        goto cleanup;
                     }
                     /* ... and then store the pointer */
-                    node->value.bit[i] = &type->info.bits.bit[i];
+                    bits[i] = &type->info.bits.bit[i];
 
                     /* stop searching */
                     found = 1;
@@ -1089,356 +1096,475 @@
 
             if (!found) {
                 /* referenced bit value does not exists */
-                LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, node->value_str, node->schema->name);
-                free(node->value.bit);
-                node->value.bit = NULL;
-                return EXIT_FAILURE;
+                if (leaf) {
+                    LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, value, leaf->schema->name);
+                } else {
+                    LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid bit reference: \"%s\".", value);
+                }
+                free(bits);
+                goto cleanup;
             }
-
             c = c + len;
         }
 
+        make_canonical(type->parent->module->ctx, LY_TYPE_BITS, value_, bits, &type->info.bits.count);
+
+        if (leaf) {
+            /* store the result */
+            leaf->value.bit = bits;
+        } else {
+            free(bits);
+        }
         break;
 
     case LY_TYPE_BOOL:
-        if (!node->value_str) {
-            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, "", node->schema->name);
-            return EXIT_FAILURE;
-        }
-
-        if (!strcmp(node->value_str, "true")) {
-            node->value.bln = 1;
-        } else if (strcmp(node->value_str, "false")) {
-            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, node->value_str, node->schema->name);
-            return EXIT_FAILURE;
+        if (value && !strcmp(value, "true")) {
+            if (leaf) {
+                leaf->value.bln = 1;
+            }
+        } else if (!value || strcmp(value, "false")) {
+            if (leaf) {
+                LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, value ? value : "", leaf->schema->name);
+            } else {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid bool value \"%s\".", value ? value : "");
+            }
+            goto cleanup;
         }
         /* else stays 0 */
         break;
 
     case LY_TYPE_DEC64:
-        if (!node->value_str || !node->value_str[0]) {
-            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, "", node->schema->name);
-            return EXIT_FAILURE;
+        if (!value || !value[0]) {
+            if (leaf) {
+                LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, "", leaf->schema->name);
+            } else {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid decimal64 value \"\".");
+            }
+            goto cleanup;
         }
 
-        /* locate dec64 structure with the fraction-digits value */
-        for (type = stype; type->der->type.der; type = &type->der->type);
-
-        ptr = node->value_str;
+        ptr = value;
         if (parse_range_dec64(&ptr, type->info.dec64.dig, &num) || ptr[0]) {
-            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, node->value_str, node->schema->name);
-            return EXIT_FAILURE;
+            if (leaf) {
+                LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, value, leaf->schema->name);
+            } else {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid decimal64 value \"%s\".", value);
+            }
+            goto cleanup;
         }
 
-        if (validate_length_range(2, 0, 0, num, type->info.dec64.dig, stype,
-                                  node->value_str, (struct lyd_node *)node)) {
-            return EXIT_FAILURE;
+        if (validate_length_range(2, 0, 0, num, type->info.dec64.dig, type, value, NULL)) {
+            goto cleanup;
         }
-        node->value.dec64 = num;
+
+        make_canonical(type->parent->module->ctx, LY_TYPE_DEC64, value_, &num, &type->info.dec64.dig);
+
+        if (leaf) {
+            /* store the result */
+            leaf->value.dec64 = num;
+        }
         break;
 
     case LY_TYPE_EMPTY:
-        /* just check that it is empty */
-        if (node->value_str && node->value_str[0]) {
-            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, node->value_str, node->schema->name);
-            return EXIT_FAILURE;
+        if (value && value[0]) {
+            if (leaf) {
+                LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, value, leaf->schema->name);
+            } else {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid empty value \"%s\".", value);
+            }
+            goto cleanup;
         }
         break;
 
     case LY_TYPE_ENUM:
-        if (!node->value_str) {
-            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, "", node->schema->name);
-            return EXIT_FAILURE;
-        }
-
         /* locate enums structure with the enumeration definitions,
          * since YANG 1.1 allows restricted enums, it is the first
          * enum type with some explicit enum specification */
-        for (type = stype; !type->info.enums.count; type = &type->der->type);
+        for (; !type->info.enums.count; type = &type->der->type);
 
         /* find matching enumeration value */
-        for (i = 0; i < type->info.enums.count; i++) {
-            if (!strcmp(node->value_str, type->info.enums.enm[i].name)) {
+        for (i = found = 0; i < type->info.enums.count; i++) {
+            if (value && !strcmp(value, type->info.enums.enm[i].name)) {
                 /* we have match, check if the value is enabled ... */
                 for (j = 0; j < type->info.enums.enm[i].iffeature_size; j++) {
                     if (!resolve_iffeature(&type->info.enums.enm[i].iffeature[i])) {
-                        LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, node->value_str, node->schema->name);
-                        LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Enum \"%s\" is disabled by its if-feature condition.",
-                               node->value_str);
-                        return EXIT_FAILURE;
+                        if (leaf) {
+                            LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, value, leaf->schema->name);
+                            LOGVAL(LYE_SPEC, LY_VLOG_LYD, leaf, "Enum \"%s\" is disabled by its if-feature condition.",
+                                   value);
+                        } else {
+                            LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Enum \"%s\" is disabled by its if-feature condition.",
+                                   value);
+                        }
+                        goto cleanup;
                     }
                 }
-
                 /* ... and store pointer to the definition */
-                node->value.enm = &type->info.enums.enm[i];
+                if (leaf) {
+                    leaf->value.enm = &type->info.enums.enm[i];
+                }
+                found = 1;
                 break;
             }
         }
 
-        if (!node->value.enm) {
-            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, node->value_str, node->schema->name);
-            return EXIT_FAILURE;
+        if (!found) {
+            if (leaf) {
+                LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, value ? value : "", leaf->schema->name);
+            } else {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid enum value \"%s\".", value ? value : "");
+            }
+            goto cleanup;
         }
-
         break;
 
     case LY_TYPE_IDENT:
-        if (!node->value_str) {
-            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, "", node->schema->name);
-            return EXIT_FAILURE;
+        if (!value) {
+            if (leaf) {
+                LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, "", leaf->schema->name);
+            } else {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid identityref value \"\".");
+            }
+            goto cleanup;
         }
 
-        node->value.ident = resolve_identref(stype, node->value_str, (struct lyd_node *)node);
-        if (!node->value.ident) {
-            return EXIT_FAILURE;
+        if (xml) {
+            /* first, convert value into the json format */
+            value = transform_xml2json(type->parent->module->ctx, value, xml, 0);
+            if (!value) {
+                /* invalid identityref format */
+                if (leaf) {
+                    LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, *value_, leaf->schema->name);
+                } else {
+                    LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid identityref value \"%s\".", *value_);
+                }
+                goto cleanup;
+            }
+        }
+
+        ident = resolve_identref(type, value, (struct lyd_node*)leaf);
+        if (!ident) {
+            if (leaf) {
+                LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, *value_, leaf->schema->name);
+            } else {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid identityref value \"%s\" (%s).", value, *value_);
+            }
+            goto cleanup;
+        } else if (leaf) {
+            /* store the result */
+            leaf->value.ident = ident;
+        }
+
+        if (xml) {
+            /* update the changed value */
+            lydict_remove(type->parent->module->ctx, *value_);
+            *value_ = value;
         }
         break;
 
     case LY_TYPE_INST:
-        if (!node->value_str) {
-            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, "", node->schema->name);
-            return EXIT_FAILURE;
+        if (!value) {
+            if (leaf) {
+                LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, "", leaf->schema->name);
+            } else {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid instance-identifier value \"\".");
+            }
+            goto cleanup;
         }
 
-        if (!resolve) {
-            node->value_type |= LY_TYPE_INST_UNRES;
+        if (xml) {
+            /* first, convert value into the json format */
+            value = transform_xml2json(type->parent->module->ctx, value, xml, 0);
+            if (!value) {
+                /* invalid instance-identifier format */
+                if (leaf) {
+                    LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, *value_, leaf->schema->name);
+                } else {
+                    LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid instance-identifier value \"%s\".", *value_);
+                }
+                goto cleanup;
+            }
+        }
+        if (resolvable && tree && !resolve_instid(tree, value) && type->info.inst.req) {
+            if (leaf) {
+                LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, *value_, leaf->schema->name);
+            } else {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid instance-identifier value \"%s\" (%s).", value, *value_);
+            }
+            goto cleanup;
+        } else if (!resolvable && leaf) {
+            /* make the note that the data node is not resolvable instance-identifier,
+             * because based on the data type the target is not necessary the part of the tree */
+            leaf->value_type |= LY_TYPE_INST_UNRES;
+        }
+
+        if (xml) {
+            /* update the changed value */
+            lydict_remove(type->parent->module->ctx, *value_);
+            *value_ = value;
         }
         break;
 
     case LY_TYPE_LEAFREF:
-        if (!node->value_str) {
-            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, "", node->schema->name);
-            return EXIT_FAILURE;
+        if (!value) {
+            if (leaf) {
+                LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, "", leaf->schema->name);
+            } else {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid leafref value \"\".");
+            }
+            goto cleanup;
         }
 
-        if (!resolve && stype->info.lref.target) {
-            type = &stype->info.lref.target->type;
-            while (type->base == LY_TYPE_LEAFREF && type->info.lref.target) {
-                type = &type->info.lref.target->type;
+        /* it is called not only to get the final type, but mainly to update value to canonical or JSON form
+         * if needed */
+        t = lyp_parse_value(&type->info.lref.target->type, value_, xml, tree, leaf, resolvable, dflt);
+        value = *value_; /* refresh possibly changed value */
+        if (!t) {
+            if (leaf) {
+                LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, value, leaf->schema->name);
+            } else {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid leafref value \"%s\".", value);
             }
-            if (type->base == LY_TYPE_LEAFREF) {
-                /* not resolved leafref */
-                break;
-            }
-            node->value_type = type->base | LY_TYPE_LEAFREF_UNRES;
-
-            /* get the value according to the target's type */
-            stype = type;
-            goto switchtype;
+            goto cleanup;
         }
+
+        if (!resolvable && leaf) {
+            /* the leafref will not be resolved because of the data tree type which make possible that the
+             * target is not present in the data tree. Therefore, instead of leafref type, we store into the
+             * leaf the target type of the leafref with the note that it is unresolved leafref */
+            leaf->value_type = t->base | LY_TYPE_LEAFREF_UNRES;
+        } else if (leaf) {
+            /* if the leaf is resolvable, its type is kept as LY_TYPE_LEAFREF */
+            leaf->value_type = LY_TYPE_LEAFREF;
+
+            /* erase possibly assigned data in value structure from recursive ly_parse_value() calling */
+            if (t->base == LY_TYPE_BITS) {
+                free(leaf->value.bit);
+            }
+            memset(&leaf->value, 0, sizeof leaf->value);
+            ly_err_clean(1);
+
+            /* if we have the complete tree, resolve the leafref */
+            if (tree && resolve_leafref(leaf, type) && type->info.lref.req != -1) {
+                /* failure */
+                goto cleanup;
+            }
+        }
+
+        type = t;
         break;
 
     case LY_TYPE_STRING:
-        if (validate_length_range(0, (node->value_str ? strlen(node->value_str) : 0), 0, 0, 0, stype,
-                                  node->value_str, (struct lyd_node *)node)) {
-            return EXIT_FAILURE;
+        if (validate_length_range(0, (value ? strlen(value) : 0), 0, 0, 0, type, value, NULL)) {
+            goto cleanup;
         }
 
-        if (validate_pattern(node->value_str, stype, (struct lyd_node *)node)) {
-            return EXIT_FAILURE;
+        if (validate_pattern(value, type, NULL)) {
+            goto cleanup;
         }
 
-        node->value.string = node->value_str;
+        if (leaf) {
+            /* store the result */
+            leaf->value.string = value;
+        }
         break;
 
     case LY_TYPE_INT8:
-        if (parse_int(node->value_str, __INT64_C(-128), __INT64_C(127), dflt ? 0 : 10, &num, (struct lyd_node *)node)
-                || validate_length_range(1, 0, num, 0, 0, stype, node->value_str, (struct lyd_node *)node)) {
-            return EXIT_FAILURE;
+        if (parse_int(value, __INT64_C(-128), __INT64_C(127), dflt ? 0 : 10, &num, NULL)
+                || validate_length_range(1, 0, num, 0, 0, type, value, NULL)) {
+            if (!leaf) {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid int8 value \"%s\".", value ? value : "");
+            } /* else error message printed in parse_int() */
+            goto cleanup;
         }
-        node->value.int8 = num;
+
+        make_canonical(type->parent->module->ctx, LY_TYPE_INT8, value_, &num, NULL);
+
+        if (leaf) {
+            /* store the result */
+            leaf->value.int8 = (int8_t)num;
+        }
         break;
 
     case LY_TYPE_INT16:
-        if (parse_int(node->value_str, __INT64_C(-32768), __INT64_C(32767), dflt ? 0 : 10, &num,
-                      (struct lyd_node *)node)
-                || validate_length_range(1, 0, num, 0, 0, stype, node->value_str, (struct lyd_node *)node)) {
-            return EXIT_FAILURE;
+        if (parse_int(value, __INT64_C(-32768), __INT64_C(32767), dflt ? 0 : 10, &num, NULL)
+                || validate_length_range(1, 0, num, 0, 0, type, value, NULL)) {
+            if (!leaf) {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid int16 value \"%s\".", value ? value : "");
+            } /* else error message printed in parse_int() */
+            goto cleanup;
         }
-        node->value.int16 = num;
+
+        make_canonical(type->parent->module->ctx, LY_TYPE_INT16, value_, &num, NULL);
+
+        if (leaf) {
+            /* store the result */
+            leaf->value.int16 = (int16_t)num;
+        }
         break;
 
     case LY_TYPE_INT32:
-        if (parse_int(node->value_str, __INT64_C(-2147483648), __INT64_C(2147483647), dflt ? 0 : 10, &num,
-                      (struct lyd_node *)node)
-                || validate_length_range(1, 0, num, 0, 0, stype, node->value_str, (struct lyd_node *)node)) {
-            return EXIT_FAILURE;
+        if (parse_int(value, __INT64_C(-2147483648), __INT64_C(2147483647), dflt ? 0 : 10, &num, NULL)
+                || validate_length_range(1, 0, num, 0, 0, type, value, NULL)) {
+            if (!leaf) {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid int32 value \"%s\".", value ? value : "");
+            } /* else error message printed in parse_int() */
+            goto cleanup;
         }
-        node->value.int32 = num;
+
+        make_canonical(type->parent->module->ctx, LY_TYPE_INT32, value_, &num, NULL);
+
+        if (leaf) {
+            /* store the result */
+            leaf->value.int32 = (int32_t)num;
+        }
         break;
 
     case LY_TYPE_INT64:
-        if (parse_int(node->value_str, __INT64_C(-9223372036854775807) - __INT64_C(1), __INT64_C(9223372036854775807),
-                      dflt ? 0 : 10, &num, (struct lyd_node *)node)
-                || validate_length_range(1, 0, num, 0, 0, stype, node->value_str, (struct lyd_node *)node)) {
-            return EXIT_FAILURE;
+        if (parse_int(value, __INT64_C(-9223372036854775807) - __INT64_C(1), __INT64_C(9223372036854775807),
+                      dflt ? 0 : 10, &num, NULL)
+                || validate_length_range(1, 0, num, 0, 0, type, value, NULL)) {
+            if (!leaf) {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid int64 value \"%s\".", value ? value : "");
+            } /* else error message printed in parse_int() */
+            goto cleanup;
         }
-        node->value.int64 = num;
+
+        make_canonical(type->parent->module->ctx, LY_TYPE_INT64, value_, &num, NULL);
+
+        if (leaf) {
+            /* store the result */
+            leaf->value.int64 = num;
+        }
         break;
 
     case LY_TYPE_UINT8:
-        if (parse_uint(node->value_str, __UINT64_C(255), dflt ? 0 : 10, &unum, (struct lyd_node *)node)
-                || validate_length_range(0, unum, 0, 0, 0, stype, node->value_str, (struct lyd_node *)node)) {
-            return EXIT_FAILURE;
+        if (parse_uint(value, __UINT64_C(255), dflt ? 0 : 10, &unum, NULL)
+                || validate_length_range(0, unum, 0, 0, 0, type, value, NULL)) {
+            if (!leaf) {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid uint8 value \"%s\".", value ? value : "");
+            } /* else error message printed in parse_uint() */
+            goto cleanup;
         }
-        node->value.uint8 = unum;
+
+        make_canonical(type->parent->module->ctx, LY_TYPE_UINT8, value_, &unum, NULL);
+
+        if (leaf) {
+            /* store the result */
+            leaf->value.uint8 = (uint8_t)unum;
+        }
         break;
 
     case LY_TYPE_UINT16:
-        if (parse_uint(node->value_str, __UINT64_C(65535), dflt ? 0 : 10, &unum, (struct lyd_node *)node)
-                || validate_length_range(0, unum, 0, 0, 0, stype, node->value_str, (struct lyd_node *)node)) {
-            return EXIT_FAILURE;
+        if (parse_uint(value, __UINT64_C(65535), dflt ? 0 : 10, &unum, NULL)
+                || validate_length_range(0, unum, 0, 0, 0, type, value, NULL)) {
+            if (!leaf) {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid uint16 value \"%s\".", value ? value : "");
+            } /* else error message printed in parse_uint() */
+            goto cleanup;
         }
-        node->value.uint16 = unum;
+
+        make_canonical(type->parent->module->ctx, LY_TYPE_UINT16, value_, &unum, NULL);
+
+        if (leaf) {
+            /* store the result */
+            leaf->value.uint16 = (uint16_t)unum;
+        }
         break;
 
     case LY_TYPE_UINT32:
-        if (parse_uint(node->value_str, __UINT64_C(4294967295), dflt ? 0 : 10, &unum,
-                       (struct lyd_node *)node)
-                || validate_length_range(0, unum, 0, 0, 0, stype, node->value_str, (struct lyd_node *)node)) {
-            return EXIT_FAILURE;
+        if (parse_uint(value, __UINT64_C(4294967295), dflt ? 0 : 10, &unum, NULL)
+                || validate_length_range(0, unum, 0, 0, 0, type, value, NULL)) {
+            if (!leaf) {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid uint32 value \"%s\".", value ? value : "");
+            } /* else error message printed in parse_uint() */
+            goto cleanup;
         }
-        node->value.uint32 = unum;
+
+        make_canonical(type->parent->module->ctx, LY_TYPE_UINT32, value_, &unum, NULL);
+
+        if (leaf) {
+            /* store the result */
+            leaf->value.uint32 = (uint32_t)unum;
+        }
         break;
 
     case LY_TYPE_UINT64:
-        if (parse_uint(node->value_str, __UINT64_C(18446744073709551615), dflt ? 0 : 10, &unum,
-                       (struct lyd_node *)node)
-                || validate_length_range(0, unum, 0, 0, 0, stype, node->value_str, (struct lyd_node *)node)) {
-            return EXIT_FAILURE;
+        if (parse_uint(value, __UINT64_C(18446744073709551615), dflt ? 0 : 10, &unum, NULL)
+                || validate_length_range(0, unum, 0, 0, 0, type, value, NULL)) {
+            if (!leaf) {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid uint64 value \"%s\".", value ? value : "");
+            } /* else error message printed in parse_uint() */
+            goto cleanup;
         }
-        node->value.uint64 = unum;
+
+        make_canonical(type->parent->module->ctx, LY_TYPE_UINT64, value_, &unum, NULL);
+
+        if (leaf) {
+            /* store the result */
+            leaf->value.uint64 = unum;
+        }
         break;
 
     case LY_TYPE_UNION:
-        /* have to cover union here because a not resolving leafref can point to union and we need to resolve the base
-         * type of the value in leafref node */
-        assert(node->value_type & LY_TYPE_LEAFREF_UNRES);
+        t = NULL;
+        found = 0;
 
         /* turn logging off, we are going to try to validate the value with all the types in order */
+        hidden = *ly_vlog_hide_location();
         ly_vlog_hide(1);
 
-        type = NULL;
-        while ((type = lyp_get_next_union_type(stype, type, &found))) {
+        while ((t = lyp_get_next_union_type(type, t, &found))) {
             found = 0;
-            ptr = NULL;
-            node->value_type = type->base;
-            memset(&node->value, 0, sizeof node->value);
-
-            /* in these cases we use JSON format */
-            if (xml && ((type->base == LY_TYPE_IDENT) || (type->base == LY_TYPE_INST))) {
-                /* remember the original value and try if it can be transformed into JSON format */
-                ptr = node->value_str;
-                node->value_str = transform_xml2json(node->schema->module->ctx, ptr, xml, 0);
-                if (!node->value_str) {
-                    /* if not, the value cannot be of these types, try another */
-                    node->value_str = ptr;
-                    found = 0;
-                    continue;
-                }
-            }
-
-            node->value_type &= ~LY_DATA_TYPE_MASK;
-            node->value_type |= type->base;
-            if (!lyp_parse_value_type(node, type, xml, resolve, dflt)) {
-                /* success */
+            ret = lyp_parse_value(t, value_, xml, tree, leaf, resolvable, dflt);
+            if (ret) {
+                /* we have the result */
+                type = ret;
                 break;
             }
+            /* erase information about errors - they are false or irrelevant
+             * and will be replaced by a single error messages */
+            ly_err_clean(1);
 
-            if (ptr) {
-                lydict_remove(node->schema->module->ctx, node->value_str);
-                node->value_str = ptr;
+            if (leaf) {
+                /* erase possible present and invalid value data */
+                if (t->base == LY_TYPE_BITS) {
+                    free(leaf->value.bit);
+                }
+                memset(&leaf->value, 0, sizeof leaf->value);
             }
-
         }
 
-        /* erase information about errors - they are false or irrelevant
-         * and will be replaced by a single error messages */
-        ly_err_clean(1);
-        ly_vlog_hide(0);
-
-        if (!type) {
-            /* failure */
-            node->value_type &= ~LY_DATA_TYPE_MASK;
-            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, (node->value_str ? node->value_str : ""), node->schema->name);
-            return EXIT_FAILURE;
+        /* turn logging back on */
+        if (!hidden) {
+            ly_vlog_hide(0);
         }
-        /* skip making canonical form because it is already created */
-        return EXIT_SUCCESS;
+
+        if (!t) {
+            /* not found */
+            if (leaf) {
+                leaf->value_type &= ~LY_DATA_TYPE_MASK;
+                LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, *value_ ? *value_ : "", leaf->schema->name);
+            } else {
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%s\" for union \"%s\".", *value_ ? *value_ : "",
+                       type->parent->name);
+            }
+            goto cleanup;
+        }
+        break;
+
+    default:
+        LOGINT;
+        return NULL;
     }
 
-    if (!lyp_parse_value_make_canonical(node, type)) {
-        ret = EXIT_SUCCESS;
-    }
+    ret = type;
+
+cleanup:
 
     return ret;
 }
 
-int
-lyp_parse_value(struct lyd_node_leaf_list *leaf, struct lyxml_elem *xml, int resolve, int dflt)
-{
-    int found = 0;
-    struct lys_type *type, *stype;
-
-    assert(leaf);
-
-    stype = &((struct lys_node_leaf *)leaf->schema)->type;
-    if (stype->base == LY_TYPE_UNION) {
-        /* turn logging off, we are going to try to validate the value with all the types in order */
-        ly_vlog_hide(1);
-
-        type = NULL;
-        while ((type = lyp_get_next_union_type(stype, type, &found))) {
-            found = 0;
-            leaf->value_type = type->base;
-            memset(&leaf->value, 0, sizeof leaf->value);
-
-            /* in these cases we use JSON format */
-            if (xml && ((type->base == LY_TYPE_IDENT) || (type->base == LY_TYPE_INST))) {
-                /* remember the original value and try if it can be transformed into JSON format */
-                xml->content = leaf->value_str;
-                leaf->value_str = transform_xml2json(leaf->schema->module->ctx, xml->content, xml, 0);
-                if (!leaf->value_str) {
-                    leaf->value_str = xml->content;
-                    xml->content = NULL;
-                    found = 0;
-                    continue;
-                }
-            }
-
-            if (!lyp_parse_value_type(leaf, type, xml, resolve, dflt)) {
-                /* success */
-                break;
-            }
-
-            if (xml && ((type->base == LY_TYPE_IDENT) || (type->base == LY_TYPE_INST))) {
-                lydict_remove(leaf->schema->module->ctx, leaf->value_str);
-                leaf->value_str = xml->content;
-                xml->content = NULL;
-            }
-
-        }
-
-        /* erase information about errors - they are false or irrelevant
-         * and will be replaced by a single error messages */
-        ly_err_clean(1);
-        ly_vlog_hide(0);
-
-        if (!type) {
-            /* failure */
-            LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, (leaf->value_str ? leaf->value_str : ""), leaf->schema->name);
-            return EXIT_FAILURE;
-        }
-    } else {
-        memset(&leaf->value, 0, sizeof leaf->value);
-        if (lyp_parse_value_type(leaf, stype, xml, resolve, dflt)) {
-            return EXIT_FAILURE;
-        }
-    }
-
-    return EXIT_SUCCESS;
-}
-
 /* does not log, cannot fail */
 struct lys_type *
 lyp_get_next_union_type(struct lys_type *type, struct lys_type *prev_type, int *found)
diff --git a/src/parser.h b/src/parser.h
index 6bfb0f8..5dbde36 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -62,9 +62,9 @@
 
 struct lys_type *lyp_get_next_union_type(struct lys_type *type, struct lys_type *prev_type, int *found);
 
-int lyp_parse_value(struct lyd_node_leaf_list *leaf, struct lyxml_elem *xml, int resolve, int dflt);
-int lyp_parse_value_type(struct lyd_node_leaf_list *node, struct lys_type *stype, struct lyxml_elem *xml, int resolve,
-                         int dflt);
+struct lys_type *lyp_parse_value(struct lys_type *type, const char **value_, struct lyxml_elem *xml,
+                                         struct lyd_node *tree, struct lyd_node_leaf_list *leaf, int resolvable,
+                                         int dflt);
 
 int lyp_check_length_range(const char *expr, struct lys_type *type);
 
diff --git a/src/parser_json.c b/src/parser_json.c
index 52d33f0..f8898fe 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -428,16 +428,16 @@
     struct lys_type *stype;
     struct ly_ctx *ctx;
     unsigned int len = 0, r;
-    int resolve;
+    int resolvable;
     char *str;
 
     assert(leaf && data);
     ctx = leaf->schema->module->ctx;
 
     if (options & (LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
-        resolve = 0;
+        resolvable = 0;
     } else {
-        resolve = 1;
+        resolvable = 1;
     }
 
     stype = &((struct lys_node_leaf *)leaf->schema)->type;
@@ -508,7 +508,10 @@
         return 0;
     }
 
-    if (lyp_parse_value(leaf, NULL, resolve, 0)) {
+    /* the value is here converted to a JSON format if needed in case of LY_TYPE_IDENT and LY_TYPE_INST or to a
+     * canonical form of the value */
+    if (!lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, &leaf->value_str, NULL, NULL, leaf,
+                         resolvable, 0)) {
         ly_errno = LY_EVALID;
         return 0;
     }
diff --git a/src/parser_xml.c b/src/parser_xml.c
index b0f3e98..5cf454a 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -78,22 +78,19 @@
 xml_get_value(struct lyd_node *node, struct lyxml_elem *xml, int options, int editbits)
 {
     struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node;
-    int resolve;
+    int resolvable;
 
     assert(node && (node->schema->nodetype & (LYS_LEAFLIST | LYS_LEAF)) && xml);
 
+    if (options & (LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
+        resolvable = 0;
+    } else {
+        resolvable = 1;
+    }
+
     leaf->value_str = xml->content;
     xml->content = NULL;
 
-    /* will be changed in case of union */
-    leaf->value_type = ((struct lys_node_leaf *)node->schema)->type.base;
-
-    if (options & (LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
-        resolve = 0;
-    } else {
-        resolve = 1;
-    }
-
     if ((editbits & 0x10) && (node->schema->nodetype & LYS_LEAF) && (!leaf->value_str || !leaf->value_str[0])) {
         /* we have edit-config leaf/leaf-list with delete operation and no (empty) value,
          * this is not a bug since the node is just used as a kind of selection node */
@@ -101,20 +98,10 @@
         return EXIT_SUCCESS;
     }
 
-    if ((leaf->value_type == LY_TYPE_IDENT) || (leaf->value_type == LY_TYPE_INST)) {
-        /* convert the path from the XML form using XML namespaces into the JSON format
-         * using module names as namespaces
-         */
-        xml->content = leaf->value_str;
-        leaf->value_str = transform_xml2json(leaf->schema->module->ctx, xml->content, xml, 1);
-        lydict_remove(leaf->schema->module->ctx, xml->content);
-        xml->content = NULL;
-        if (!leaf->value_str) {
-            return EXIT_FAILURE;
-        }
-    }
-
-    if (lyp_parse_value(leaf, xml, resolve, 0)) {
+    /* the value is here converted to a JSON format if needed in case of LY_TYPE_IDENT and LY_TYPE_INST or to a
+     * canonical form of the value */
+    if (!lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, &leaf->value_str, xml, NULL, leaf,
+                         resolvable, 0)) {
         return EXIT_FAILURE;
     }
 
diff --git a/src/printer_json.c b/src/printer_json.c
index aa6498f..938523a 100644
--- a/src/printer_json.c
+++ b/src/printer_json.c
@@ -135,7 +135,7 @@
         break;
 
     case LY_TYPE_LEAFREF:
-        type = lyd_leaf_type(leaf);
+        type = lyd_leaf_type(leaf, 1);
         if (!type) {
             /* error */
             ly_print(out, "\"(!error!)\"");
diff --git a/src/resolve.c b/src/resolve.c
index 612e7b9..f809ca0 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -3054,12 +3054,8 @@
                 *value = dflt;
             }
         }
-
-    } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
-        /* it was converted to JSON format before, nothing else sensible we can do */
-
     } else {
-        if (lyp_parse_value(&node, NULL, 1, 1)) {
+        if (!lyp_parse_value(&((struct lys_node_leaf *)node.schema)->type, &node.value_str, NULL, NULL, &node, 1, 1)) {
             ret = -1;
             if (base_tpdf) {
                 /* default value is defined in some base typedef */
@@ -4048,7 +4044,7 @@
  *
  * @return Matching node or NULL if no such a node exists. If error occurs, NULL is returned and ly_errno is set.
  */
-static struct lyd_node *
+struct lyd_node *
 resolve_instid(struct lyd_node *data, const char *path)
 {
     int i = 0, j;
@@ -5049,7 +5045,7 @@
  *
  * @param[in] type Identityref type.
  * @param[in] ident_name Identityref name.
- * @param[in] node Node where the identityref is being resolved
+ * @param[in] node Node where the identityref is being resolved, if NULL the logging is switched off
  *
  * @return Pointer to the identity resolvent, NULL on error.
  */
@@ -5067,10 +5063,14 @@
 
     rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
     if (rc < 1) {
-        LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
+        if (node) {
+            LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
+        }
         return NULL;
     } else if (rc < (signed)strlen(ident_name)) {
-        LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
+        if (node) {
+            LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
+        }
         return NULL;
     }
 
@@ -5099,15 +5099,19 @@
         type = &type->der->type;
     }
 
-    LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
+    if (node) {
+        LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
+    }
     return NULL;
 
 match:
     for (i = 0; i < cur->iffeature_size; i++) {
         if (!resolve_iffeature(&cur->iffeature[i])) {
-            LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
-            LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity \"%s\" is disabled by its if-feature condition.",
-                   cur->name);
+            if (node) {
+                LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
+                LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity \"%s\" is disabled by its if-feature condition.",
+                       cur->name);
+            }
             return NULL;
         }
     }
@@ -6627,15 +6631,11 @@
     }
 }
 
-static int
+int
 resolve_leafref(struct lyd_node_leaf_list *leaf, struct lys_type *type)
 {
     struct unres_data matches;
-    struct lyd_node_leaf_list *dummy, *cmp;
     uint32_t i;
-    int rc;
-    struct lys_type *stype;
-    struct ly_ctx *ctx = leaf->schema->module->ctx; /* shortcut */
 
     assert(type->base == LY_TYPE_LEAFREF);
 
@@ -6649,72 +6649,15 @@
 
     /* check that value matches */
     for (i = 0; i < matches.count; ++i) {
-        cmp = (struct lyd_node_leaf_list *)matches.node[i]; /* shortcut */
-        switch (cmp->value_type) {
-        case LY_TYPE_STRING:
-        case LY_TYPE_BOOL:
-        case LY_TYPE_ENUM:
-        case LY_TYPE_BINARY:
-        case LY_TYPE_IDENT:
-        case LY_TYPE_INST:
-        case LY_TYPE_EMPTY:
-            /* canonical representation is the same as lexical ... */
-        case LY_TYPE_UNION:
-        case LY_TYPE_LEAFREF:
-            /* ... or we cannot resolve it */
-simplecmp:
-            if (ly_strequal(leaf->value_str, cmp->value_str, 1)) {
-                leaf->value.leafref = matches.node[i];
-                goto done;
-            }
-            break;
-        default:
-            /* in other case, get the canonical form of the value via a dummy node */
-            stype = (struct lys_type *)lyd_leaf_type(cmp);
-            if (!stype) {
-                /* try simple comparison */
-                goto simplecmp;
-            }
-            dummy = calloc(1, sizeof *dummy);
-            dummy->schema = cmp->schema;
-            dummy->value_type = cmp->value_type;
-            dummy->value_str = lydict_insert(ctx, leaf->value_str, 0);
-            /* parse the value according to the possible type */
-            rc = lyp_parse_value_type(dummy, stype, NULL, 0, 0);
-            if (!rc) {
-                /* success - try to compare the canonical forms */
-                if (ly_strequal(dummy->value_str, cmp->value_str, 1)) {
-                    /* replace leafref value with its canonical form */
-                    leaf->value.leafref = matches.node[i];
-                    lydict_remove(ctx, leaf->value_str);
-                    leaf->value_str = dummy->value_str;
-                } else {
-                    rc = -1;
-                }
-            }
-            if (rc) {
-                /* failure - remove duplicate leaf value */
-                lydict_remove(ctx, dummy->value_str);
-            }
-
-            /* cleanup - dummy */
-            if (dummy->value_type == LY_TYPE_BITS) {
-                free(dummy->value.bit);
-            }
-            free(dummy);
-
-            if (!rc) {
-                /* success - stop the loop */
-                goto done;
-            } else if (rc > 0) {
-                /* conversion to canonical form failed, try simple comparison of the current value */
-                goto simplecmp;
-            }
+        /* not that the value is already in canonical form since the parsers does the conversion,
+         * so we can simply compare just the values */
+        if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
+            /* we have the match */
+            leaf->value.leafref = matches.node[i];
             break;
         }
     }
 
-done:
     free(matches.node);
 
     if (!leaf->value.leafref) {
@@ -6731,133 +6674,31 @@
 }
 
 API const struct lys_type *
-lyd_leaf_type(const struct lyd_node_leaf_list *leaf)
+lyd_leaf_type(struct lyd_node_leaf_list *leaf, int resolve)
 {
-    struct lyd_node *node;
-    struct lys_type *type, *type_iter;
-    lyd_val value;
-    int f = 0, r;
-
     if (!leaf || !(leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
         return NULL;
     }
 
-    /* init */
-    type = &((struct lys_node_leaf *)leaf->schema)->type;
-    value = leaf->value;
-    ly_vlog_hide(1);
-
-    /* resolve until we get the real data type */
-    while (1) {
-        /* get the correct data type from schema */
-        switch (type->base) {
-        case LY_TYPE_LEAFREF:
-            type = &type->info.lref.target->type;
-            break; /* continue in while loop */
-        case LY_TYPE_UNION:
-            type_iter = NULL;
-            while ((type_iter = lyp_get_next_union_type(type, type_iter, &f))) {
-                if (type_iter->base == LY_TYPE_LEAFREF) {
-                    if (type_iter->info.lref.req == -1) {
-                        /* target not required, so it always succeeds */
-                        break;
-                    } else {
-                        /* try to resolve leafref */
-                        memset(&((struct lyd_node_leaf_list *)leaf)->value, 0, sizeof leaf->value);
-                        r = resolve_leafref((struct lyd_node_leaf_list *)leaf, type_iter);
-                        /* revert leaf's content affected by resolve_leafref */
-                        ((struct lyd_node_leaf_list *)leaf)->value = value;
-                        if (!r) {
-                            /* success, we can continue with the leafref type */
-                            break;
-                        }
-                    }
-                } else if (type_iter->base == LY_TYPE_INST) {
-                    if (type_iter->info.inst.req == -1) {
-                        /* target not required, so it always succeeds */
-                        return type_iter;
-                    } else {
-                        /* try to resolve instance-identifier */
-                        ly_err_clean(1);
-                        node = resolve_instid((struct lyd_node *)leaf, leaf->value_str);
-                        if (!ly_errno && node) {
-                            /* the real type is instance-identifier */
-                            return type_iter;
-                        }
-                    }
-                } else {
-                    r = lyp_parse_value_type((struct lyd_node_leaf_list *)leaf, type_iter, NULL, 1, 0);
-                    /* revert leaf's content affected by resolve_leafref */
-                    if (leaf->value_type == LY_TYPE_BITS) {
-                        if (leaf->value.bit) {
-                            free(leaf->value.bit);
-                        }
-                    }
-                    ((struct lyd_node_leaf_list *)leaf)->value = value;
-                    if (!r) {
-                        /* we have the real type */
-                        return type_iter;
-                    }
-                }
-                f = 0;
-            }
-            /* erase ly_errno and ly_vecode */
-            ly_err_clean(1);
-
-            if (!type_iter) {
-                LOGERR(LY_EINVAL, "Unable to get type from union \"%s\" with no valid type.", type->parent->name)
-                return NULL;
-            }
-            type = type_iter;
-            break;
-        default:
-            /* we have the real type */
-            ly_vlog_hide(0);
-            return type;
-        }
+    if (((struct lys_node_leaf *)leaf->schema)->type.base == LY_TYPE_BITS) {
+        free(leaf->value.bit);
     }
+    memset(&leaf->value, 0, sizeof leaf->value);
 
-    ly_vlog_hide(0);
-    return NULL;
+    /* resolve */
+    return lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, (const char **)&leaf->value_str, NULL,
+                           (struct lyd_node *)leaf, resolve ? leaf : NULL, 1, 0);
 }
 
 static int
 resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type)
 {
     struct lys_type *datatype = NULL;
-    int f = 0;
 
     assert(type->base == LY_TYPE_UNION);
 
     memset(&leaf->value, 0, sizeof leaf->value);
-    while ((datatype = lyp_get_next_union_type(type, datatype, &f))) {
-        leaf->value_type = datatype->base;
-
-        if (datatype->base == LY_TYPE_LEAFREF) {
-            /* try to resolve leafref */
-            if (!resolve_leafref(leaf, datatype)) {
-                /* success */
-                break;
-            }
-        } else if (datatype->base == LY_TYPE_INST) {
-            /* try to resolve instance-identifier */
-            ly_err_clean(1);
-            leaf->value.instance = resolve_instid((struct lyd_node *)leaf, leaf->value_str);
-            if (!ly_errno && (leaf->value.instance || datatype->info.inst.req == -1)) {
-                /* success */
-                break;
-            }
-        } else {
-            if (!lyp_parse_value_type(leaf, datatype, NULL, 1, 0)) {
-                /* success */
-                break;
-            }
-        }
-        f = 0;
-    }
-    /* erase ly_errno and ly_vecode */
-    ly_err_clean(1);
-
+    datatype = lyp_parse_value(type, &leaf->value_str, NULL, (struct lyd_node *)leaf, leaf, 1, 0);
     if (!datatype) {
         /* failure */
         LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, (leaf->value_str ? leaf->value_str : ""), leaf->schema->name);
diff --git a/src/resolve.h b/src/resolve.h
index c2b9796..a1bf21f 100644
--- a/src/resolve.h
+++ b/src/resolve.h
@@ -175,6 +175,8 @@
 int resolve_applies_must(const struct lyd_node *node);
 
 struct lys_ident *resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node);
+struct lyd_node *resolve_instid(struct lyd_node *data, const char *path);
+int resolve_leafref(struct lyd_node_leaf_list *leaf, struct lys_type *type);
 
 int resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres);
 
diff --git a/src/tree_data.c b/src/tree_data.c
index f3eed6d..411a879 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -692,8 +692,9 @@
     }
 
     /* resolve the type correctly (after it was connected to parent cause of log) */
-    if (lyp_parse_value((struct lyd_node_leaf_list *)ret, NULL, 1, 0)) {
-        lyd_free((struct lyd_node *)ret);
+    if (!lyp_parse_value(&((struct lys_node_leaf *)ret->schema)->type, &((struct lyd_node_leaf_list *)ret)->value_str,
+                         NULL, NULL, (struct lyd_node_leaf_list *)ret, 1, 0)) {
+        lyd_free(ret);
         return NULL;
     }
 
@@ -741,6 +742,7 @@
     lyd_val backup_val;
     struct lyd_node *parent;
     struct lys_node_list *slist;
+    LY_DATA_TYPE backup_type;
     uint32_t i;
 
     if (!leaf) {
@@ -765,17 +767,21 @@
     }
 
     backup = leaf->value_str;
+    backup_type = leaf->value_type;
     memcpy(&backup_val, &leaf->value, sizeof backup);
     leaf->value_str = lydict_insert(leaf->schema->module->ctx, val_str ? val_str : "", 0);
     /* leaf->value is erased by lyp_parse_value() */
 
-    /* resolve the type correctly */
-    if (lyp_parse_value(leaf, NULL, 1, 0)) {
+    /* resolve the type correctly, makes the value canonical if needed */
+    if (!lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, &leaf->value_str, NULL, NULL, leaf, 1, 0)) {
         lydict_remove(leaf->schema->module->ctx, leaf->value_str);
         leaf->value_str = backup;
         memcpy(&leaf->value, &backup_val, sizeof backup);
         return EXIT_FAILURE;
     }
+    if (backup_type == LY_TYPE_BITS) {
+        free(backup_val.bit);
+    }
 
     /* value is correct, remove backup */
     lydict_remove(leaf->schema->module->ctx, backup);
diff --git a/src/tree_data.h b/src/tree_data.h
index 0cd6842..e2861e2 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -1151,9 +1151,12 @@
  * representation so it is not #LY_TYPE_UNION neither #LY_TYPE_LEAFREF.
  *
  * @param[in] leaf The leaf/leaf-list node to be examined.
+ * @param[in] resolve Flag to store the leaf's value as its value data, in this case the value is resolved in the data
+ *            tree. Otherwise the data tree is not checked, so e.g. leafref type can be returned even if the value
+ *            does not match any target value in the data tree.
  * @return Pointer to the type definition of the \p leaf.
  */
-const struct lys_type *lyd_leaf_type(const struct lyd_node_leaf_list *leaf);
+const struct lys_type *lyd_leaf_type(struct lyd_node_leaf_list *leaf, int resolve);
 
 /**@} */
 
diff --git a/src/validation.c b/src/validation.c
index cc61b01..d2192e2 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -72,7 +72,8 @@
              * target's type, because the target leaf does not need to be present */
             if (leaf->value_type == LY_TYPE_LEAFREF || leaf->value_type == LY_TYPE_INST) {
                 memset(&leaf->value, 0, sizeof leaf->value);
-                if (lyp_parse_value_type(leaf, &((struct lys_node_leaf *)leaf->schema)->type, NULL, 0, 0)) {
+                if (!lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, &leaf->value_str, NULL,
+                                     (struct lyd_node *)node, leaf, 0, 0)) {
                     return EXIT_FAILURE;
                 }
             }
diff --git a/tests/api/test_tree_data.c b/tests/api/test_tree_data.c
index 0ea8831..5572d7b 100644
--- a/tests/api/test_tree_data.c
+++ b/tests/api/test_tree_data.c
@@ -1589,19 +1589,19 @@
 
     data = lyd_parse_mem(ctx, xml1, LYD_XML, LYD_OPT_CONFIG);
     assert_ptr_not_equal(data, NULL);
-    assert_int_equal(lyd_leaf_type((struct lyd_node_leaf_list *)data->child->prev)->base, LY_TYPE_STRING);
+    assert_int_equal(lyd_leaf_type((struct lyd_node_leaf_list *)data->child->prev, 1)->base, LY_TYPE_STRING);
     lyd_free_withsiblings(data);
 
     data = lyd_parse_mem(ctx, xml2, LYD_XML, LYD_OPT_CONFIG);
     assert_ptr_not_equal(data, NULL);
-    assert_int_equal(lyd_leaf_type((struct lyd_node_leaf_list *)data->child->prev)->base, LY_TYPE_ENUM);
+    assert_int_equal(lyd_leaf_type((struct lyd_node_leaf_list *)data->child->prev, 1)->base, LY_TYPE_ENUM);
     lyd_free_withsiblings(data);
 
     /* Use trusted flag to avoid getting error on parsing since 'ssh' is invalid value */
     data = lyd_parse_mem(ctx, xml3, LYD_XML, LYD_OPT_CONFIG | LYD_OPT_TRUSTED);
     assert_ptr_not_equal(data, NULL);
-    assert_int_equal(lyd_leaf_type((struct lyd_node_leaf_list *)data->child->prev), NULL);
-    assert_string_equal(ly_errmsg(), "Unable to get type from union \"u\" with no valid type.");
+    assert_int_equal(lyd_leaf_type((struct lyd_node_leaf_list *)data->child->prev, 1), NULL);
+    assert_string_equal(ly_errmsg(), "Invalid value \"ssh\" in \"u\" element.");
     lyd_free_withsiblings(data);
 }
 
diff --git a/tests/schema/test_typedef.c b/tests/schema/test_typedef.c
index 5fe6365..bde226e 100644
--- a/tests/schema/test_typedef.c
+++ b/tests/schema/test_typedef.c
@@ -250,12 +250,12 @@
 
     root = lyd_parse_mem(st->ctx, data1, LYD_XML, LYD_OPT_CONFIG);
     assert_ptr_equal(root, NULL);
-    assert_string_equal(ly_errmsg(), "Failed to resolve identityref \"des\".");
+    assert_string_equal(ly_errmsg(), "Invalid value \"des\" in \"l2\" element.");
     assert_string_equal(ly_errpath(), "/x:l2");
 
     root = lyd_parse_mem(st->ctx, data2, LYD_XML, LYD_OPT_CONFIG);
     assert_ptr_equal(root, NULL);
-    assert_string_equal(ly_errmsg(), "Failed to resolve identityref \"des3\".");
+    assert_string_equal(ly_errmsg(), "Invalid value \"des3\" in \"l2\" element.");
     assert_string_equal(ly_errpath(), "/x:l2");
 
     root = lyd_parse_mem(st->ctx, data3, LYD_XML, LYD_OPT_CONFIG);
@@ -290,12 +290,12 @@
 
     root = lyd_parse_mem(st->ctx, data1, LYD_XML, LYD_OPT_CONFIG);
     assert_ptr_equal(root, NULL);
-    assert_string_equal(ly_errmsg(), "Failed to resolve identityref \"des\".");
+    assert_string_equal(ly_errmsg(), "Invalid value \"des\" in \"l2\" element.");
     assert_string_equal(ly_errpath(), "/x:l2");
 
     root = lyd_parse_mem(st->ctx, data2, LYD_XML, LYD_OPT_CONFIG);
     assert_ptr_equal(root, NULL);
-    assert_string_equal(ly_errmsg(), "Failed to resolve identityref \"des3\".");
+    assert_string_equal(ly_errmsg(), "Invalid value \"des3\" in \"l2\" element.");
     assert_string_equal(ly_errpath(), "/x:l2");
 
     root = lyd_parse_mem(st->ctx, data3, LYD_XML, LYD_OPT_CONFIG);