xpath BUGFIX support for unprefixed identities
diff --git a/src/xpath.c b/src/xpath.c
index 9edf3d0..f32af4e 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -4098,6 +4098,51 @@
     return ret;
 }
 
+/**
+ * @brief Get the module of an identity used in derived-from(-or-self)() functions.
+ *
+ * @param[in,out] qname Qualified node name. If includes prefix, it is skipped.
+ * @param[in,out] qname_len Length of @p qname, is updated accordingly.
+ * @param[in] set Set with general XPath context.
+ * @param[out] mod Module of the identity.
+ * @return LY_ERR
+ */
+static LY_ERR
+xpath_derived_ident_module(const char **qname, uint32_t *qname_len, const struct lyxp_set *set,
+        const struct lys_module **mod)
+{
+    LY_CHECK_RET(moveto_resolve_model(qname, qname_len, set, mod));
+    if (*mod) {
+        /* prefixed identity */
+        return LY_SUCCESS;
+    }
+
+    switch (set->format) {
+    case LY_VALUE_SCHEMA:
+    case LY_VALUE_SCHEMA_RESOLVED:
+        /* current module */
+        *mod = set->cur_mod;
+        break;
+    case LY_VALUE_CANON:
+    case LY_VALUE_JSON:
+    case LY_VALUE_LYB:
+    case LY_VALUE_STR_NS:
+        /* inherit parent (context node) module */
+        if (set->cur_scnode) {
+            *mod = set->cur_scnode->module;
+        } else {
+            *mod = set->cur_mod;
+        }
+        break;
+    case LY_VALUE_XML:
+        /* all identifiers need to be prefixed */
+        LOGVAL(set->ctx, LYVE_DATA, "Non-prefixed identity \"%.*s\" in XML xpath found.", (int)*qname_len, *qname);
+        return LY_EVALID;
+    }
+
+    return LY_SUCCESS;
+}
+
 static LY_ERR
 xpath_derived_(struct lyxp_set **args, struct lyxp_set *set, uint32_t options, ly_bool self_match, const char *func)
 {
@@ -4147,12 +4192,8 @@
     /* parse the identity */
     id_name = args[1]->val.str;
     id_len = strlen(id_name);
-    rc = moveto_resolve_model(&id_name, &id_len, set, &mod);
+    rc = xpath_derived_ident_module(&id_name, &id_len, set, &mod);
     LY_CHECK_RET(rc);
-    if (!mod) {
-        LOGVAL(set->ctx, LYVE_XPATH, "Identity \"%.*s\" without a prefix.", (int)id_len, id_name);
-        return LY_EVALID;
-    }
 
     /* find the identity */
     found = 0;
diff --git a/tests/utests/data/test_validation.c b/tests/utests/data/test_validation.c
index 17fd078..d80438a 100644
--- a/tests/utests/data/test_validation.c
+++ b/tests/utests/data/test_validation.c
@@ -164,6 +164,37 @@
 }
 
 static void
+test_unprefixed_ident(void **state)
+{
+    struct lyd_node *tree;
+    const char *schema =
+            "module a {\n"
+            "    namespace urn:tests:a;\n"
+            "    prefix a;\n"
+            "    yang-version 1.1;\n"
+            "\n"
+            "    identity d3 {base d2;}\n"
+            "    identity d2 {base d1;}\n"
+            "    identity d1;\n"
+            "\n"
+            "    leaf a {type identityref {base d1;}}\n"
+            "    leaf b {type string; must \"derived-from-or-self(/a, 'd2')\";}\n"
+            "    leaf c {type string; when \"derived-from(/a, 'd2')\";}\n"
+            "}";
+
+    UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
+
+    CHECK_PARSE_LYD_PARAM("<b xmlns=\"urn:tests:a\">hey</b>", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+    CHECK_LOG_CTX("Must condition \"derived-from-or-self(/a, 'd2')\" not satisfied.", "/a:b", 0);
+
+    CHECK_PARSE_LYD_PARAM("<c xmlns=\"urn:tests:a\">hey</c>", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+    CHECK_LOG_CTX("When condition \"derived-from(/a, 'd2')\" not satisfied.", "/a:c", 0);
+
+    LYD_TREE_CREATE("<a xmlns=\"urn:tests:a\">d3</a><b xmlns=\"urn:tests:a\">b-val</b><c xmlns=\"urn:tests:a\">c-val</c>", tree);
+    lyd_free_all(tree);
+}
+
+static void
 test_mandatory(void **state)
 {
     struct lyd_node *tree;
@@ -1523,6 +1554,7 @@
         UTEST(test_mandatory),
         UTEST(test_mandatory_when),
         UTEST(test_type_incomplete_when),
+        UTEST(test_unprefixed_ident),
         UTEST(test_minmax),
         UTEST(test_unique),
         UTEST(test_unique_nested),