data types FEATURE support for union types in data
diff --git a/src/plugins_types.c b/src/plugins_types.c
index 30ab278..7445972 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -1308,7 +1308,7 @@
  * Implementation of the ly_clb_resolve_prefix.
  */
 static const struct lys_module *
-ly_type_store_instanceid_get_prefix(struct ly_ctx *UNUSED(ctx), const char *prefix, size_t prefix_len, void *private)
+ly_type_stored_prefixes_clb(struct ly_ctx *UNUSED(ctx), const char *prefix, size_t prefix_len, void *private)
 {
     struct lyd_value_prefix *prefixes = (struct lyd_value_prefix*)private;
     unsigned int u;
@@ -1348,7 +1348,7 @@
 
     type = ((struct lysc_node_leaf*)key)->type;
     pred->value->plugin = type->plugin;
-    ret = type->plugin->store(ctx, type, val, val_len, options, ly_type_store_instanceid_get_prefix, prefixes, format, key, NULL,
+    ret = type->plugin->store(ctx, type, val, val_len, options, ly_type_stored_prefixes_clb, prefixes, format, key, NULL,
                               pred->value, NULL, &err);
     if (ret == LY_EINCOMPLETE) {
         /* actually expected success without complete data */
@@ -1408,7 +1408,7 @@
 static LY_ERR
 ly_type_store_instanceid(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
                          ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
-                         const void *context_node, const struct lyd_node **trees,
+                         const void *UNUSED(context_node), const struct lyd_node **trees,
                          struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     LY_ERR ret = LY_EVALID;
@@ -1430,13 +1430,16 @@
     /* init */
     *err = NULL;
 
-    if (options & LY_TYPE_OPTS_SECOND_CALL) {
+    if ((options & LY_TYPE_OPTS_SECOND_CALL) && (options & LY_TYPE_OPTS_STORE)) {
         /* the second run, the first one ended with LY_EINCOMPLETE, but we have prepared the target structure */
 
-        if (!lyd_target(((struct lyd_node_term*)context_node)->value.target, trees)) {
+        if (!lyd_target(storage->target, trees)) {
             /* TODO print instance-identifier */
             asprintf(&errmsg, "Invalid instance-identifier \"%s\" value - required instance not found.",
                      "TODO");
+            /* we have to clean up the storage */
+            type->plugin->free(ctx, type, storage);
+
             goto error;
         }
         return LY_SUCCESS;
@@ -2086,6 +2089,162 @@
     realtype->plugin->free(ctx, realtype, value);
 }
 
+/**
+ * @brief Validate, canonize and store value of the YANG built-in union type.
+ *
+ * Implementation of the ly_type_store_clb.
+ */
+static LY_ERR
+ly_type_store_union(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+                    ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
+                    const void *context_node, const struct lyd_node **trees,
+                    struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
+{
+    LY_ERR ret;
+    unsigned int u;
+    struct lysc_type_union *type_u = (struct lysc_type_union*)type;
+    struct lyd_value_subvalue *subvalue;
+    int secondcall = 0;
+    char *errmsg = NULL;
+
+    if ((options & LY_TYPE_OPTS_SECOND_CALL) && (options & LY_TYPE_OPTS_STORE)) {
+        subvalue = storage->subvalue;
+        /* standalone second_call flag - the options flag can be removed, but we need information
+         * about the second call to avoid rewriting the canonized value */
+        secondcall = 1;
+
+        /* get u of the used type to call the store callback second time, if it fails
+         * we are continuing with another type in row, anyway now we should have the data */
+        LY_ARRAY_FOR(type_u->types, u) {
+            if (type_u->types[u] == subvalue->type) {
+                goto search_subtype;
+            }
+        }
+    } else {
+        /* prepare subvalue storage */
+        subvalue = calloc(1, sizeof *subvalue);
+        subvalue->value = calloc(1, sizeof *subvalue->value);
+
+        /* store prefixes for later use */
+        subvalue->prefixes = ly_type_get_prefixes(ctx, value, value_len, get_prefix, parser);
+
+        /* use the first usable sybtype to store the value */
+        LY_ARRAY_FOR(type_u->types, u) {
+            subvalue->value->plugin = type_u->types[u]->plugin;
+            subvalue->type = type_u->types[u];
+
+search_subtype:
+            ret = type_u->types[u]->plugin->store(ctx, type_u->types[u], value, value_len, options & ~(LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_DYNAMIC),
+                                                  ly_type_stored_prefixes_clb, subvalue->prefixes, format,
+                                                  context_node, trees, subvalue->value, NULL, err);
+            if (ret == LY_SUCCESS || ret == LY_EINCOMPLETE) {
+                /* success (or not yet complete) */
+                break;
+            }
+
+            if (options & LY_TYPE_OPTS_SECOND_CALL) {
+                /* if started as LY_TYPE_OPTS_SECOND_CALL, we need it just for a single call of the
+                 * store callback, because if it fails, another store callback is called for the first time */
+                options = options & ~LY_TYPE_OPTS_SECOND_CALL;
+            }
+            if (*err) {
+                ly_err_free(*err);
+                *err = NULL;
+            }
+        }
+    }
+    if (u == LY_ARRAY_SIZE(type_u->types)) {
+        asprintf(&errmsg, "Invalid union value \"%.*s\" - no matching subtype found.", (int)value_len, value);
+        goto error;
+    }
+    /* success */
+
+    if (!secondcall) {
+        if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
+            if (options & LY_TYPE_OPTS_DYNAMIC) {
+                ly_type_store_canonized(ctx, options, lydict_insert_zc(ctx, (char*)value), storage, canonized);
+                value = NULL;
+            } else {
+                ly_type_store_canonized(ctx, options, lydict_insert(ctx, value_len ? value : "", value_len), storage, canonized);
+            }
+        }
+
+        if (options & LY_TYPE_OPTS_DYNAMIC) {
+            free((char*)value);
+        }
+    }
+
+    if (options & LY_TYPE_OPTS_STORE) {
+        storage->subvalue = subvalue;
+    } else {
+        LY_ARRAY_FOR(subvalue->prefixes, u) {
+            lydict_remove(ctx, subvalue->prefixes[u].prefix);
+        }
+        LY_ARRAY_FREE(subvalue->prefixes);
+        free(subvalue->value);
+        free(subvalue);
+    }
+
+    return ret;
+
+error:
+
+    if (!*err) {
+        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+    }
+    LY_ARRAY_FOR(subvalue->prefixes, u) {
+        lydict_remove(ctx, subvalue->prefixes[u].prefix);
+    }
+    LY_ARRAY_FREE(subvalue->prefixes);
+    free(subvalue->value);
+    free(subvalue);
+    if ((options & LY_TYPE_OPTS_SECOND_CALL) && (options & LY_TYPE_OPTS_STORE)) {
+        subvalue = NULL;
+    }
+
+    return LY_EVALID;
+}
+
+/**
+ * @brief Comparison callback checking the union value.
+ *
+ * Implementation of the ly_type_compare_clb.
+ */
+static LY_ERR
+ly_type_compare_union(const struct lyd_value *val1, const struct lyd_value *val2)
+{
+    if (val1->subvalue->type != val2->subvalue->type) {
+        return LY_EVALID;
+    }
+    return val1->subvalue->type->plugin->compare(val1->subvalue->value, val2->subvalue->value);
+}
+
+/**
+ * @brief Free value of the YANG built-in union type.
+ *
+ * Implementation of the ly_type_free_clb.
+ */
+static void
+ly_type_free_union(struct ly_ctx *ctx, struct lysc_type *type, struct lyd_value *value)
+{
+    unsigned int u;
+
+    if (value->subvalue) {
+        if (value->subvalue->value) {
+            value->subvalue->value->plugin->free(ctx, value->subvalue->type, value->subvalue->value);
+            LY_ARRAY_FOR(value->subvalue->prefixes, u) {
+                lydict_remove(ctx, value->subvalue->prefixes[u].prefix);
+            }
+            LY_ARRAY_FREE(value->subvalue->prefixes);
+            free(value->subvalue->value);
+        }
+        free(value->subvalue);
+        value->subvalue = NULL;
+    }
+    ly_type_free_canonical(ctx, type, value);
+}
+
+
 struct lysc_type_plugin ly_builtin_type_plugins[LY_DATA_TYPE_COUNT] = {
     {0}, /* LY_TYPE_UNKNOWN */
     {.type = LY_TYPE_BINARY, .store = ly_type_store_binary, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
@@ -2102,7 +2261,7 @@
     {.type = LY_TYPE_IDENT, .store = ly_type_store_identityref, .compare = ly_type_compare_identityref, .free = ly_type_free_canonical},
     {.type = LY_TYPE_INST, .store = ly_type_store_instanceid, .compare = ly_type_compare_instanceid, .free = ly_type_free_instanceid},
     {.type = LY_TYPE_LEAFREF, .store = ly_type_store_leafref, .compare = ly_type_compare_leafref, .free = ly_type_free_leafref},
-    {0}, /* TODO LY_TYPE_UNION */
+    {.type = LY_TYPE_UNION, .store = ly_type_store_union, .compare = ly_type_compare_union, .free = ly_type_free_union},
     {.type = LY_TYPE_INT8, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
     {.type = LY_TYPE_INT16, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
     {.type = LY_TYPE_INT32, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
diff --git a/src/tree_data.h b/src/tree_data.h
index 060f869..242ffa1 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -177,10 +177,15 @@
         struct lysc_type_bitenum_item *enum_item;  /**< pointer to the definition of the enumeration value */
         struct lysc_type_bitenum_item **bits_items; /**< list of set pointers to the specification of the set bits ([sized array](@ref sizedarrays)) */
         struct lysc_ident *ident;    /**< pointer to the schema definition of the identityref value */
-        struct lyd_value_prefix {
-            const char *prefix;           /**< prefix string used in the canonized string to identify the mod of the YANG schema */
-            const struct lys_module *mod; /**< YANG schema module identified by the prefix string */
-        } *prefixes;                 /**< list of mappings between prefix in canonized value to a YANG schema ([sized array](@ref sizedarrays)) */
+
+        struct lyd_value_subvalue {
+            struct lyd_value_prefix {
+                const char *prefix;           /**< prefix string used in the canonized string to identify the mod of the YANG schema */
+                const struct lys_module *mod; /**< YANG schema module identified by the prefix string */
+            } *prefixes;                 /**< list of mappings between prefix in canonized value to a YANG schema ([sized array](@ref sizedarrays)) */
+            struct lysc_type *type;
+            struct lyd_value *value;
+        } *subvalue;
 
         struct lyd_value_path {
             const struct lysc_node *node;
diff --git a/src/xml.c b/src/xml.c
index b5af06f..95b0e64 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -249,7 +249,7 @@
     for (u = context->ns.count - 1; u + 1 > 0; --u) {
         ns = (struct lyxml_ns *)context->ns.objs[u];
         if (prefix && prefix_len) {
-            if (!strncmp(prefix, ns->prefix, prefix_len) && ns->prefix[prefix_len] == '\0') {
+            if (ns->prefix && !strncmp(prefix, ns->prefix, prefix_len) && ns->prefix[prefix_len] == '\0') {
                 return ns;
             }
         } else if (!ns->prefix) {