parser common UPDATE log metadata paths

Refs #2098
diff --git a/src/parser_common.c b/src/parser_common.c
index bdc8529..ef67a8c 100644
--- a/src/parser_common.c
+++ b/src/parser_common.c
@@ -304,6 +304,8 @@
         const char *name, size_t name_len, const void *value, size_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format,
         void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node)
 {
+    LY_ERR rc = LY_SUCCESS;
+    char *dpath = NULL, *path = NULL;
     ly_bool incomplete;
     struct lyd_meta *first = NULL;
 
@@ -312,11 +314,20 @@
         first = *meta;
     }
 
-    LY_CHECK_RET(lyd_create_meta(parent, meta, mod, name, name_len, value, value_len, dynamic, format, prefix_data,
-            hints, ctx_node, 0, &incomplete));
+    /* generate path to the metadata */
+    LY_CHECK_RET(ly_vlog_build_data_path(lydctx->data_ctx->ctx, &dpath));
+    if (asprintf(&path, "%s/@%s:%.*s", dpath, mod->name, (int)name_len, name) == -1) {
+        LOGMEM(lydctx->data_ctx->ctx);
+        rc = LY_EMEM;
+        goto cleanup;
+    }
+    LOG_LOCSET(NULL, NULL, path, NULL);
+
+    LY_CHECK_GOTO(rc = lyd_create_meta(parent, meta, mod, name, name_len, value, value_len, dynamic, format, prefix_data,
+            hints, ctx_node, 0, &incomplete), cleanup);
 
     if (incomplete && !(lydctx->parse_opts & LYD_PARSE_ONLY)) {
-        LY_CHECK_RET(ly_set_add(&lydctx->meta_types, *meta, 1, NULL));
+        LY_CHECK_GOTO(rc = ly_set_add(&lydctx->meta_types, *meta, 1, NULL), cleanup);
     }
 
     if (first) {
@@ -324,7 +335,11 @@
         *meta = first;
     }
 
-    return LY_SUCCESS;
+cleanup:
+    LOG_LOCBACK(0, 0, 1, 0);
+    free(dpath);
+    free(path);
+    return rc;
 }
 
 LY_ERR
diff --git a/tests/utests/data/test_parser_json.c b/tests/utests/data/test_parser_json.c
index 37d9d43..8feed9c 100644
--- a/tests/utests/data/test_parser_json.c
+++ b/tests/utests/data/test_parser_json.c
@@ -47,7 +47,8 @@
             "leaf foo3 { type uint32; }"
             "leaf foo4 { type uint64; }"
             "rpc r1 {input {leaf l1 {type string;} leaf l2 {type string;}}}"
-            "notification n2;}";
+            "notification n2;"
+            "}";
 
     UTEST_SETUP;
 
@@ -163,7 +164,7 @@
     /* reverse solidus in JSON object member name */
     data = "{\"@a:foo\":{\"a:hi\\nt\":1},\"a:foo\":\"xxx\"}";
     assert_int_equal(LY_EINVAL, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
-    CHECK_LOG_CTX("Annotation definition for attribute \"a:hi\nt\" not found.", "Data location \"/@a:foo\", line number 1.");
+    CHECK_LOG_CTX("Annotation definition for attribute \"a:hi\nt\" not found.", "Path \"/@a:foo/@a:hi\nt\", line number 1.");
 }
 
 static void
@@ -900,6 +901,19 @@
     lyd_free_all(envp);
 }
 
+static void
+test_metadata(void **state)
+{
+    const char *data;
+    struct lyd_node *tree;
+
+    /* invalid metadata value */
+    data = "{\"a:c\":{\"x\":\"xval\",\"@x\":{\"a:hint\":\"value\"}}}";
+    assert_int_equal(LY_EVALID, lyd_parse_data_mem(_UC->ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+    assert_null(tree);
+    CHECK_LOG_CTX("Invalid non-number-encoded int8 value \"value\".", "Path \"/a:c/x/@a:hint\", line number 1.");
+}
+
 int
 main(void)
 {
@@ -918,6 +932,7 @@
         UTEST(test_restconf_rpc, setup),
         UTEST(test_restconf_notification, setup),
         UTEST(test_restconf_reply, setup),
+        UTEST(test_metadata, setup),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);
diff --git a/tests/utests/data/test_parser_xml.c b/tests/utests/data/test_parser_xml.c
index a2cd30f..d651253 100644
--- a/tests/utests/data/test_parser_xml.c
+++ b/tests/utests/data/test_parser_xml.c
@@ -31,6 +31,7 @@
             "    namespace urn:tests:a;\n"
             "    prefix a;\n"
             "    yang-version 1.1;\n"
+            "    import ietf-yang-metadata {prefix md;}"
             "    list l1 { key \"a b c\"; leaf a {type string;} leaf b {type string;} leaf c {type int16;}"
             "        leaf d {type string;}"
             "        container cont {leaf e {type boolean;}}"
@@ -45,7 +46,9 @@
             "    anyxml anyx;\n"
             "    leaf foo2 { type string; default \"default-val\"; }\n"
             "    leaf foo3 { type uint32; }\n"
-            "    notification n2;}";
+            "    notification n2;"
+            "    md:annotation attr {type enumeration {enum val;}}"
+            "}";
 
     UTEST_SETUP;
 
@@ -655,7 +658,7 @@
     assert_int_equal(LY_EVALID, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_RPC_NETCONF, &tree, &op));
     ly_in_free(in, 0);
     CHECK_LOG_CTX("Invalid enumeration value \"merge2\".",
-            "Data location \"/ietf-netconf:copy-config/source/config/a:l1[a='val_a'][b='val_b'][c='5']/cont/e\", line number 13.");
+            "Path \"/ietf-netconf:copy-config/source/config/a:l1[a='val_a'][b='val_b'][c='5']/cont/e/@ietf-netconf:operation\", line number 13.");
     lyd_free_all(tree);
     assert_null(op);
 }
@@ -961,6 +964,19 @@
     lyd_free_all(tree);
 }
 
+static void
+test_metadata(void **state)
+{
+    const char *data;
+    struct lyd_node *tree;
+
+    /* invalid metadata value */
+    data = "<c xmlns=\"urn:tests:a\" xmlns:a=\"urn:tests:a\"><x a:attr=\"value\">xval</x></c>";
+    assert_int_equal(LY_EVALID, lyd_parse_data_mem(_UC->ctx, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+    assert_null(tree);
+    CHECK_LOG_CTX("Invalid enumeration value \"value\".", "Path \"/a:c/x/@a:attr\", line number 1.");
+}
+
 int
 main(void)
 {
@@ -982,6 +998,7 @@
         UTEST(test_restconf_reply, setup),
         UTEST(test_filter_attributes, setup),
         UTEST(test_data_skip, setup),
+        UTEST(test_metadata, setup),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);