data tree NEW support for with-defaults attribute

Tests included.
diff --git a/src/parser_xml.c b/src/parser_xml.c
index da7ba5d..b23b5bf 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -133,7 +133,7 @@
 }
 
 static LY_ERR
-lydxml_attributes(struct lyd_xml_ctx *ctx, struct ly_set *attrs_data, struct lyd_attr **attr)
+lydxml_attributes(struct lyd_xml_ctx *ctx, struct ly_set *attrs_data, const struct lysc_node *sparent, struct lyd_attr **attr)
 {
     LY_ERR ret = LY_EVALID, rc;
     const struct lyxml_ns *ns;
@@ -177,7 +177,7 @@
         }
 
         rc = lyd_create_attr(NULL, attr, mod, attr_data->name, attr_data->name_len, attr_data->value,
-                             attr_data->value_len, &attr_data->dynamic, lydxml_resolve_prefix, ctx, LYD_XML);
+                             attr_data->value_len, &attr_data->dynamic, lydxml_resolve_prefix, ctx, LYD_XML, sparent);
         if (rc == LY_EINCOMPLETE) {
             ly_set_add(&ctx->incomplete_type_validation_attrs, attr, LY_SET_OPT_USEASLIST);
         } else if (rc) {
@@ -216,7 +216,7 @@
     size_t prefix_len, name_len;
     struct ly_set attrs_data = {0};
     const struct lyxml_ns *ns;
-    struct lyd_attr *attr;
+    struct lyd_attr *attr = NULL, *attr2;
     const struct lysc_node *snode;
     struct lys_module *mod;
     unsigned int parents_count = ctx->elements.count;
@@ -238,16 +238,12 @@
             }
         }
 
-        attr = NULL;
         if (ctx->status == LYXML_ATTRIBUTE) {
             /* first parse all attributes so we have all the namespaces available */
             if (lydxml_attributes_parse(ctx, data, &attrs_data) != LY_SUCCESS) {
                 ret = LY_EVALID;
                 goto cleanup;
             }
-
-            /* create actual attributes so that prefixes are available in the context */
-            LY_CHECK_GOTO(ret = lydxml_attributes(ctx, &attrs_data, &attr), cleanup);
         }
 
         ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
@@ -270,6 +266,11 @@
             goto cleanup;
         }
 
+        /* create actual attributes so that prefixes are available in the context */
+        if (attrs_data.count) {
+            LY_CHECK_GOTO(ret = lydxml_attributes(ctx, &attrs_data, snode, &attr), cleanup);
+        }
+
         if (snode->nodetype & (LYS_ACTION | LYS_NOTIF)) {
             LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Unexpected %s element \"%.*s\".",
                    snode->nodetype == LYS_ACTION ? "RPC/action" : "notification", name_len, name);
@@ -402,11 +403,6 @@
             }
         }
 
-        /* add attributes */
-        assert(!cur->attr);
-        cur->attr = attr;
-        attr = NULL;
-
         /* correct flags */
         if (!(snode->nodetype & (LYS_ACTION | LYS_NOTIF)) && snode->when) {
             if (ctx->options & LYD_OPT_TRUSTED) {
@@ -421,6 +417,18 @@
             /* node is valid */
             cur->flags &= ~LYD_NEW;
         }
+        LY_LIST_FOR(attr, attr2) {
+            if (!strcmp(attr2->name, "default") && !strcmp(attr2->annotation->module->name, "ietf-netconf-with-defaults")
+                    && attr2->value.boolean) {
+                /* node is default according to the metadata */
+                cur->flags |= LYD_DEFAULT;
+            }
+        }
+
+        /* add attributes */
+        assert(!cur->attr);
+        cur->attr = attr;
+        attr = NULL;
 
         /* insert */
         lyd_insert_node((struct lyd_node *)parent, node, cur);
diff --git a/src/tree_data.c b/src/tree_data.c
index f3c049f..f6cd61f 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -185,26 +185,25 @@
 }
 
 LY_ERR
-lyd_value_parse_attr(struct lyd_attr *attr, const char *value, size_t value_len, int *dynamic, int second,
-                     ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node **trees)
+lyd_value_parse_attr(struct ly_ctx *ctx, struct lyd_attr *attr, const char *value, size_t value_len, int *dynamic,
+                     int second, ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
+                     const struct lysc_node *ctx_snode, const struct lyd_node **trees)
 {
     LY_ERR ret = LY_SUCCESS;
     struct ly_err_item *err = NULL;
-    struct ly_ctx *ctx;
     struct lyext_metadata *ant;
     int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
             (dynamic && *dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
-    assert(attr);
 
-    ctx = attr->parent->schema->module->ctx;
+    assert(ctx && attr && ((trees && attr->parent) || ctx_snode));
+
     ant = attr->annotation->data;
 
     if (!second) {
         attr->value.realtype = ant->type;
     }
     ret = ant->type->plugin->store(ctx, ant->type, value, value_len, options, get_prefix, parser, format,
-                                  trees ? (void*)attr->parent : (void*)attr->parent->schema, trees,
-                                  &attr->value, NULL, &err);
+                                  trees ? (void *)attr->parent : (void *)ctx_snode, trees, &attr->value, NULL, &err);
     if (ret && (ret != LY_EINCOMPLETE)) {
         if (err) {
             ly_err_print(err);
@@ -879,14 +878,14 @@
 LY_ERR
 lyd_create_attr(struct lyd_node *parent, struct lyd_attr **attr, const struct lys_module *mod, const char *name,
                 size_t name_len, const char *value, size_t value_len, int *dynamic, ly_clb_resolve_prefix get_prefix,
-                void *prefix_data, LYD_FORMAT format)
+                void *prefix_data, LYD_FORMAT format, const struct lysc_node *ctx_snode)
 {
     LY_ERR ret;
     struct lysc_ext_instance *ant = NULL;
     struct lyd_attr *at, *last;
     uint32_t v;
 
-    assert(parent || attr);
+    assert((parent || attr) && mod);
 
     LY_ARRAY_FOR(mod->compiled->exts, v) {
         if (mod->compiled->exts[v].def->plugin == lyext_plugins_internal[LYEXT_PLUGIN_INTERNAL_ANNOTATION].plugin &&
@@ -907,7 +906,7 @@
     LY_CHECK_ERR_RET(!at, LOGMEM(mod->ctx), LY_EMEM);
     at->parent = parent;
     at->annotation = ant;
-    ret = lyd_value_parse_attr(at, value, value_len, dynamic, 0, get_prefix, prefix_data, format, NULL);
+    ret = lyd_value_parse_attr(mod->ctx, at, value, value_len, dynamic, 0, get_prefix, prefix_data, format, ctx_snode, NULL);
     if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
         free(at);
         return ret;
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index 3e6b1de..7cd5d34 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -139,13 +139,14 @@
  * @param[in] get_prefix Parser-specific getter to resolve prefixes used in the @p value string.
  * @param[in] prefix_data User data for @p get_prefix.
  * @param[in] format Input format of @p value.
+ * @param[in] ctx_snode Context node for value resolution in schema.
  * @return LY_SUCCESS on success.
  * @return LY_EINCOMPLETE in case data tree is needed to finish the validation.
  * @return LY_ERR value if an error occurred.
  */
 LY_ERR lyd_create_attr(struct lyd_node *parent, struct lyd_attr **attr, const struct lys_module *mod, const char *name,
-                       size_t name_len, const char *value, size_t value_len, int *dynamic,
-                       ly_clb_resolve_prefix get_prefix, void *prefix_data, LYD_FORMAT format);
+                       size_t name_len, const char *value, size_t value_len, int *dynamic, ly_clb_resolve_prefix get_prefix,
+                       void *prefix_data, LYD_FORMAT format, const struct lysc_node *ctx_snode);
 
 /**
  * @brief Validate, canonize and store the given @p value into the node according to the node's type's rules.
@@ -171,6 +172,7 @@
 /**
  * @brief Validate, canonize and store the given @p value into the attribute according to the metadata annotation type's rules.
  *
+ * @param[in] ctx libyang context.
  * @param[in] attr Data attribute for the @p value.
  * @param[in] value String value to be parsed, must not be NULL.
  * @param[in] value_len Length of the give @p value (mandatory).
@@ -179,6 +181,7 @@
  * @param[in] get_prefix Parser-specific getter to resolve prefixes used in the @p value string.
  * @param[in] parser Parser's data for @p get_prefix
  * @param[in] format Input format of the data.
+ * @param[in] ctx_snode Context node for value resolution in schema.
  * @param[in] trees ([Sized array](@ref sizedarrays)) of data trees (e.g. when validating RPC/Notification) where the required
  *            data instance (leafref target, instance-identifier) can be placed. NULL in case the data tree are not yet complete,
  *            then LY_EINCOMPLETE can be returned.
@@ -186,8 +189,9 @@
  * @return LY_EINCOMPLETE in case the @p trees is not provided and it was needed to finish the validation.
  * @return LY_ERR value if an error occurred.
  */
-LY_ERR lyd_value_parse_attr(struct lyd_attr *attr, const char *value, size_t value_len, int *dynamic, int second,
-                            ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node **trees);
+LY_ERR lyd_value_parse_attr(struct ly_ctx *ctx, struct lyd_attr *attr, const char *value, size_t value_len, int *dynamic,
+                            int second, ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
+                            const struct lysc_node *ctx_snode, const struct lyd_node **trees);
 
 /**
  * @brief Parse XML string as YANG data tree.
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 80633a3..b1a662e 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -801,20 +801,6 @@
         }
     }
 
-#if 0
-    /* hack for NETCONF's edit-config's operation attribute. It is not defined in the schema, but since libyang
-     * implements YANG metadata (annotations), we need its definition. Because the ietf-netconf schema is not the
-     * internal part of libyang, we cannot add the annotation into the schema source, but we do it here to have
-     * the anotation definitions available in the internal schema structure. There is another hack in schema
-     * printers to do not print this internally added annotation. */
-    if (ly_strequal(mod->name, "ietf-netconf", 0)) {
-        if (lyp_add_ietf_netconf_annotations(mod)) {
-            lys_free(mod, NULL, 1, 1);
-            return NULL;
-        }
-    }
-#endif
-
     if (!mod->implemented) {
         /* pre-compile features and extension definitions of the module */
         LY_CHECK_GOTO(lys_feature_precompile(NULL, ctx, mod, mod->parsed->features, &mod->off_features), error);
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 064e6cd..61f4a19 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -68,7 +68,7 @@
         LY_ARRAY_CREATE_GOTO((CTX)->ctx, EXT_C, LY_ARRAY_SIZE(EXTS_P), RET, GOTO); \
         for (uint32_t __exts_iter = 0, __array_offset = LY_ARRAY_SIZE(EXT_C); __exts_iter < LY_ARRAY_SIZE(EXTS_P); ++__exts_iter) { \
             LY_ARRAY_INCREMENT(EXT_C); \
-            RET = lys_compile_ext(CTX, &(EXTS_P)[__exts_iter], &(EXT_C)[__exts_iter + __array_offset], PARENT, PARENT_TYPE); \
+            RET = lys_compile_ext(CTX, &(EXTS_P)[__exts_iter], &(EXT_C)[__exts_iter + __array_offset], PARENT, PARENT_TYPE, NULL); \
             LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
         } \
     }
@@ -441,13 +441,23 @@
     return NULL;
 }
 
+/**
+ * @brief Fill in the prepared compiled extension instance structure according to the parsed extension instance.
+ *
+ * @param[in] ctx Compilation context.
+ * @param[in] ext_p Parsed extension instance.
+ * @param[in,out] ext Prepared compiled extension instance.
+ * @param[in] parent Extension instance parent.
+ * @param[in] parent_type Extension instance parent type.
+ * @param[in] ext_mod Optional module with the extension instance extension definition, set only for internal annotations.
+ */
 static LY_ERR
-lys_compile_ext(struct lysc_ctx *ctx, struct lysp_ext_instance *ext_p, struct lysc_ext_instance *ext, void *parent, LYEXT_PARENT parent_type)
+lys_compile_ext(struct lysc_ctx *ctx, struct lysp_ext_instance *ext_p, struct lysc_ext_instance *ext, void *parent,
+                LYEXT_PARENT parent_type, const struct lys_module *ext_mod)
 {
     LY_ERR ret = LY_EVALID;
     const char *name;
     unsigned int u;
-    const struct lys_module *mod;
     struct lysc_ext **elist = NULL;
     const char *prefixed_name = NULL;
 
@@ -491,24 +501,26 @@
     }
     lysc_update_path(ctx, NULL, prefixed_name);
 
-    mod = lys_module_find_prefix(ctx->mod_def, prefixed_name, u - 1);
-    if (!mod) {
-        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-               "Invalid prefix \"%.*s\" used for extension instance identifier.", u, prefixed_name);
-        goto cleanup;
-    } else if (!mod->parsed->extensions) {
-        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                "Extension instance \"%s\" refers \"%s\" module that does not contain extension definitions.",
-                prefixed_name, mod->name);
-        goto cleanup;
+    if (!ext_mod) {
+        ext_mod = lys_module_find_prefix(ctx->mod_def, prefixed_name, u - 1);
+        if (!ext_mod) {
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                "Invalid prefix \"%.*s\" used for extension instance identifier.", u, prefixed_name);
+            goto cleanup;
+        } else if (!ext_mod->parsed->extensions) {
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                    "Extension instance \"%s\" refers \"%s\" module that does not contain extension definitions.",
+                    prefixed_name, ext_mod->name);
+            goto cleanup;
+        }
     }
     name = &prefixed_name[u];
 
     /* find the extension definition there */
-    if (mod->off_extensions) {
-        elist = mod->off_extensions;
+    if (ext_mod->off_extensions) {
+        elist = ext_mod->off_extensions;
     } else {
-        elist = mod->compiled->extensions;
+        elist = ext_mod->compiled->extensions;
     }
     LY_ARRAY_FOR(elist, u) {
         if (!strcmp(name, elist[u]->name)) {
@@ -7209,6 +7221,44 @@
     return ret;
 }
 
+static LY_ERR
+lys_compile_ietf_netconf_wd_annotation(struct lysc_ctx *ctx, struct lys_module *mod)
+{
+    struct lysc_ext_instance *ext;
+    struct lysp_ext_instance *ext_p = NULL;
+    struct lysp_stmt *stmt;
+    const struct lys_module *ext_mod;
+    LY_ERR ret = LY_SUCCESS;
+
+    /* create the parsed extension instance manually */
+    ext_p = calloc(1, sizeof *ext_p);
+    LY_CHECK_ERR_GOTO(!ext_p, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
+    ext_p->name = lydict_insert(ctx->ctx, "md:annotation", 0);
+    ext_p->argument = lydict_insert(ctx->ctx, "default", 0);
+    ext_p->insubstmt = LYEXT_SUBSTMT_SELF;
+    ext_p->insubstmt_index = 0;
+
+    stmt = calloc(1, sizeof *ext_p->child);
+    stmt->stmt = lydict_insert(ctx->ctx, "type", 0);
+    stmt->arg = lydict_insert(ctx->ctx, "boolean", 0);
+    stmt->kw = LY_STMT_TYPE;
+    ext_p->child = stmt;
+
+    /* allocate new extension instance */
+    LY_ARRAY_NEW_GOTO(mod->ctx, mod->compiled->exts, ext, ret, cleanup);
+
+    /* manually get extension definition module */
+    ext_mod = ly_ctx_get_module_latest(ctx->ctx, "ietf-yang-metadata");
+
+    /* compile the extension instance */
+    LY_CHECK_GOTO(ret = lys_compile_ext(ctx, ext_p, ext, mod->compiled, LYEXT_PAR_MODULE, ext_mod), cleanup);
+
+cleanup:
+    lysp_ext_instance_free(ctx->ctx, ext_p);
+    free(ext_p);
+    return ret;
+}
+
 LY_ERR
 lys_compile(struct lys_module *mod, int options)
 {
@@ -7408,6 +7458,24 @@
            leafref paths, default values and must/when expressions in all schemas of the context to check that they are still valid */
     }
 
+#if 0
+    /* hack for NETCONF's edit-config's operation attribute. It is not defined in the schema, but since libyang
+     * implements YANG metadata (annotations), we need its definition. Because the ietf-netconf schema is not the
+     * internal part of libyang, we cannot add the annotation into the schema source, but we do it here to have
+     * the anotation definitions available in the internal schema structure. */
+    if (ly_strequal(mod->name, "ietf-netconf", 0)) {
+        if (lyp_add_ietf_netconf_annotations(mod)) {
+            lys_free(mod, NULL, 1, 1);
+            return NULL;
+        }
+    }
+#endif
+
+    /* add ietf-netconf-with-defaults "default" metadata to the compiled module */
+    if (!strcmp(mod->name, "ietf-netconf-with-defaults")) {
+        LY_CHECK_GOTO(ret = lys_compile_ietf_netconf_wd_annotation(&ctx, mod), error);
+    }
+
     ly_set_erase(&ctx.dflts, free);
     ly_set_erase(&ctx.unres, NULL);
     ly_set_erase(&ctx.groupings, NULL);
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 736629d..5efbb1e 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -715,11 +715,18 @@
 /**
  * @brief Free the parsed type structure.
  * @param[in] ctx libyang context where the string data resides in a dictionary.
- * @param[in] type Parsed schema type structure to free. Note that since the type itself is not freed.
+ * @param[in] type Parsed schema type structure to free. Note that the type itself is not freed.
  */
 void lysp_type_free(struct ly_ctx *ctx, struct lysp_type *type);
 
 /**
+ * @brief Free the parsed extension instance structure.
+ * @param[in] ctx libyang context where the string data resides in a dictionary.
+ * @param[in] type Parsed extension instance structure to free. Note that the instance itself is not freed.
+ */
+void lysp_ext_instance_free(struct ly_ctx *ctx, struct lysp_ext_instance *ext);
+
+/**
  * @param[in,out] exts [sized array](@ref sizedarrays) For extension instances in case of statements that do not store extension instances in their own list.
  */
 LY_ERR lysp_stmt_parse(struct lysc_ctx *ctx, const struct lysp_stmt *stmt, enum ly_stmt kw, void **result, struct lysp_ext_instance **exts);
diff --git a/src/validation.c b/src/validation.c
index a32a11e..97f02d6 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -92,8 +92,8 @@
         struct lyd_attr *attr = (struct lyd_attr *)attr_types->objs[u];
 
         /* validate and store the value of the node */
-        ret = lyd_value_parse_attr(attr, attr->value.original, strlen(attr->value.original), 0, 1, get_prefix_clb,
-                                   parser_data, format, trees);
+        ret = lyd_value_parse_attr(attr->parent->schema->module->ctx, attr, attr->value.original,
+                                   strlen(attr->value.original), 0, 1, get_prefix_clb, parser_data, format, NULL, trees);
         LY_CHECK_RET(ret);
     }