data tree REFACTOR unify value prefix storing

Opaque nodes and attributes were using their own
format, which was unified with others.
diff --git a/src/parser_json.c b/src/parser_json.c
index d2794ad..7ccf92b 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -280,69 +280,6 @@
 }
 
 /**
- * @brief Go through the @p value and find all possible prefixes and store them in @p val_prefs_p [sized array](@ref sizedarrays).
- *
- * @param[in] ctx libyang context
- * @param[in] value Pointer to the beginning of the value to check.
- * @param[in] value_len Length of the string to examine in @p value.
- * @param[out] val_prefs_p Pointer to the resulting [sized array](@ref sizedarrays) of found prefixes. NULL in case there are no prefixes.
- * @return LY_EMEM on memory allocation failure.
- * @return LY_SUCCESS on success, empty @p val_prefs_p (NULL) is valid result if there are no possible prefixes
- */
-static LY_ERR
-lydjson_get_value_prefixes(const struct ly_ctx *ctx, const char *value, size_t value_len, struct ly_prefix **val_prefs_p)
-{
-    LY_ERR ret;
-    LY_ARRAY_COUNT_TYPE u;
-    uint32_t c;
-    const char *start, *stop;
-    struct ly_prefix *prefixes = NULL;
-    size_t len;
-
-    for (stop = start = value; (size_t)(stop - value) < value_len; start = stop) {
-        size_t bytes;
-        ly_getutf8(&stop, &c, &bytes);
-        if (is_yangidentstartchar(c)) {
-            for (ly_getutf8(&stop, &c, &bytes);
-                    is_yangidentchar(c) && (size_t)(stop - value) < value_len;
-                    ly_getutf8(&stop, &c, &bytes)) {}
-            stop = stop - bytes;
-            if (*stop == ':') {
-                /* we have a possible prefix */
-                struct ly_prefix *p = NULL;
-
-                len = stop - start;
-
-                /* check whether we do not already have this prefix stored */
-                LY_ARRAY_FOR(prefixes, u) {
-                    if (!ly_strncmp(prefixes[u].id, start, len)) {
-                        p = &prefixes[u];
-                        break;
-                    }
-                }
-                if (!p) {
-                    LY_ARRAY_NEW_GOTO(ctx, prefixes, p, ret, error);
-                    LY_CHECK_GOTO(ret = lydict_insert(ctx, start, len, &p->id), error);
-                    LY_CHECK_GOTO(ret = lydict_insert(ctx, start, len, &p->module_name), error);
-                } /* else the prefix already present */
-            }
-            stop = stop + bytes;
-        }
-    }
-
-    *val_prefs_p = prefixes;
-    return LY_SUCCESS;
-
-error:
-    LY_ARRAY_FOR(prefixes, u) {
-        lydict_remove(ctx, prefixes[u].id);
-        lydict_remove(ctx, prefixes[u].module_name);
-    }
-    LY_ARRAY_FREE(prefixes);
-    return ret;
-}
-
-/**
  * @brief Check that the input data are parseable as the @p list.
  *
  * Checks for all the list's keys. Function does not revert the context state.
@@ -604,15 +541,8 @@
                 LY_LIST_FOR(meta_container->child, meta_iter) {
                     /* convert opaq node to a attribute of the opaq node */
                     struct lyd_node_opaq *meta = (struct lyd_node_opaq *)meta_iter;
-                    struct ly_prefix *val_prefs = NULL;
-                    ly_bool dynamic = 0;
-
-                    /* get value prefixes */
-                    LY_CHECK_GOTO(ret = lydjson_get_value_prefixes(lydctx->jsonctx->ctx, lydctx->jsonctx->value,
-                            lydctx->jsonctx->value_len, &val_prefs), cleanup);
-
                     ret = lyd_create_attr(node, NULL, lydctx->jsonctx->ctx, meta->name, strlen(meta->name), meta->value,
-                            ly_strlen(meta->value), &dynamic, LYD_JSON, meta->hints, val_prefs, meta->prefix.id,
+                            ly_strlen(meta->value), NULL, LY_PREF_JSON, meta->hints, NULL, meta->prefix.id,
                             ly_strlen(meta->prefix.id), meta->prefix.module_name, ly_strlen(meta->prefix.module_name));
                     LY_CHECK_GOTO(ret, cleanup);
                 }
@@ -838,18 +768,15 @@
             lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_options);
         } else {
             /* create attribute */
-            struct ly_prefix *val_prefs = NULL;
             const char *module_name;
             size_t module_name_len;
 
             lydjson_get_node_prefix(node, prefix, prefix_len, &module_name, &module_name_len);
 
-            /* get value prefixes */
-            LY_CHECK_GOTO(ret = lydjson_get_value_prefixes(lydctx->jsonctx->ctx, lydctx->jsonctx->value, lydctx->jsonctx->value_len, &val_prefs), cleanup);
-
             /* attr2 is always changed to the created attribute */
-            ret = lyd_create_attr(node, NULL, lydctx->jsonctx->ctx, name, name_len, lydctx->jsonctx->value, lydctx->jsonctx->value_len,
-                    &lydctx->jsonctx->dynamic, LYD_JSON, 0, val_prefs, prefix, prefix_len, module_name, module_name_len);
+            ret = lyd_create_attr(node, NULL, lydctx->jsonctx->ctx, name, name_len, lydctx->jsonctx->value,
+                    lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic, LY_PREF_JSON, 0, NULL, prefix, prefix_len,
+                    module_name, module_name_len);
             LY_CHECK_GOTO(ret, cleanup);
         }
         /* next member */
@@ -937,7 +864,6 @@
     LY_ERR ret = LY_SUCCESS;
     const char *value = NULL, *module_name;
     size_t value_len = 0, module_name_len = 0;
-    struct ly_prefix *val_prefs = NULL;
     ly_bool dynamic = 0;
     uint32_t type_hint = 0;
 
@@ -949,17 +875,12 @@
         lydctx->jsonctx->dynamic = 0;
 
         LY_CHECK_RET(lydjson_value_type_hint(lydctx, status_inner_p, &type_hint));
-
-        if (value) {
-            /* get value prefixes */
-            LY_CHECK_RET(lydjson_get_value_prefixes(lydctx->jsonctx->ctx, value, value_len, &val_prefs));
-        }
     }
 
     /* create node */
     lydjson_get_node_prefix((struct lyd_node *)parent, prefix, prefix_len, &module_name, &module_name_len);
-    ret = lyd_create_opaq(lydctx->jsonctx->ctx, name, name_len, value, value_len, &dynamic, LYD_JSON, type_hint,
-            val_prefs, prefix, prefix_len, module_name, module_name_len, node_p);
+    ret = lyd_create_opaq(lydctx->jsonctx->ctx, name, name_len, value, value_len, &dynamic, LY_PREF_JSON, type_hint,
+            NULL, prefix, prefix_len, module_name, module_name_len, node_p);
     if (dynamic) {
         free((char *)value);
     }
@@ -1519,11 +1440,11 @@
     /* now the notificationContent is expected, which will be parsed by the caller */
 
     /* create notification envelope */
-    ret = lyd_create_opaq(jsonctx->ctx, "notification", 12, "", 0, NULL, LYD_JSON, LYD_NODEHINT_ENVELOPE, NULL, NULL,
+    ret = lyd_create_opaq(jsonctx->ctx, "notification", 12, "", 0, NULL, LY_PREF_JSON, LYD_NODEHINT_ENVELOPE, NULL, NULL,
             0, "ietf-restconf", 13, envp_p);
     LY_CHECK_GOTO(ret, cleanup);
     /* create notification envelope */
-    ret = lyd_create_opaq(jsonctx->ctx, "eventTime", 9, value, value_len, &dynamic, LYD_JSON, LYD_VALHINT_STRING, NULL,
+    ret = lyd_create_opaq(jsonctx->ctx, "eventTime", 9, value, value_len, &dynamic, LY_PREF_JSON, LYD_VALHINT_STRING, NULL,
             NULL, 0, "ietf-restconf", 13, &et);
     LY_CHECK_GOTO(ret, cleanup);
     /* insert eventTime into notification */
@@ -1664,7 +1585,7 @@
     LY_CHECK_GOTO(*status != LYJSON_OBJECT, cleanup);
 
     /* create the object envelope */
-    ret = lyd_create_opaq(jsonctx->ctx, object_id, strlen(object_id), "", 0, NULL, LYD_JSON, LYD_NODEHINT_ENVELOPE,
+    ret = lyd_create_opaq(jsonctx->ctx, object_id, strlen(object_id), "", 0, NULL, LY_PREF_JSON, LYD_NODEHINT_ENVELOPE,
             NULL, NULL, 0, module_key, ly_strlen(module_key), envp_p);
     LY_CHECK_GOTO(ret, cleanup);
 
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index 412c8fa..f2f27b0 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -35,6 +35,7 @@
 #include "tree_data_internal.h"
 #include "tree_schema.h"
 #include "validation.h"
+#include "xml.h"
 
 void
 lylyb_ctx_free(struct lylyb_ctx *ctx)
@@ -410,42 +411,64 @@
 }
 
 /**
- * @brief Parse opaque prefixes structure.
+ * @brief Parse format-specific prefix data.
  *
  * @param[in] lybctx LYB context.
- * @param[out] prefs Parsed prefixes.
+ * @param[in] format Prefix data format.
+ * @param[out] prefix_data Parsed prefix data.
  * @return LY_ERR value.
  */
 static LY_ERR
-lyb_parse_opaq_prefixes(struct lylyb_ctx *lybctx, struct ly_prefix **prefs)
+lyb_parse_prefix_data(struct lylyb_ctx *lybctx, LY_PREFIX_FORMAT format, void **prefix_data)
 {
     LY_ERR ret = LY_SUCCESS;
     uint8_t count, i;
-    char *str;
+    struct ly_set *set = NULL;
+    struct lyxml_ns *ns = NULL;
 
-    /* read count */
-    lyb_read(&count, 1, lybctx);
-    if (!count) {
-        return LY_SUCCESS;
-    }
+    switch (format) {
+    case LY_PREF_XML:
+        /* read count */
+        lyb_read(&count, 1, lybctx);
+        if (!count) {
+            return LY_SUCCESS;
+        }
 
-    LY_ARRAY_CREATE_RET(lybctx->ctx, *prefs, count, LY_EMEM);
-    for (i = 0; i < count; ++i) {
-        LY_ARRAY_INCREMENT(*prefs);
+        /* read all NS elements */
+        LY_CHECK_GOTO(ret = ly_set_new(&set), cleanup);
 
-        /* prefix */
-        LY_CHECK_GOTO(ret = lyb_read_string(&str, 1, lybctx), cleanup);
-        LY_CHECK_GOTO(ret = lydict_insert_zc(lybctx->ctx, str, &(*prefs)[i].id), cleanup);
+        for (i = 0; i < count; ++i) {
+            ns = calloc(1, sizeof *ns);
 
-        /* module reference is the same as JSON name */
-        LY_CHECK_GOTO(ret = lyb_read_string(&str, 1, lybctx), cleanup);
-        LY_CHECK_GOTO(ret = lydict_insert_zc(lybctx->ctx, str, &(*prefs)[i].module_name), cleanup);
+            /* prefix */
+            LY_CHECK_GOTO(ret = lyb_read_string(&ns->prefix, 1, lybctx), cleanup);
+
+            /* namespace */
+            LY_CHECK_GOTO(ret = lyb_read_string(&ns->uri, 1, lybctx), cleanup);
+
+            LY_CHECK_GOTO(ret = ly_set_add(set, ns, 1, NULL), cleanup);
+            ns = NULL;
+        }
+
+        *prefix_data = set;
+        break;
+    case LY_PREF_JSON:
+        /* nothing stored */
+        break;
+    default:
+        LOGINT(lybctx->ctx);
+        ret = LY_EINT;
+        break;
     }
 
 cleanup:
     if (ret) {
-        ly_free_val_prefs(lybctx->ctx, *prefs);
-        *prefs = NULL;
+        ly_free_prefix_data(format, set);
+        if (ns) {
+            free(ns->prefix);
+            free(ns->uri);
+            free(ns);
+        }
     }
     return ret;
 }
@@ -465,8 +488,8 @@
     struct lyd_attr *attr2;
     char *prefix = NULL, *module_name = NULL, *name = NULL, *value = NULL;
     ly_bool dynamic = 0;
-    LYD_FORMAT format = 0;
-    struct ly_prefix *val_prefs = NULL;
+    LY_PREFIX_FORMAT format = 0;
+    void *val_prefix_data = NULL;
 
     /* read count */
     lyb_read(&count, 1, lybctx);
@@ -496,21 +519,21 @@
         ret = lyb_read_string(&name, 1, lybctx);
         LY_CHECK_GOTO(ret, cleanup);
 
-        /* value prefixes */
-        ret = lyb_parse_opaq_prefixes(lybctx, &val_prefs);
-        LY_CHECK_GOTO(ret, cleanup);
-
         /* format */
         lyb_read((uint8_t *)&format, 1, lybctx);
 
+        /* value prefixes */
+        ret = lyb_parse_prefix_data(lybctx, format, &val_prefix_data);
+        LY_CHECK_GOTO(ret, cleanup);
+
         /* value */
         ret = lyb_read_string(&value, 0, lybctx);
-        LY_CHECK_ERR_GOTO(ret, ly_free_val_prefs(lybctx->ctx, val_prefs), cleanup);
+        LY_CHECK_ERR_GOTO(ret, ly_free_prefix_data(format, val_prefix_data), cleanup);
         dynamic = 1;
 
         /* attr2 is always changed to the created attribute */
         ret = lyd_create_attr(NULL, &attr2, lybctx->ctx, name, strlen(name), value, ly_strlen(value), &dynamic, format,
-                0, val_prefs, prefix, ly_strlen(prefix), module_name, ly_strlen(module_name));
+                0, val_prefix_data, prefix, ly_strlen(prefix), module_name, ly_strlen(module_name));
         LY_CHECK_GOTO(ret, cleanup);
 
         free(prefix);
@@ -682,11 +705,11 @@
     const struct lysc_node *snode = NULL;
     struct lyd_meta *meta = NULL, *m;
     struct lyd_attr *attr = NULL, *a;
-    struct ly_prefix *val_prefs = NULL;
     LYD_ANYDATA_VALUETYPE value_type;
     char *value = NULL, *name = NULL, *prefix = NULL, *module_key = NULL;
     ly_bool dynamic = 0;
-    LYD_FORMAT format = 0;
+    LY_PREFIX_FORMAT format = 0;
+    void *val_prefix_data = NULL;
     uint32_t prev_lo, flags;
     const struct ly_ctx *ctx = lybctx->lybctx->ctx;
 
@@ -738,21 +761,21 @@
         ret = lyb_read_string(&name, 1, lybctx->lybctx);
         LY_CHECK_GOTO(ret, cleanup);
 
-        /* parse value prefixes */
-        ret = lyb_parse_opaq_prefixes(lybctx->lybctx, &val_prefs);
-        LY_CHECK_GOTO(ret, cleanup);
-
         /* parse format */
         lyb_read((uint8_t *)&format, 1, lybctx->lybctx);
 
+        /* parse value prefixes */
+        ret = lyb_parse_prefix_data(lybctx->lybctx, format, &val_prefix_data);
+        LY_CHECK_GOTO(ret, cleanup);
+
         /* parse value */
         ret = lyb_read_string(&value, 0, lybctx->lybctx);
-        LY_CHECK_ERR_GOTO(ret, ly_free_val_prefs(ctx, val_prefs), cleanup);
+        LY_CHECK_ERR_GOTO(ret, ly_free_prefix_data(format, val_prefix_data), cleanup);
         dynamic = 1;
 
         /* create node */
-        ret = lyd_create_opaq(ctx, name, strlen(name), value, strlen(value), &dynamic, format, 0, val_prefs, prefix,
-                ly_strlen(prefix), module_key, ly_strlen(module_key), &node);
+        ret = lyd_create_opaq(ctx, name, strlen(name), value, strlen(value), &dynamic, format, 0, val_prefix_data,
+                prefix, ly_strlen(prefix), module_key, ly_strlen(module_key), &node);
         LY_CHECK_GOTO(ret, cleanup);
 
         /* process children */
diff --git a/src/parser_xml.c b/src/parser_xml.c
index e19b86f..69a8354 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -142,7 +142,8 @@
 {
     LY_ERR ret = LY_SUCCESS;
     const struct lyxml_ns *ns;
-    struct ly_prefix *val_prefs;
+    void *val_prefix_data;
+    LY_PREFIX_FORMAT format;
     struct lyd_attr *attr2;
     const char *name, *prefix;
     size_t name_len, prefix_len;
@@ -178,12 +179,12 @@
         assert(xmlctx->status == LYXML_ATTR_CONTENT);
 
         /* get value prefixes */
-        LY_CHECK_GOTO(ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs), cleanup);
+        LY_CHECK_GOTO(ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
+                &xmlctx->ns, &format, &val_prefix_data), cleanup);
 
         /* attr2 is always changed to the created attribute */
-        ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, xmlctx->value, xmlctx->value_len,
-                &xmlctx->dynamic, LYD_XML, 0, val_prefs, prefix, prefix_len,
-                ns ? ns->uri : NULL, ns ? strlen(ns->uri) : 0);
+        ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic,
+                format, 0, val_prefix_data, prefix, prefix_len, ns ? ns->uri : NULL, ns ? strlen(ns->uri) : 0);
         LY_CHECK_GOTO(ret, cleanup);
 
         if (!*attr) {
@@ -382,7 +383,8 @@
     struct lys_module *mod;
     uint32_t prev_opts;
     struct lyd_node *node = NULL, *anchor;
-    struct ly_prefix *val_prefs;
+    void *val_prefix_data;
+    LY_PREFIX_FORMAT format;
     uint32_t getnext_opts;
 
     xmlctx = lydctx->xmlctx;
@@ -464,16 +466,18 @@
         if (xmlctx->ws_only) {
             /* ignore WS-only value */
             xmlctx->value_len = 0;
-            val_prefs = NULL;
+            val_prefix_data = NULL;
+            format = LY_PREF_XML;
         } else {
             /* get value prefixes */
-            ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs);
+            ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
+                    &xmlctx->ns, &format, &val_prefix_data);
             LY_CHECK_GOTO(ret, error);
         }
 
         /* create node */
-        ret = lyd_create_opaq(ctx, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, LYD_XML,
-                LYD_HINT_DATA, val_prefs, prefix, prefix_len, ns->uri, strlen(ns->uri), &node);
+        ret = lyd_create_opaq(ctx, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format,
+                LYD_HINT_DATA, val_prefix_data, prefix, prefix_len, ns->uri, strlen(ns->uri), &node);
         LY_CHECK_GOTO(ret, error);
 
         /* parser next */
@@ -701,7 +705,7 @@
     LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
 
     /* create node */
-    ret = lyd_create_opaq(xmlctx->ctx, name, strlen(name), "", 0, NULL, LYD_XML, LYD_NODEHINT_ENVELOPE, NULL, prefix,
+    ret = lyd_create_opaq(xmlctx->ctx, name, strlen(name), "", 0, NULL, LY_PREF_XML, LYD_NODEHINT_ENVELOPE, NULL, prefix,
             prefix_len, uri, strlen(uri), envp);
     LY_CHECK_GOTO(ret, cleanup);
 
@@ -872,7 +876,7 @@
     }*/
 
     /* create node */
-    ret = lyd_create_opaq(xmlctx->ctx, "eventTime", 9, xmlctx->value, xmlctx->value_len, NULL, LYD_XML,
+    ret = lyd_create_opaq(xmlctx->ctx, "eventTime", 9, xmlctx->value, xmlctx->value_len, NULL, LY_PREF_XML,
             LYD_NODEHINT_ENVELOPE, NULL, prefix, prefix_len, ns->uri, strlen(ns->uri), &et);
     LY_CHECK_GOTO(ret, cleanup);
 
diff --git a/src/plugins_types.c b/src/plugins_types.c
index 8adf75b..0bb68fc 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -31,6 +31,7 @@
 #include "schema_compile.h"
 #include "set.h"
 #include "tree.h"
+#include "tree_data_internal.h"
 #include "tree_schema.h"
 #include "tree_schema_internal.h"
 #include "xml.h"
@@ -596,9 +597,6 @@
     }
 }
 
-static LY_ERR ly_type_union_store_prefix_data(const struct ly_ctx *ctx, const char *value, size_t value_len,
-        LY_PREFIX_FORMAT format, void *prefix_data, LY_PREFIX_FORMAT *format_p, void **prefix_data_p);
-
 API LY_ERR
 lysc_prefixes_compile(const char *str, size_t str_len, const struct lysp_module *prefix_mod, struct lysc_prefix **prefixes)
 {
@@ -607,15 +605,12 @@
 
     LY_CHECK_ARG_RET(NULL, prefix_mod, prefixes, LY_EINVAL);
 
-    ret = ly_type_union_store_prefix_data(prefix_mod->mod->ctx, str, str_len, LY_PREF_SCHEMA, (void *)prefix_mod, &format,
+    ret = ly_store_prefix_data(prefix_mod->mod->ctx, str, str_len, LY_PREF_SCHEMA, (void *)prefix_mod, &format,
             (void **)prefixes);
     assert(format == LY_PREF_SCHEMA_RESOLVED);
     return ret;
 }
 
-static LY_ERR ly_type_union_dup_prefix_data(const struct ly_ctx *ctx, LY_PREFIX_FORMAT format, const void *prefix_data,
-        void **prefix_data_p);
-
 API LY_ERR
 lysc_prefixes_dup(const struct lysc_prefix *orig, struct lysc_prefix **dup)
 {
@@ -627,15 +622,13 @@
         return LY_SUCCESS;
     }
 
-    return ly_type_union_dup_prefix_data(NULL, LY_PREF_SCHEMA_RESOLVED, orig, (void **)dup);
+    return ly_dup_prefix_data(NULL, LY_PREF_SCHEMA_RESOLVED, orig, (void **)dup);
 }
 
-static void ly_type_union_free_prefix_data(LY_PREFIX_FORMAT format, void *prefix_data);
-
 API void
 lysc_prefixes_free(struct lysc_prefix *prefixes)
 {
-    ly_type_union_free_prefix_data(LY_PREF_SCHEMA_RESOLVED, prefixes);
+    ly_free_prefix_data(LY_PREF_SCHEMA_RESOLVED, prefixes);
 }
 
 static int
@@ -2036,223 +2029,6 @@
     }
 }
 
-/**
- * @brief Free stored prefix data of a union.
- *
- * @param[in] format Format of the prefixes.
- * @param[in] prefix_data Prefix data to free.
- */
-static void
-ly_type_union_free_prefix_data(LY_PREFIX_FORMAT format, void *prefix_data)
-{
-    struct ly_set *ns_list;
-    struct lysc_prefix *prefixes;
-    uint32_t i;
-    LY_ARRAY_COUNT_TYPE u;
-
-    if (!prefix_data) {
-        return;
-    }
-
-    switch (format) {
-    case LY_PREF_XML:
-        ns_list = prefix_data;
-        for (i = 0; i < ns_list->count; ++i) {
-            free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
-            free(((struct lyxml_ns *)ns_list->objs[i])->uri);
-        }
-        ly_set_free(ns_list, free);
-        break;
-    case LY_PREF_SCHEMA_RESOLVED:
-        prefixes = prefix_data;
-        LY_ARRAY_FOR(prefixes, u) {
-            free(prefixes[u].prefix);
-        }
-        LY_ARRAY_FREE(prefixes);
-        break;
-    case LY_PREF_SCHEMA:
-    case LY_PREF_JSON:
-        break;
-    }
-}
-
-/**
- * @brief Duplicate prefix data of a union.
- *
- * @param[in] ctx libyang context.
- * @param[in] format Format of the prefixes in the value.
- * @param[in] prefix_data Prefix data to duplicate.
- * @param[out] prefix_data_p Duplicated prefix data.
- * @return LY_ERR value.
- */
-static LY_ERR
-ly_type_union_dup_prefix_data(const struct ly_ctx *ctx, LY_PREFIX_FORMAT format, const void *prefix_data,
-        void **prefix_data_p)
-{
-    LY_ERR ret = LY_SUCCESS;
-    struct lyxml_ns *ns;
-    struct lysc_prefix *prefixes = NULL, *orig_pref;
-    struct ly_set *ns_list, *orig_ns;
-    uint32_t i;
-    LY_ARRAY_COUNT_TYPE u;
-
-    assert(!*prefix_data_p);
-
-    switch (format) {
-    case LY_PREF_SCHEMA:
-        *prefix_data_p = (void *)prefix_data;
-        break;
-    case LY_PREF_SCHEMA_RESOLVED:
-        /* copy all the value prefixes */
-        orig_pref = (struct lysc_prefix *)prefix_data;
-        LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
-        *prefix_data_p = prefixes;
-
-        LY_ARRAY_FOR(orig_pref, u) {
-            if (orig_pref[u].prefix) {
-                prefixes[u].prefix = strdup(orig_pref[u].prefix);
-                LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
-            }
-            prefixes[u].mod = orig_pref[u].mod;
-            LY_ARRAY_INCREMENT(prefixes);
-        }
-        break;
-    case LY_PREF_XML:
-        /* copy all the namespaces */
-        LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
-        *prefix_data_p = ns_list;
-
-        orig_ns = (struct ly_set *)prefix_data;
-        for (i = 0; i < orig_ns->count; ++i) {
-            ns = calloc(1, sizeof *ns);
-            LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
-            LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
-
-            if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
-                ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
-                LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
-            }
-            ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
-            LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
-        }
-        break;
-    case LY_PREF_JSON:
-        assert(!prefix_data);
-        *prefix_data_p = NULL;
-        break;
-    }
-
-cleanup:
-    if (ret) {
-        ly_type_union_free_prefix_data(format, *prefix_data_p);
-        *prefix_data_p = NULL;
-    }
-    return ret;
-}
-
-/**
- * @brief Store used prefixes in a value of a union.
- *
- * @param[in] ctx libyang context.
- * @param[in] value Value string to be parsed.
- * @param[in] value_len Length of the @p value string.
- * @param[in] format Format of the prefixes in the value.
- * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
- * @param[out] format_p Resulting format of the prefixes.
- * @param[out] prefix_data_p Resulting prefix data for the value in format @p format_p.
- * @return LY_ERR value.
- */
-static LY_ERR
-ly_type_union_store_prefix_data(const struct ly_ctx *ctx, const char *value, size_t value_len, LY_PREFIX_FORMAT format,
-        void *prefix_data, LY_PREFIX_FORMAT *format_p, void **prefix_data_p)
-{
-    LY_ERR ret = LY_SUCCESS;
-    const char *start, *stop;
-    const struct lys_module *mod;
-    struct lyxml_ns *ns;
-    struct ly_set *ns_list;
-    struct lysc_prefix *prefixes = NULL, *val_pref;
-
-    switch (format) {
-    case LY_PREF_SCHEMA:
-    case LY_PREF_XML:
-        /* copy all referenced modules... */
-        if (format == LY_PREF_XML) {
-            /* ...as prefix - namespace pairs */
-            LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
-            *format_p = LY_PREF_XML;
-            *prefix_data_p = ns_list;
-        } else {
-            /* ...as prefix - module pairs */
-            assert(format == LY_PREF_SCHEMA);
-            LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
-            *format_p = LY_PREF_SCHEMA_RESOLVED;
-            *prefix_data_p = prefixes;
-        }
-
-        /* add all used prefixes */
-        for (stop = start = value; (size_t)(stop - value) < value_len; start = stop) {
-            size_t bytes;
-            uint32_t c;
-
-            ly_getutf8(&stop, &c, &bytes);
-            if (is_xmlqnamestartchar(c)) {
-                for (ly_getutf8(&stop, &c, &bytes);
-                        is_xmlqnamechar(c) && (size_t)(stop - value) < value_len;
-                        ly_getutf8(&stop, &c, &bytes)) {}
-                stop = stop - bytes;
-                if (*stop == ':') {
-                    /* we have a possible prefix */
-                    size_t len = stop - start;
-
-                    /* do we already have the prefix? */
-                    mod = ly_type_store_resolve_prefix(ctx, start, len, *format_p, *prefix_data_p);
-                    if (!mod) {
-                        mod = ly_type_store_resolve_prefix(ctx, start, len, format, prefix_data);
-                        if (mod) {
-                            if (*format_p == LY_PREF_XML) {
-                                /* store a new prefix - namespace pair */
-                                ns = calloc(1, sizeof *ns);
-                                LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
-                                LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
-
-                                ns->prefix = strndup(start, len);
-                                LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
-                                ns->uri = strdup(mod->ns);
-                                LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
-                            } else {
-                                assert(*format_p == LY_PREF_SCHEMA_RESOLVED);
-                                /* store a new prefix - module pair */
-                                LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
-                                *prefix_data_p = prefixes;
-
-                                val_pref->prefix = strndup(start, len);
-                                LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
-                                val_pref->mod = mod;
-                            }
-                        } /* else it is not even defined */
-                    } /* else the prefix is already present */
-                }
-                stop = stop + bytes;
-            }
-        }
-        break;
-    case LY_PREF_SCHEMA_RESOLVED:
-    case LY_PREF_JSON:
-        /* simply copy all the prefix data */
-        *format_p = format;
-        LY_CHECK_GOTO(ret = ly_type_union_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
-        break;
-    }
-
-cleanup:
-    if (ret) {
-        ly_type_union_free_prefix_data(*format_p, *prefix_data_p);
-        *prefix_data_p = NULL;
-    }
-    return ret;
-}
-
 static LY_ERR
 ly_type_union_store_type(const struct ly_ctx *ctx, struct lysc_type **types, struct lyd_value_subvalue *subvalue,
         ly_bool resolve, const struct lyd_node *ctx_node, const struct lyd_node *tree, struct ly_err_item **err)
@@ -2344,7 +2120,7 @@
     }
 
     /* store format-specific data for later prefix resolution */
-    ret = ly_type_union_store_prefix_data(ctx, subvalue->original, value_len, format, prefix_data, &subvalue->format,
+    ret = ly_store_prefix_data(ctx, subvalue->original, value_len, format, prefix_data, &subvalue->format,
             &subvalue->prefix_data);
     LY_CHECK_GOTO(ret, cleanup);
     subvalue->hints = hints;
@@ -2357,7 +2133,7 @@
 cleanup:
     if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
         lydict_remove(ctx, subvalue->original);
-        ly_type_union_free_prefix_data(subvalue->format, subvalue->prefix_data);
+        ly_free_prefix_data(subvalue->format, subvalue->prefix_data);
         free(subvalue);
     } else {
         /* store it as union, the specific type is in the subvalue, but canonical value is the specific type value */
@@ -2454,7 +2230,7 @@
     LY_CHECK_RET(lydict_insert(ctx, original->subvalue->original, strlen(original->subvalue->original),
             &dup->subvalue->original));
     dup->subvalue->format = original->subvalue->format;
-    LY_CHECK_RET(ly_type_union_dup_prefix_data(ctx, original->subvalue->format, original->subvalue->prefix_data,
+    LY_CHECK_RET(ly_dup_prefix_data(ctx, original->subvalue->format, original->subvalue->prefix_data,
             &dup->subvalue->prefix_data));
 
     dup->realtype = original->realtype;
@@ -2474,7 +2250,7 @@
         if (value->subvalue->value.realtype) {
             value->subvalue->value.realtype->plugin->free(ctx, &value->subvalue->value);
         }
-        ly_type_union_free_prefix_data(value->subvalue->format, value->subvalue->prefix_data);
+        ly_free_prefix_data(value->subvalue->format, value->subvalue->prefix_data);
         lydict_remove(ctx, value->subvalue->original);
         free(value->subvalue);
         value->subvalue = NULL;
diff --git a/src/printer_json.c b/src/printer_json.c
index cffe955..2bc64ad 100644
--- a/src/printer_json.c
+++ b/src/printer_json.c
@@ -159,16 +159,15 @@
         const struct lys_module *mod;
 
         switch (onode->format) {
-        case LYD_JSON:
+        case LY_PREF_JSON:
             return onode->prefix.module_name;
-        case LYD_XML:
+        case LY_PREF_XML:
             mod = ly_ctx_get_module_implemented_ns(onode->ctx, onode->prefix.module_ns);
             if (!mod) {
                 return NULL;
             }
             return mod->name;
-        case LYD_LYB:
-        case LYD_UNKNOWN:
+        default:
             /* cannot be created */
             LOGINT(LYD_CTX(node));
         }
@@ -290,7 +289,7 @@
  * @return LY_ERR value.
  */
 static LY_ERR
-json_print_member2(struct jsonpr_ctx *ctx, const struct lyd_node *parent, LYD_FORMAT format,
+json_print_member2(struct jsonpr_ctx *ctx, const struct lyd_node *parent, LY_PREFIX_FORMAT format,
         const struct ly_prefix *prefix, const char *name, ly_bool is_attr)
 {
     const char *module_name = NULL;
@@ -302,17 +301,16 @@
         const struct lys_module *mod;
 
         switch (format) {
-        case LYD_JSON:
+        case LY_PREF_JSON:
             module_name = prefix->module_name;
             break;
-        case LYD_XML:
+        case LY_PREF_XML:
             mod = ly_ctx_get_module_implemented_ns(ctx->ctx, prefix->module_ns);
             if (mod) {
                 module_name = mod->name;
             }
             break;
-        case LYD_LYB:
-        case LYD_UNKNOWN:
+        default:
             /* cannot be created */
             LOGINT_RET(ctx->ctx);
         }
@@ -466,7 +464,7 @@
 
     if (node->schema && node->meta) {
         if (inner) {
-            LY_CHECK_RET(json_print_member2(ctx, NULL, LYD_JSON, NULL, "", 1));
+            LY_CHECK_RET(json_print_member2(ctx, NULL, LY_PREF_JSON, NULL, "", 1));
         } else {
             LY_CHECK_RET(json_print_member(ctx, node, 1));
         }
@@ -478,7 +476,7 @@
         LEVEL_PRINTED;
     } else if (!node->schema && ((struct lyd_node_opaq *)node)->attr) {
         if (inner) {
-            LY_CHECK_RET(json_print_member2(ctx, NULL, LYD_JSON, NULL, "", 1));
+            LY_CHECK_RET(json_print_member2(ctx, NULL, LY_PREF_JSON, NULL, "", 1));
         } else {
             LY_CHECK_RET(json_print_member2(ctx, node, ((struct lyd_node_opaq *)node)->format,
                     &((struct lyd_node_opaq *)node)->prefix, ((struct lyd_node_opaq *)node)->name, 1));
diff --git a/src/printer_lyb.c b/src/printer_lyb.c
index 71bb1e5..bb5cc9e 100644
--- a/src/printer_lyb.c
+++ b/src/printer_lyb.c
@@ -35,6 +35,7 @@
 #include "tree_data_internal.h"
 #include "tree_schema.h"
 #include "tree_schema_internal.h"
+#include "xml.h"
 
 /**
  * @brief Hash table equal callback for checking hash equality only.
@@ -545,36 +546,54 @@
 }
 
 /**
- * @brief Print opaque prefixes.
+ * @brief Print prefix data.
  *
  * @param[in] out Out structure.
- * @param[in] prefs Prefixes to print.
+ * @param[in] format Value prefix format.
+ * @param[in] prefix_data Prefix data to print.
  * @param[in] lybctx LYB context.
  * @return LY_ERR value.
  */
 static LY_ERR
-lyb_print_opaq_prefixes(struct ly_out *out, const struct ly_prefix *prefs, struct lylyb_ctx *lybctx)
+lyb_print_prefix_data(struct ly_out *out, LY_PREFIX_FORMAT format, const void *prefix_data, struct lylyb_ctx *lybctx)
 {
-    uint8_t count;
-    LY_ARRAY_COUNT_TYPE u;
+    const struct ly_set *set;
+    const struct lyxml_ns *ns;
+    uint32_t i;
 
-    if (prefs && (LY_ARRAY_COUNT(prefs) > UINT8_MAX)) {
-        LOGERR(lybctx->ctx, LY_EINT, "Maximum supported number of prefixes is %u.", UINT8_MAX);
-        return LY_EINT;
-    }
+    switch (format) {
+    case LY_PREF_XML:
+        set = prefix_data;
+        if (!set) {
+            /* no prefix data */
+            i = 0;
+            LY_CHECK_RET(lyb_write(out, (uint8_t *)&i, 1, lybctx));
+            break;
+        }
+        if (set->count > UINT8_MAX) {
+            LOGERR(lybctx->ctx, LY_EINT, "Maximum supported number of prefixes is %u.", UINT8_MAX);
+            return LY_EINT;
+        }
 
-    count = prefs ? LY_ARRAY_COUNT(prefs) : 0;
+        /* write number of prefixes on 1 byte */
+        LY_CHECK_RET(lyb_write(out, (uint8_t *)&set->count, 1, lybctx));
 
-    /* write number of prefixes on 1 byte */
-    LY_CHECK_RET(lyb_write(out, &count, 1, lybctx));
+        /* write all the prefixes */
+        for (i = 0; i < set->count; ++i) {
+            ns = set->objs[i];
 
-    /* write all the prefixes */
-    LY_ARRAY_FOR(prefs, u) {
-        /* prefix */
-        LY_CHECK_RET(lyb_write_string(prefs[u].id, 0, 1, out, lybctx));
+            /* prefix */
+            LY_CHECK_RET(lyb_write_string(ns->prefix, 0, 1, out, lybctx));
 
-        /* namespace */
-        LY_CHECK_RET(lyb_write_string(prefs[u].module_name, 0, 1, out, lybctx));
+            /* namespace */
+            LY_CHECK_RET(lyb_write_string(ns->uri, 0, 1, out, lybctx));
+        }
+        break;
+    case LY_PREF_JSON:
+        /* nothing to print */
+        break;
+    default:
+        LOGINT_RET(lybctx->ctx);
     }
 
     return LY_SUCCESS;
@@ -600,12 +619,12 @@
     /* name */
     LY_CHECK_RET(lyb_write_string(opaq->name, 0, 1, out, lybctx));
 
-    /* value prefixes */
-    LY_CHECK_RET(lyb_print_opaq_prefixes(out, opaq->val_prefs, lybctx));
-
     /* format */
     LY_CHECK_RET(lyb_write_number(opaq->format, 1, out, lybctx));
 
+    /* value prefixes */
+    LY_CHECK_RET(lyb_print_prefix_data(out, opaq->format, opaq->val_prefix_data, lybctx));
+
     /* value */
     LY_CHECK_RET(lyb_write_string(opaq->value, 0, 0, out, lybctx));
 
@@ -788,12 +807,12 @@
         /* name */
         LY_CHECK_RET(lyb_write_string(iter->name, 0, 1, out, lybctx));
 
-        /* value prefixes */
-        LY_CHECK_RET(lyb_print_opaq_prefixes(out, iter->val_prefs, lybctx));
-
         /* format */
         LY_CHECK_RET(lyb_write_number(iter->format, 1, out, lybctx));
 
+        /* value prefixes */
+        LY_CHECK_RET(lyb_print_prefix_data(out, iter->format, iter->val_prefix_data, lybctx));
+
         /* value */
         LY_CHECK_RET(lyb_write_string(iter->value, 0, 0, out, lybctx));
 
diff --git a/src/printer_xml.c b/src/printer_xml.c
index 994496a..7108863 100644
--- a/src/printer_xml.c
+++ b/src/printer_xml.c
@@ -67,7 +67,7 @@
         if (!new_prefix) {
             /* find default namespace */
             if (!ctx->prefix.objs[i - 1]) {
-                if (ctx->ns.objs[i - 1] == ns) {
+                if (!strcmp(ctx->ns.objs[i - 1], ns)) {
                     /* matching default namespace */
                     return ctx->prefix.objs[i - 1];
                 }
@@ -76,7 +76,7 @@
             }
         } else {
             /* find prefixed namespace */
-            if (ctx->ns.objs[i - 1] == ns) {
+            if (!strcmp(ctx->ns.objs[i - 1], ns)) {
                 if (!ctx->prefix.objs[i - 1]) {
                     /* default namespace is not interesting */
                     continue;
@@ -105,13 +105,13 @@
 }
 
 static const char *
-xml_print_ns_opaq(struct xmlpr_ctx *ctx, LYD_FORMAT format, const struct ly_prefix *prefix, uint32_t prefix_opts)
+xml_print_ns_opaq(struct xmlpr_ctx *ctx, LY_PREFIX_FORMAT format, const struct ly_prefix *prefix, uint32_t prefix_opts)
 {
     switch (format) {
-    case LYD_XML:
+    case LY_PREF_XML:
         return xml_print_ns(ctx, prefix->module_ns, (prefix_opts & LYXML_PREFIX_DEFAULT) ? NULL : prefix->id, prefix_opts);
         break;
-    case LYD_JSON:
+    case LY_PREF_JSON:
         if (prefix->module_name) {
             const struct lys_module *mod = ly_ctx_get_module_latest(ctx->ctx, prefix->module_name);
             if (mod) {
@@ -119,8 +119,7 @@
             }
         }
         break;
-    case LYD_LYB:
-    case LYD_UNKNOWN:
+    default:
         /* cannot be created */
         LOGINT(ctx->ctx);
     }
@@ -128,6 +127,27 @@
     return NULL;
 }
 
+static void
+xml_print_ns_prefix_data(struct xmlpr_ctx *ctx, LY_PREFIX_FORMAT format, void *prefix_data, uint32_t prefix_opts)
+{
+    const struct ly_set *set;
+    const struct lyxml_ns *ns;
+    uint32_t i;
+
+    switch (format) {
+    case LY_PREF_XML:
+        set = prefix_data;
+        for (i = 0; i < set->count; ++i) {
+            ns = set->objs[i];
+            xml_print_ns(ctx, ns->uri, (prefix_opts & LYXML_PREFIX_DEFAULT) ? NULL : ns->prefix, prefix_opts);
+        }
+        break;
+    default:
+        /* cannot be created */
+        LOGINT(ctx->ctx);
+    }
+}
+
 /**
  * TODO
  */
@@ -240,7 +260,6 @@
 {
     const struct lyd_attr *attr;
     const char *pref;
-    LY_ARRAY_COUNT_TYPE u;
 
     LY_LIST_FOR(node->attr, attr) {
         pref = NULL;
@@ -250,10 +269,8 @@
         }
 
         /* print namespaces connected with the value's prefixes */
-        if (attr->val_prefs) {
-            LY_ARRAY_FOR(attr->val_prefs, u) {
-                xml_print_ns_opaq(ctx, attr->format, &attr->val_prefs[u], LYXML_PREFIX_REQUIRED);
-            }
+        if (attr->val_prefix_data) {
+            xml_print_ns_prefix_data(ctx, attr->format, attr->val_prefix_data, LYXML_PREFIX_REQUIRED);
         }
 
         /* print the attribute with its prefix and value */
@@ -437,16 +454,13 @@
 {
     LY_ERR ret;
     struct lyd_node *child;
-    LY_ARRAY_COUNT_TYPE u;
 
     LY_CHECK_RET(xml_print_opaq_open(ctx, node));
 
     if (node->value[0]) {
         /* print namespaces connected with the value's prefixes */
-        if (node->val_prefs) {
-            LY_ARRAY_FOR(node->val_prefs, u) {
-                xml_print_ns_opaq(ctx, node->format, &node->val_prefs[u], LYXML_PREFIX_REQUIRED);
-            }
+        if (node->val_prefix_data) {
+            xml_print_ns_prefix_data(ctx, node->format, node->val_prefix_data, LYXML_PREFIX_REQUIRED);
         }
 
         ly_print_(ctx->out, ">%s", node->value);
diff --git a/src/tree_data.c b/src/tree_data.c
index 2627811..e8b598d 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -668,7 +668,7 @@
 
 LY_ERR
 lyd_create_opaq(const struct ly_ctx *ctx, const char *name, size_t name_len, const char *value, size_t value_len,
-        ly_bool *dynamic, LYD_FORMAT format, uint32_t hints, struct ly_prefix *val_prefs, const char *prefix, size_t pref_len,
+        ly_bool *dynamic, LY_PREFIX_FORMAT format, uint32_t hints, void *val_prefix_data, const char *prefix, size_t pref_len,
         const char *module_key, size_t module_key_len, struct lyd_node **node)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -681,10 +681,10 @@
     }
 
     opaq = calloc(1, sizeof *opaq);
-    LY_CHECK_ERR_RET(!opaq, LOGMEM(ctx); ly_free_val_prefs(ctx, val_prefs), LY_EMEM);
+    LY_CHECK_ERR_RET(!opaq, LOGMEM(ctx); ly_free_prefix_data(format, val_prefix_data), LY_EMEM);
 
     opaq->prev = (struct lyd_node *)opaq;
-    opaq->val_prefs = val_prefs;
+    opaq->val_prefix_data = val_prefix_data;
     opaq->format = format;
     LY_CHECK_GOTO(ret = lydict_insert(ctx, name, name_len, &opaq->name), finish);
 
@@ -1014,7 +1014,7 @@
         value = "";
     }
 
-    LY_CHECK_RET(lyd_create_opaq(ctx, name, strlen(name), value, strlen(value), NULL, LYD_JSON, 0, NULL, NULL, 0,
+    LY_CHECK_RET(lyd_create_opaq(ctx, name, strlen(name), value, strlen(value), NULL, LY_PREF_JSON, 0, NULL, NULL, 0,
             module_name, strlen(module_name), &ret));
     if (parent) {
         lyd_insert_node(parent, NULL, ret);
@@ -1051,7 +1051,7 @@
         val_str = "";
     }
 
-    LY_CHECK_RET(lyd_create_attr(parent, &ret, ctx, name, name_len, val_str, strlen(val_str), NULL, LYD_JSON, 0, NULL,
+    LY_CHECK_RET(lyd_create_attr(parent, &ret, ctx, name, name_len, val_str, strlen(val_str), NULL, LY_PREF_JSON, 0, NULL,
             prefix, pref_len, module_name, module_name ? strlen(module_name) : 0));
 
     if (attr) {
@@ -1279,7 +1279,7 @@
             if (!(schema->flags & LYS_KEYLESS)) {
                 if ((options & LYD_NEW_PATH_OPAQ) && (p[path_idx].pred_type == LY_PATH_PREDTYPE_NONE)) {
                     /* creating opaque list without keys */
-                    LY_CHECK_GOTO(ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0, NULL, LYD_JSON,
+                    LY_CHECK_GOTO(ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0, NULL, LY_PREF_JSON,
                             LYD_NODEHINT_LIST, NULL, NULL, 0, schema->module->name, strlen(schema->module->name), &node),
                             cleanup);
                 } else {
@@ -1298,7 +1298,7 @@
         case LYS_LEAFLIST:
             if ((options & LYD_NEW_PATH_OPAQ) && (p[path_idx].pred_type == LY_PATH_PREDTYPE_NONE)) {
                 /* creating opaque leaf-list without value */
-                LY_CHECK_GOTO(ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0, NULL, LYD_JSON,
+                LY_CHECK_GOTO(ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0, NULL, LY_PREF_JSON,
                         LYD_NODEHINT_LEAFLIST, NULL, NULL, 0, schema->module->name, strlen(schema->module->name), &node),
                         cleanup);
             } else {
@@ -1321,9 +1321,8 @@
                 LY_CHECK_GOTO(ret, cleanup);
             } else {
                 /* creating opaque leaf without value */
-                LY_CHECK_GOTO(ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0, NULL, LYD_JSON,
-                        0, NULL, NULL, 0, schema->module->name,
-                        strlen(schema->module->name), &node), cleanup);
+                LY_CHECK_GOTO(ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0, NULL, LY_PREF_JSON,
+                        0, NULL, NULL, 0, schema->module->name, strlen(schema->module->name), &node), cleanup);
             }
             break;
         case LYS_ANYDATA:
@@ -2193,8 +2192,8 @@
 
 LY_ERR
 lyd_create_attr(struct lyd_node *parent, struct lyd_attr **attr, const struct ly_ctx *ctx, const char *name, size_t name_len,
-        const char *value, size_t value_len, ly_bool *dynamic, LYD_FORMAT format, uint32_t hints,
-        struct ly_prefix *val_prefs, const char *prefix, size_t prefix_len, const char *module_key, size_t module_key_len)
+        const char *value, size_t value_len, ly_bool *dynamic, LY_PREFIX_FORMAT format, uint32_t hints,
+        void *val_prefix_data, const char *prefix, size_t prefix_len, const char *module_key, size_t module_key_len)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyd_attr *at, *last;
@@ -2207,10 +2206,10 @@
     }
 
     at = calloc(1, sizeof *at);
-    LY_CHECK_ERR_RET(!at, LOGMEM(ctx); ly_free_val_prefs(ctx, val_prefs), LY_EMEM);
+    LY_CHECK_ERR_RET(!at, LOGMEM(ctx); ly_free_prefix_data(format, val_prefix_data), LY_EMEM);
     at->hints = hints;
     at->format = format;
-    at->val_prefs = val_prefs;
+    at->val_prefix_data = val_prefix_data;
 
     LY_CHECK_GOTO(ret = lydict_insert(ctx, name, name_len, &at->name), finish);
     if (dynamic && *dynamic) {
@@ -2290,19 +2289,18 @@
             return LY_ENOT;
         }
         switch (opaq1->format) {
-        case LYD_XML:
-            if (lyxml_value_compare(opaq1->value, opaq1->val_prefs, opaq2->value, opaq2->val_prefs)) {
+        case LY_PREF_XML:
+            if (lyxml_value_compare(LYD_CTX(node1), opaq1->value, opaq1->val_prefix_data, opaq2->value, opaq2->val_prefix_data)) {
                 return LY_ENOT;
             }
             break;
-        case LYD_JSON:
+        case LY_PREF_JSON:
             /* prefixes in JSON are unique, so it is not necessary to canonize the values */
             if (strcmp(opaq1->value, opaq2->value)) {
                 return LY_ENOT;
             }
             break;
-        case LYD_LYB:
-        case LYD_UNKNOWN:
+        default:
             /* not allowed */
             LOGINT(LYD_CTX(node1));
             return LY_EINT;
@@ -2483,7 +2481,6 @@
     struct lyd_node *dup = NULL;
     struct lyd_meta *meta;
     struct lyd_node_any *any;
-    LY_ARRAY_COUNT_TYPE u;
 
     LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
 
@@ -2547,13 +2544,9 @@
             LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), orig->prefix.id, 0, &opaq->prefix.id), error);
         }
         LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), orig->prefix.module_ns, 0, &opaq->prefix.module_ns), error);
-        if (orig->val_prefs) {
-            LY_ARRAY_CREATE_GOTO(LYD_CTX(node), opaq->val_prefs, LY_ARRAY_COUNT(orig->val_prefs), ret, error);
-            LY_ARRAY_FOR(orig->val_prefs, u) {
-                LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), orig->val_prefs[u].id, 0, &opaq->val_prefs[u].id), error);
-                LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), orig->val_prefs[u].module_ns, 0, &opaq->val_prefs[u].module_ns), error);
-                LY_ARRAY_INCREMENT(opaq->val_prefs);
-            }
+        if (orig->val_prefix_data) {
+            ret = ly_dup_prefix_data(LYD_CTX(node), opaq->format, orig->val_prefix_data, &opaq->val_prefix_data);
+            LY_CHECK_GOTO(ret, error);
         }
         LY_CHECK_GOTO(ret = lydict_insert(LYD_CTX(node), orig->value, 0, &opaq->value), error);
         opaq->ctx = orig->ctx;
diff --git a/src/tree_data.h b/src/tree_data.h
index e431940..0dbb3c7 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -492,12 +492,12 @@
  */
 struct lyd_attr {
     struct lyd_node_opaq *parent;   /**< data node where the attribute is placed */
-    struct lyd_attr *next;
-    struct ly_prefix *val_prefs;    /**< list of prefixes in the value ([sized array](@ref sizedarrays)) */
-    const char *name;
-    const char *value;
+    struct lyd_attr *next;          /**< pointer to the next attribute */
+    void *val_prefix_data;          /**< format-specific prefix data (see ::ly_resolve_prefix()) */
+    const char *name;               /**< attribute name */
+    const char *value;              /**< attribute value */
 
-    LYD_FORMAT format;              /**< format of the prefixes, only LYD_XML and LYD_JSON values can appear at this place */
+    LY_PREFIX_FORMAT format;        /**< format of the attribute and any prefixes, ::LY_PREF_XML or ::LY_PREF_JSON */
     uint32_t hints;                 /**< additional information about from the data source, see the [hints list](@ref lydhints) */
     struct ly_prefix prefix;        /**< name prefix, it is stored because they are a real pain to generate properly */
 
@@ -720,10 +720,10 @@
 #endif
 
     struct lyd_node *child;         /**< pointer to the child node (NULL if there are none) */
-    const char *name;
-    LYD_FORMAT format;
+    const char *name;               /**< node name */
+    LY_PREFIX_FORMAT format;        /**< format of the node and any prefixes, ::LY_PREF_XML or ::LY_PREF_JSON */
     struct ly_prefix prefix;        /**< name prefix */
-    struct ly_prefix *val_prefs;    /**< list of prefixes in the value ([sized array](@ref sizedarrays)) */
+    void *val_prefix_data;          /**< format-specific prefix data (see ::ly_resolve_prefix()) */
     const char *value;              /**< original value */
     uint32_t hints;                 /**< additional information about from the data source, see the [hints list](@ref lydhints) */
     const struct ly_ctx *ctx;       /**< libyang context */
diff --git a/src/tree_data_free.c b/src/tree_data_free.c
index 192f63e..fa9eab8 100644
--- a/src/tree_data_free.c
+++ b/src/tree_data_free.c
@@ -24,18 +24,6 @@
 #include "tree_data_internal.h"
 #include "tree_schema.h"
 
-void
-ly_free_val_prefs(const struct ly_ctx *ctx, struct ly_prefix *val_prefs)
-{
-    LY_ARRAY_COUNT_TYPE u;
-
-    LY_ARRAY_FOR(val_prefs, u) {
-        FREE_STRING(ctx, val_prefs[u].id);
-        FREE_STRING(ctx, val_prefs[u].module_ns);
-    }
-    LY_ARRAY_FREE(val_prefs);
-}
-
 static void
 lyd_free_meta(struct lyd_meta *meta, ly_bool siblings)
 {
@@ -127,7 +115,7 @@
         attr = iter;
         iter = iter->next;
 
-        ly_free_val_prefs(ctx, attr->val_prefs);
+        ly_free_prefix_data(attr->format, attr->val_prefix_data);
         FREE_STRING(ctx, attr->name);
         FREE_STRING(ctx, attr->value);
         FREE_STRING(ctx, attr->prefix.id);
@@ -174,7 +162,7 @@
         FREE_STRING(LYD_CTX(opaq), opaq->name);
         FREE_STRING(LYD_CTX(opaq), opaq->prefix.id);
         FREE_STRING(LYD_CTX(opaq), opaq->prefix.module_ns);
-        ly_free_val_prefs(LYD_CTX(opaq), opaq->val_prefs);
+        ly_free_prefix_data(opaq->format, opaq->val_prefix_data);
         FREE_STRING(LYD_CTX(opaq), opaq->value);
     } else if (node->schema->nodetype & LYD_NODE_INNER) {
         /* remove children hash table in case of inner data node */
diff --git a/src/tree_data_helpers.c b/src/tree_data_helpers.c
index 968dd87..2b1b5df 100644
--- a/src/tree_data_helpers.c
+++ b/src/tree_data_helpers.c
@@ -11,6 +11,8 @@
  *
  *     https://opensource.org/licenses/BSD-3-Clause
  */
+#define _XOPEN_SOURCE 500 /* strdup */
+#define _POSIX_C_SOURCE 200809L /*strndup */
 
 #include <assert.h>
 #include <stdint.h>
@@ -18,6 +20,7 @@
 #include <string.h>
 
 #include "common.h"
+#include "compat.h"
 #include "context.h"
 #include "dict.h"
 #include "hash_table.h"
@@ -400,3 +403,193 @@
 
     return 0;
 }
+
+void
+ly_free_prefix_data(LY_PREFIX_FORMAT format, void *prefix_data)
+{
+    struct ly_set *ns_list;
+    struct lysc_prefix *prefixes;
+    uint32_t i;
+    LY_ARRAY_COUNT_TYPE u;
+
+    if (!prefix_data) {
+        return;
+    }
+
+    switch (format) {
+    case LY_PREF_XML:
+        ns_list = prefix_data;
+        for (i = 0; i < ns_list->count; ++i) {
+            free(((struct lyxml_ns *)ns_list->objs[i])->prefix);
+            free(((struct lyxml_ns *)ns_list->objs[i])->uri);
+        }
+        ly_set_free(ns_list, free);
+        break;
+    case LY_PREF_SCHEMA_RESOLVED:
+        prefixes = prefix_data;
+        LY_ARRAY_FOR(prefixes, u) {
+            free(prefixes[u].prefix);
+        }
+        LY_ARRAY_FREE(prefixes);
+        break;
+    case LY_PREF_SCHEMA:
+    case LY_PREF_JSON:
+        break;
+    }
+}
+
+LY_ERR
+ly_dup_prefix_data(const struct ly_ctx *ctx, LY_PREFIX_FORMAT format, const void *prefix_data,
+        void **prefix_data_p)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct lyxml_ns *ns;
+    struct lysc_prefix *prefixes = NULL, *orig_pref;
+    struct ly_set *ns_list, *orig_ns;
+    uint32_t i;
+    LY_ARRAY_COUNT_TYPE u;
+
+    assert(!*prefix_data_p);
+
+    switch (format) {
+    case LY_PREF_SCHEMA:
+        *prefix_data_p = (void *)prefix_data;
+        break;
+    case LY_PREF_SCHEMA_RESOLVED:
+        /* copy all the value prefixes */
+        orig_pref = (struct lysc_prefix *)prefix_data;
+        LY_ARRAY_CREATE_GOTO(ctx, prefixes, LY_ARRAY_COUNT(orig_pref), ret, cleanup);
+        *prefix_data_p = prefixes;
+
+        LY_ARRAY_FOR(orig_pref, u) {
+            if (orig_pref[u].prefix) {
+                prefixes[u].prefix = strdup(orig_pref[u].prefix);
+                LY_CHECK_ERR_GOTO(!prefixes[u].prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
+            }
+            prefixes[u].mod = orig_pref[u].mod;
+            LY_ARRAY_INCREMENT(prefixes);
+        }
+        break;
+    case LY_PREF_XML:
+        /* copy all the namespaces */
+        LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
+        *prefix_data_p = ns_list;
+
+        orig_ns = (struct ly_set *)prefix_data;
+        for (i = 0; i < orig_ns->count; ++i) {
+            ns = calloc(1, sizeof *ns);
+            LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
+            LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
+
+            if (((struct lyxml_ns *)orig_ns->objs[i])->prefix) {
+                ns->prefix = strdup(((struct lyxml_ns *)orig_ns->objs[i])->prefix);
+                LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
+            }
+            ns->uri = strdup(((struct lyxml_ns *)orig_ns->objs[i])->uri);
+            LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
+        }
+        break;
+    case LY_PREF_JSON:
+        assert(!prefix_data);
+        *prefix_data_p = NULL;
+        break;
+    }
+
+cleanup:
+    if (ret) {
+        ly_free_prefix_data(format, *prefix_data_p);
+        *prefix_data_p = NULL;
+    }
+    return ret;
+}
+
+LY_ERR
+ly_store_prefix_data(const struct ly_ctx *ctx, const char *value, size_t value_len, LY_PREFIX_FORMAT format,
+        void *prefix_data, LY_PREFIX_FORMAT *format_p, void **prefix_data_p)
+{
+    LY_ERR ret = LY_SUCCESS;
+    const char *start, *stop;
+    const struct lys_module *mod;
+    struct lyxml_ns *ns;
+    struct ly_set *ns_list;
+    struct lysc_prefix *prefixes = NULL, *val_pref;
+
+    switch (format) {
+    case LY_PREF_SCHEMA:
+    case LY_PREF_XML:
+        /* copy all referenced modules... */
+        if (format == LY_PREF_XML) {
+            /* ...as prefix - namespace pairs */
+            LY_CHECK_GOTO(ret = ly_set_new(&ns_list), cleanup);
+            *format_p = LY_PREF_XML;
+            *prefix_data_p = ns_list;
+        } else {
+            /* ...as prefix - module pairs */
+            assert(format == LY_PREF_SCHEMA);
+            LY_ARRAY_CREATE_GOTO(ctx, prefixes, 0, ret, cleanup);
+            *format_p = LY_PREF_SCHEMA_RESOLVED;
+            *prefix_data_p = prefixes;
+        }
+
+        /* add all used prefixes */
+        for (stop = start = value; (size_t)(stop - value) < value_len; start = stop) {
+            size_t bytes;
+            uint32_t c;
+
+            ly_getutf8(&stop, &c, &bytes);
+            if (is_xmlqnamestartchar(c)) {
+                for (ly_getutf8(&stop, &c, &bytes);
+                        is_xmlqnamechar(c) && (size_t)(stop - value) < value_len;
+                        ly_getutf8(&stop, &c, &bytes)) {}
+                stop = stop - bytes;
+                if (*stop == ':') {
+                    /* we have a possible prefix */
+                    size_t len = stop - start;
+
+                    /* do we already have the prefix? */
+                    mod = ly_type_store_resolve_prefix(ctx, start, len, *format_p, *prefix_data_p);
+                    if (!mod) {
+                        mod = ly_type_store_resolve_prefix(ctx, start, len, format, prefix_data);
+                        if (mod) {
+                            if (*format_p == LY_PREF_XML) {
+                                /* store a new prefix - namespace pair */
+                                ns = calloc(1, sizeof *ns);
+                                LY_CHECK_ERR_GOTO(!ns, LOGMEM(ctx); ret = LY_EMEM, cleanup);
+                                LY_CHECK_GOTO(ret = ly_set_add(ns_list, ns, 1, NULL), cleanup);
+
+                                ns->prefix = strndup(start, len);
+                                LY_CHECK_ERR_GOTO(!ns->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
+                                ns->uri = strdup(mod->ns);
+                                LY_CHECK_ERR_GOTO(!ns->uri, LOGMEM(ctx); ret = LY_EMEM, cleanup);
+                            } else {
+                                assert(*format_p == LY_PREF_SCHEMA_RESOLVED);
+                                /* store a new prefix - module pair */
+                                LY_ARRAY_NEW_GOTO(ctx, prefixes, val_pref, ret, cleanup);
+                                *prefix_data_p = prefixes;
+
+                                val_pref->prefix = strndup(start, len);
+                                LY_CHECK_ERR_GOTO(!val_pref->prefix, LOGMEM(ctx); ret = LY_EMEM, cleanup);
+                                val_pref->mod = mod;
+                            }
+                        } /* else it is not even defined */
+                    } /* else the prefix is already present */
+                }
+                stop = stop + bytes;
+            }
+        }
+        break;
+    case LY_PREF_SCHEMA_RESOLVED:
+    case LY_PREF_JSON:
+        /* simply copy all the prefix data */
+        *format_p = format;
+        LY_CHECK_GOTO(ret = ly_dup_prefix_data(ctx, format, prefix_data, prefix_data_p), cleanup);
+        break;
+    }
+
+cleanup:
+    if (ret) {
+        ly_free_prefix_data(*format_p, *prefix_data_p);
+        *prefix_data_p = NULL;
+    }
+    return ret;
+}
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index a633873..e2e51f8 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -173,7 +173,7 @@
  * @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
  * @param[in] format Input format of @p value and @p ns.
  * @param[in] hints [Hints](@ref lydhints) from the parser regarding the node/value type.
- * @param[in] val_prefs Possible value prefixes, array is spent (even in case the function fails).
+ * @param[in] val_prefix_data Format-specific prefix data, param is spent (even in case the function fails).
  * @param[in] prefix Element prefix.
  * @param[in] pref_len Length of @p prefix, must be set correctly.
  * @param[in] module_key Mandatory key to reference module, can be namespace or name.
@@ -183,7 +183,7 @@
  * @return LY_ERR value if an error occurred.
  */
 LY_ERR lyd_create_opaq(const struct ly_ctx *ctx, const char *name, size_t name_len, const char *value, size_t value_len,
-        ly_bool *dynamic, LYD_FORMAT format, uint32_t hints, struct ly_prefix *val_prefs, const char *prefix,
+        ly_bool *dynamic, LY_PREFIX_FORMAT format, uint32_t hints, void *val_prefix_data, const char *prefix,
         size_t pref_len, const char *module_key, size_t module_key_len, struct lyd_node **node);
 
 /**
@@ -276,7 +276,7 @@
  * @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
  * @param[in] format Input format of @p value and @p ns.
  * @param[in] hints [Hints](@ref lydhints) from the parser regarding the node/value type.
- * @param[in] val_prefs Possible value prefixes, array is spent (even in case the function fails).
+ * @param[in] val_prefix_data Format-specific prefix data, param is spent (even in case the function fails).
  * @param[in] prefix Attribute prefix.
  * @param[in] prefix_len Attribute prefix length.
  * @param[in] module_key Mandatory key to reference module, can be namespace or name.
@@ -285,8 +285,8 @@
  * @return LY_ERR value on error.
  */
 LY_ERR lyd_create_attr(struct lyd_node *parent, struct lyd_attr **attr, const struct ly_ctx *ctx, const char *name,
-        size_t name_len, const char *value, size_t value_len, ly_bool *dynamic, LYD_FORMAT format, uint32_t hints,
-        struct ly_prefix *val_prefs, const char *prefix, size_t prefix_len, const char *module_key, size_t module_key_len);
+        size_t name_len, const char *value, size_t value_len, ly_bool *dynamic, LY_PREFIX_FORMAT format, uint32_t hints,
+        void *val_prefix_data, const char *prefix, size_t prefix_len, const char *module_key, size_t module_key_len);
 
 /**
  * @brief Store and canonize the given @p value into @p val according to the schema node type rules.
@@ -407,14 +407,6 @@
 void lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *when_check, struct lyd_meta **meta, uint32_t options);
 
 /**
- * @brief Free value prefixes.
- *
- * @param[in] ctx libyang context.
- * @param[in] val_prefis Value prefixes to free, sized array (@ref sizedarrays).
- */
-void ly_free_val_prefs(const struct ly_ctx *ctx, struct ly_prefix *val_prefs);
-
-/**
  * @brief Append all list key predicates to path.
  *
  * @param[in] node Node with keys to print.
@@ -426,4 +418,38 @@
  */
 LY_ERR lyd_path_list_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, ly_bool is_static);
 
+/**
+ * @brief Free stored prefix data.
+ *
+ * @param[in] format Format of the prefixes.
+ * @param[in] prefix_data Prefix data to free.
+ */
+void ly_free_prefix_data(LY_PREFIX_FORMAT format, void *prefix_data);
+
+/**
+ * @brief Duplicate prefix data.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] format Format of the prefixes in the value.
+ * @param[in] prefix_data Prefix data to duplicate.
+ * @param[out] prefix_data_p Duplicated prefix data.
+ * @return LY_ERR value.
+ */
+LY_ERR ly_dup_prefix_data(const struct ly_ctx *ctx, LY_PREFIX_FORMAT format, const void *prefix_data, void **prefix_data_p);
+
+/**
+ * @brief Store used prefixes in a value.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] value Value string to be parsed.
+ * @param[in] value_len Length of the @p value string.
+ * @param[in] format Format of the prefixes in the value.
+ * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
+ * @param[out] format_p Resulting format of the prefixes.
+ * @param[out] prefix_data_p Resulting prefix data for the value in format @p format_p.
+ * @return LY_ERR value.
+ */
+LY_ERR ly_store_prefix_data(const struct ly_ctx *ctx, const char *value, size_t value_len, LY_PREFIX_FORMAT format,
+        void *prefix_data, LY_PREFIX_FORMAT *format_p, void **prefix_data_p);
+
 #endif /* LY_TREE_DATA_INTERNAL_H_ */
diff --git a/src/xml.c b/src/xml.c
index 0a43388..516fe4b 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -1076,66 +1076,11 @@
 }
 
 LY_ERR
-lyxml_get_prefixes(struct lyxml_ctx *xmlctx, const char *value, size_t value_len, struct ly_prefix **val_prefs)
+lyxml_value_compare(const struct ly_ctx *ctx, const char *value1, void *val_prefix_data1, const char *value2,
+        void *val_prefix_data2)
 {
-    LY_ERR ret;
-    LY_ARRAY_COUNT_TYPE u;
-    uint32_t c;
-    const struct lyxml_ns *ns;
-    const char *start, *stop;
-    struct ly_prefix *prefixes = NULL;
-    size_t len;
-
-    for (stop = start = value; (size_t)(stop - value) < value_len; start = stop) {
-        size_t bytes;
-        ly_getutf8(&stop, &c, &bytes);
-        if (is_xmlqnamestartchar(c)) {
-            for (ly_getutf8(&stop, &c, &bytes);
-                    is_xmlqnamechar(c) && (size_t)(stop - value) < value_len;
-                    ly_getutf8(&stop, &c, &bytes)) {}
-            stop = stop - bytes;
-            if (*stop == ':') {
-                /* we have a possible prefix */
-                len = stop - start;
-                ns = lyxml_ns_get(&xmlctx->ns, start, len);
-                if (ns) {
-                    struct ly_prefix *p = NULL;
-
-                    /* check whether we do not already have this prefix stored */
-                    LY_ARRAY_FOR(prefixes, u) {
-                        if (!ly_strncmp(prefixes[u].id, start, len)) {
-                            p = &prefixes[u];
-                            break;
-                        }
-                    }
-                    if (!p) {
-                        LY_ARRAY_NEW_GOTO(xmlctx->ctx, prefixes, p, ret, error);
-                        LY_CHECK_GOTO(ret = lydict_insert(xmlctx->ctx, start, len, &p->id), error);
-                        LY_CHECK_GOTO(ret = lydict_insert(xmlctx->ctx, ns->uri, 0, &p->module_ns), error);
-                    } /* else the prefix already present */
-                }
-            }
-            stop = stop + bytes;
-        }
-    }
-
-    *val_prefs = prefixes;
-    return LY_SUCCESS;
-
-error:
-    LY_ARRAY_FOR(prefixes, u) {
-        lydict_remove(xmlctx->ctx, prefixes[u].id);
-        lydict_remove(xmlctx->ctx, prefixes[u].module_ns);
-    }
-    LY_ARRAY_FREE(prefixes);
-    return ret;
-}
-
-LY_ERR
-lyxml_value_compare(const char *value1, const struct ly_prefix *prefs1, const char *value2, const struct ly_prefix *prefs2)
-{
-    const char *ptr1, *ptr2, *ns1, *ns2;
-    LY_ARRAY_COUNT_TYPE u1, u2;
+    const char *ptr1, *ptr2, *end1, *end2;
+    const struct lys_module *mod1, *mod2;
 
     if (!value1 && !value2) {
         return LY_SUCCESS;
@@ -1149,38 +1094,24 @@
     while (ptr1[0] && ptr2[0]) {
         if (ptr1[0] != ptr2[0]) {
             /* it can be a start of prefix that maps to the same module */
-            size_t len;
-            ns1 = ns2 = NULL;
-            u1 = u2 = 0;
-            if (prefs1) {
+            mod1 = mod2 = NULL;
+            if (val_prefix_data1 && (end1 = strchr(ptr1, ':'))) {
                 /* find module of the first prefix, if any */
-                LY_ARRAY_FOR(prefs1, u1) {
-                    len = strlen(prefs1[u1].id);
-                    if (!strncmp(ptr1, prefs1[u1].id, len) && (ptr1[len] == ':')) {
-                        ns1 = prefs1[u1].module_ns;
-                        break;
-                    }
-                }
+                mod1 = ly_resolve_prefix(ctx, ptr1, end1 - ptr1, LY_PREF_XML, val_prefix_data1);
             }
-            if (prefs2) {
+            if (val_prefix_data2 && (end2 = strchr(ptr2, ':'))) {
                 /* find module of the second prefix, if any */
-                LY_ARRAY_FOR(prefs2, u2) {
-                    len = strlen(prefs2[u2].id);
-                    if (!strncmp(ptr2, prefs2[u2].id, len) && (ptr2[len] == ':')) {
-                        ns2 = prefs2[u2].module_ns;
-                        break;
-                    }
-                }
+                mod2 = ly_resolve_prefix(ctx, ptr2, end2 - ptr2, LY_PREF_XML, val_prefix_data2);
             }
 
-            if (!ns1 || !ns2 || (ns1 != ns2)) {
+            if (!mod1 || !mod2 || (mod1 != mod2)) {
                 /* not a prefix or maps to different namespaces */
                 break;
             }
 
             /* skip prefixes in both values (':' is skipped as iter) */
-            ptr1 += strlen(prefs1[u1].id);
-            ptr2 += strlen(prefs2[u2].id);
+            ptr1 = end1;
+            ptr2 = end2;
         }
 
         ++ptr1;
diff --git a/src/xml.h b/src/xml.h
index 6bed9f0..629ad04 100644
--- a/src/xml.h
+++ b/src/xml.h
@@ -164,28 +164,18 @@
 void lyxml_ctx_free(struct lyxml_ctx *xmlctx);
 
 /**
- * @brief Find all possible prefixes in a value.
- *
- * @param[in] xmlctx XML context to use.
- * @param[in] value Value to check.
- * @param[in] value_len Value length.
- * @param[out] val_prefs Array of found prefixes.
- * @return LY_ERR value.
- */
-LY_ERR lyxml_get_prefixes(struct lyxml_ctx *xmlctx, const char *value, size_t value_len, struct ly_prefix **val_prefs);
-
-/**
  * @brief Compare values and their prefix mappings.
  *
+ * @param[in] ctx libyang context.
  * @param[in] value1 First value.
- * @param[in] prefs1 First value prefixes.
+ * @param[in] val_prefix_data1 First value prefix data.
  * @param[in] value2 Second value.
- * @param[in] prefs2 Second value prefixes.
+ * @param[in] val_prefix_data2 Second value prefix data.
  * @return LY_SUCCESS if values are equal.
  * @return LY_ENOT if values are not equal.
  * @return LY_ERR on error.
  */
-LY_ERR lyxml_value_compare(const char *value1, const struct ly_prefix *prefs1, const char *value2,
-        const struct ly_prefix *prefs2);
+LY_ERR lyxml_value_compare(const struct ly_ctx *ctx,  const char *value1, void *val_prefix_data1, const char *value2,
+        void *val_prefix_data2);
 
 #endif /* LY_XML_H_ */