data FEATURE support extension's data parsing

Make the data parsers to support parsing data corresponding to a
separate schema tree specified in an extension instance.
diff --git a/doc/transition.dox b/doc/transition.dox
index 59addbb..0bcc338 100644
--- a/doc/transition.dox
+++ b/doc/transition.dox
@@ -276,7 +276,9 @@
  * lyd_parse_fd()               | ::lyd_parse_data_fd()           | Renamed and limited to data trees only.
  * lyd_parse_mem()              | ::lyd_parse_data_mem()          | ^
  * lyd_parse_path()             | ::lyd_parse_data_path()         | ^
+ * -                            | ::lyd_parse_ext_data()          | Separated function for parsing data trees matching a schema tree of the given extension instance.
  * -                            | ::lyd_parse_op()                | Separated function for parsing RPCs, actions, replies, and notifications.
+ * -                            | ::lyd_parse_ext_op()            | Separated function for parsing RPCs, actions, replies, and notifications of the given extension instance.
  * -                            | ::lyd_print_all()               | New API accepting ::ly_out.
  * -                            | ::lyd_print_tree()              | ^
  *
diff --git a/src/lyb.h b/src/lyb.h
index 85ad901..30e89fd 100644
--- a/src/lyb.h
+++ b/src/lyb.h
@@ -54,6 +54,7 @@
  * Note that the structure maps to the lyd_ctx which is common for all the data parsers
  */
 struct lyd_lyb_ctx {
+    const struct lysc_ext_instance *ext; /**< extension instance possibly changing document root context of the data being parsed */
     union {
         struct {
             uint32_t parse_opts;   /**< various @ref dataparseroptions. */
diff --git a/src/parser_data.h b/src/parser_data.h
index 7dc3e00..16b5c0a 100644
--- a/src/parser_data.h
+++ b/src/parser_data.h
@@ -58,8 +58,11 @@
  *     example the *:operational* datastore is not necessarily valid and results of the NETCONF's \<get\> or \<get-config\>
  *     oprations used with filters will be incomplete (and thus invalid). This can be allowed using ::LYD_PARSE_ONLY,
  *     the ::LYD_PARSE_NO_STATE should be used for the data returned by \<get-config\> operation.
+ * - ::lyd_parse_ext_data() is used for parsing configuration data trees defined inside extension instances, such as
+ *   instances of yang-data extension specified in [RFC 8040](http://tools.ietf.org/html/rfc8040).
  * - ::lyd_parse_op() is used for parsing RPCs/actions, replies, and notifications. Even NETCONF rpc, rpc-reply, and
- *     notification messages are supported.
+ *   notification messages are supported.
+ * - ::lyd_parse_ext_op() is used for parsing RPCs/actions, replies, and notifications defined inside extension instances.
  *
  * Further information regarding the processing input instance data can be found on the following pages.
  * - @subpage howtoDataValidation
@@ -71,7 +74,9 @@
  * - ::lyd_parse_data_mem()
  * - ::lyd_parse_data_fd()
  * - ::lyd_parse_data_path()
+ * - ::lyd_parse_ext_data()
  * - ::lyd_parse_op()
+ * - ::lyd_parse_ext_op()
  */
 
 /**
@@ -252,6 +257,26 @@
         uint32_t validate_options, struct lyd_node **tree);
 
 /**
+ * @brief Parse (and validate) data from the input handler as a YANG data tree following the schema tree of the given
+ * extension instance.
+ *
+ * Note that the data being parsed are limited only to the schema tree specified by the given extension, it does not allow
+ * to mix them with the standard data from any module.
+ *
+ * @param[in] ext Extension instance providing the specific schema tree to match with the data being parsed.
+ * @param[in] parent Optional parent to connect the parsed nodes to.
+ * @param[in] in The input handle to provide the dumped data in the specified @p format to parse (and validate).
+ * @param[in] format Format of the input data to be parsed. Can be 0 to try to detect format from the input handler.
+ * @param[in] parse_options Options for parser, see @ref dataparseroptions.
+ * @param[in] validate_options Options for the validation phase, see @ref datavalidationoptions.
+ * @param[out] tree Full parsed data tree, note that NULL can be a valid tree. If @p parent is set, set to NULL.
+ * @return LY_SUCCESS in case of successful parsing (and validation).
+ * @return LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
+ */
+LY_ERR lyd_parse_ext_data(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
+        uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree);
+
+/**
  * @ingroup datatree
  * @defgroup datatype Data operation type
  *
@@ -323,6 +348,47 @@
         enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op);
 
 /**
+ * @brief Parse YANG data into an operation data tree following only the specification from the given extension instance.
+ *
+ * At least one of @p parent, @p tree, or @p op must always be set.
+ *
+ * Specific @p data_type values have different parameter meaning as follows:
+ * - ::LYD_TYPE_RPC_NETCONF:
+ *   - @p parent - must be NULL, the whole RPC is expected;
+ *   - @p format - must be ::LYD_XML, NETCONF supports only this format;
+ *   - @p tree - must be provided, all the NETCONF-specific XML envelopes will be returned here as
+ *               a separate opaque data tree, even if the function fails, this may be returned;
+ *   - @p op - must be provided, the RPC/action data tree itself will be returned here, pointing to the operation;
+ *
+ * - ::LYD_TYPE_NOTIF_NETCONF:
+ *   - @p parent - must be NULL, the whole notification is expected;
+ *   - @p format - must be ::LYD_XML, NETCONF supports only this format;
+ *   - @p tree - must be provided, all the NETCONF-specific XML envelopes will be returned here as
+ *               a separate opaque data tree, even if the function fails, this may be returned;
+ *   - @p op - must be provided, the notification data tree itself will be returned here, pointing to the operation;
+ *
+ * - ::LYD_TYPE_REPLY_NETCONF:
+ *   - @p parent - must be set, pointing to the invoked RPC operation (RPC or action) node;
+ *   - @p format - must be ::LYD_XML, NETCONF supports only this format;
+ *   - @p tree - must be provided, all the NETCONF-specific XML envelopes will be returned here as
+ *               a separate opaque data tree, even if the function fails, this may be returned;
+ *   - @p op - must be NULL, the reply is appended to the RPC;
+ *   Note that there are 3 kinds of NETCONF replies - ok, error, and data. Only data reply appends any nodes to the RPC.
+ *
+ * @param[in] ext Extension instance providing the specific schema tree to match with the data being parsed.
+ * @param[in] parent Optional parent to connect the parsed nodes to.
+ * @param[in] in Input handle to read the input from.
+ * @param[in] format Expected format of the data in @p in.
+ * @param[in] data_type Expected operation to parse (@ref datatype).
+ * @param[out] tree Optional full parsed data tree. If @p parent is set, set to NULL.
+ * @param[out] op Optional parsed operation node.
+ * @return LY_ERR value.
+ * @return LY_ENOT if @p data_type is a NETCONF message and the root XML element is not the expected one.
+ */
+LY_ERR lyd_parse_ext_op(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
+        enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op);
+
+/**
  * @brief Fully validate a data tree.
  *
  * @param[in,out] tree Data tree to recursively validate. May be changed by validation.
diff --git a/src/parser_internal.h b/src/parser_internal.h
index 282938e..98a1147 100644
--- a/src/parser_internal.h
+++ b/src/parser_internal.h
@@ -43,6 +43,7 @@
  * @brief Internal (common) context for YANG data parsers.
  */
 struct lyd_ctx {
+    const struct lysc_ext_instance *ext; /**< extension instance possibly changing document root context of the data being parsed */
     uint32_t parse_opts;           /**< various @ref dataparseroptions. */
     uint32_t val_opts;             /**< various @ref datavalidationoptions. */
     uint32_t int_opts;             /**< internal parser options */
@@ -123,6 +124,7 @@
  * @brief Parse XML string as a YANG data tree.
  *
  * @param[in] ctx libyang context.
+ * @param[in] ext Optional extenion instance to parse data following the schema tree specified in the extension instance
  * @param[in] parent Parent to connect the parsed nodes to, if any.
  * @param[in,out] first_p Pointer to the first top-level parsed node, used only if @p parent is NULL.
  * @param[in] in Input structure.
@@ -135,14 +137,15 @@
  * @param[out] lydctx_p Data parser context to finish validation.
  * @return LY_ERR value.
  */
-LY_ERR lyd_parse_xml(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
-        uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type, struct lyd_node **envp, struct ly_set *parsed,
-        struct lyd_ctx **lydctx_p);
+LY_ERR lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+        struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
+        struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p);
 
 /**
  * @brief Parse JSON string as a YANG data tree.
  *
  * @param[in] ctx libyang context.
+ * @param[in] ext Optional extenion instance to parse data following the schema tree specified in the extension instance
  * @param[in] parent Parent to connect the parsed nodes to, if any.
  * @param[in,out] first_p Pointer to the first top-level parsed node, used only if @p parent is NULL.
  * @param[in] in Input structure.
@@ -153,13 +156,15 @@
  * @param[out] lydctx_p Data parser context to finish validation.
  * @return LY_ERR value.
  */
-LY_ERR lyd_parse_json(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
-        uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type, struct ly_set *parsed, struct lyd_ctx **lydctx_p);
+LY_ERR lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+        struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
+        struct ly_set *parsed, struct lyd_ctx **lydctx_p);
 
 /**
  * @brief Parse binary LYB data as a YANG data tree.
  *
  * @param[in] ctx libyang context.
+ * @param[in] ext Optional extenion instance to parse data following the schema tree specified in the extension instance
  * @param[in] parent Parent to connect the parsed nodes to, if any.
  * @param[in,out] first_p Pointer to the first top-level parsed node, used only if @p parent is NULL.
  * @param[in] in Input structure.
@@ -170,8 +175,9 @@
  * @param[out] lydctx_p Data parser context to finish validation.
  * @return LY_ERR value.
  */
-LY_ERR lyd_parse_lyb(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
-        uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type, struct ly_set *parsed, struct lyd_ctx **lydctx_p);
+LY_ERR lyd_parse_lyb(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+        struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
+        struct ly_set *parsed, struct lyd_ctx **lydctx_p);
 
 /**
  * @brief Search all the parents for an operation node, check validity based on internal parser flags.
diff --git a/src/parser_json.c b/src/parser_json.c
index 37b7e68..d64745e 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -26,6 +26,7 @@
 #include "json.h"
 #include "log.h"
 #include "parser_internal.h"
+#include "plugins_exts.h"
 #include "set.h"
 #include "tree.h"
 #include "tree_data.h"
@@ -40,6 +41,7 @@
  * Note that the structure maps to the lyd_ctx which is common for all the data parsers
  */
 struct lyd_json_ctx {
+    const struct lysc_ext_instance *ext; /**< extension instance possibly changing document root context of the data being parsed */
     uint32_t parse_opts;           /**< various @ref dataparseroptions. */
     uint32_t val_opts;             /**< various @ref datavalidationoptions. */
     uint32_t int_opts;             /**< internal data parser options */
@@ -227,11 +229,25 @@
 
     /* get the schema node */
     if (mod && (!parent || parent->schema)) {
-        *snode_p = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
+        if (!parent && lydctx->ext) {
+            *snode_p = lys_find_ext_instance_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
+        } else {
+            *snode_p = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
+        }
         if (!*snode_p) {
             if (lydctx->parse_opts & LYD_PARSE_STRICT) {
-                LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
-                        name_len, name, mod->name);
+                if (lydctx->ext) {
+                    if (lydctx->ext->argument) {
+                        LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
+                                name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
+                    } else {
+                        LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
+                                name_len, name, lydctx->ext->def->name);
+                    }
+                } else {
+                    LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
+                            name_len, name, mod->name);
+                }
                 ret = LY_EVALID;
                 goto cleanup;
             } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
@@ -1369,8 +1385,9 @@
 }
 
 LY_ERR
-lyd_parse_json(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
-        uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
+lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+        struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
+        struct ly_set *parsed, struct lyd_ctx **lydctx_p)
 {
     LY_ERR rc = LY_SUCCESS;
     struct lyd_json_ctx *lydctx = NULL;
@@ -1401,6 +1418,7 @@
         goto cleanup;
     }
     lydctx->int_opts = int_opts;
+    lydctx->ext = ext;
 
     /* find the operation node if it exists already */
     LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index 05f410c..7707dd0 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -641,7 +641,15 @@
 
     /* find our node with matching hashes */
     sibling = NULL;
-    while ((sibling = lys_getnext(sibling, sparent, mod ? mod->compiled : NULL, getnext_opts))) {
+    while (1) {
+        if (!sparent && lybctx->ext) {
+            sibling = lys_getnext_ext(sibling, sparent, lybctx->ext, getnext_opts);
+        } else {
+            sibling = lys_getnext(sibling, sparent, mod ? mod->compiled : NULL, getnext_opts);
+        }
+        if (!sibling) {
+            break;
+        }
         /* skip schema nodes from models not present during printing */
         if (lyb_has_schema_model(sibling, lybctx->lybctx->models) &&
                 lyb_is_schema_hash_match((struct lysc_node *)sibling, hash, i + 1)) {
@@ -651,7 +659,10 @@
     }
 
     if (!sibling && (lybctx->parse_opts & LYD_PARSE_STRICT)) {
-        if (mod) {
+        if (lybctx->ext) {
+            LOGVAL(lybctx->lybctx->ctx, LYVE_REFERENCE, "Failed to find matching hash for a node from \"%s\" extension instance node.",
+                    lybctx->ext->def->name);
+        } else if (mod) {
             LOGVAL(lybctx->lybctx->ctx, LYVE_REFERENCE, "Failed to find matching hash for a top-level node"
                     " from \"%s\".", mod->name);
         } else {
@@ -1018,8 +1029,9 @@
 }
 
 LY_ERR
-lyd_parse_lyb(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
-        uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
+lyd_parse_lyb(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+        struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
+        struct ly_set *parsed, struct lyd_ctx **lydctx_p)
 {
     LY_ERR rc = LY_SUCCESS;
     struct lyd_lyb_ctx *lybctx;
@@ -1058,6 +1070,7 @@
         goto cleanup;
     }
     lybctx->int_opts = int_opts;
+    lybctx->ext = ext;
 
     /* find the operation node if it exists already */
     LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lybctx->op_node), cleanup);
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 158bb6b..d01fdcd 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -23,6 +23,7 @@
 #include "log.h"
 #include "parser_data.h"
 #include "parser_internal.h"
+#include "plugins_exts.h"
 #include "set.h"
 #include "tree_data.h"
 #include "tree_data_internal.h"
@@ -36,6 +37,7 @@
  * Note that the structure maps to the lyd_ctx which is common for all the data parsers
  */
 struct lyd_xml_ctx {
+    const struct lysc_ext_instance *ext; /**< extension instance possibly changing document root context of the data being parsed */
     uint32_t parse_opts;           /**< various @ref dataparseroptions. */
     uint32_t val_opts;             /**< various @ref datavalidationoptions. */
     uint32_t int_opts;             /**< internal data parser options */
@@ -429,12 +431,24 @@
     /* get the schema node */
     snode = NULL;
     if (mod && (!parent || parent->schema)) {
-        snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
+        if (!parent && lydctx->ext) {
+            snode = lys_find_ext_instance_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
+        } else {
+            snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
+        }
         if (!snode) {
             if (lydctx->parse_opts & LYD_PARSE_STRICT) {
                 if (parent) {
                     LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.", name_len, name,
                             parent->schema->name);
+                } else if (lydctx->ext) {
+                    if (lydctx->ext->argument) {
+                        LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.", name_len, name,
+                                lydctx->ext->argument, lydctx->ext->def->name);
+                    } else {
+                        LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.", name_len, name,
+                                lydctx->ext->def->name);
+                    }
                 } else {
                     LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.", name_len, name,
                             mod->name);
@@ -1284,9 +1298,9 @@
 }
 
 LY_ERR
-lyd_parse_xml(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
-        uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type, struct lyd_node **envp, struct ly_set *parsed,
-        struct lyd_ctx **lydctx_p)
+lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+        struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
+        struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
 {
     LY_ERR rc = LY_SUCCESS;
     struct lyd_xml_ctx *lydctx;
@@ -1304,6 +1318,7 @@
     lydctx->parse_opts = parse_opts;
     lydctx->val_opts = val_opts;
     lydctx->free = lyd_xml_ctx_free;
+    lydctx->ext = ext;
 
     switch (data_type) {
     case LYD_TYPE_DATA_YANG:
diff --git a/src/plugins_exts.h b/src/plugins_exts.h
index 3daf42d..9ad46a2 100644
--- a/src/plugins_exts.h
+++ b/src/plugins_exts.h
@@ -157,6 +157,9 @@
 LY_ERR lysc_ext_substmt(const struct lysc_ext_instance *ext, enum ly_stmt substmt,
         void **instance_p, enum ly_stmt_cardinality *cardinality_p);
 
+const struct lysc_node *lys_find_ext_instance_node(const struct lysc_ext_instance *ext, const struct lys_module *module,
+        const char *name, size_t name_len, uint16_t nodetype, uint32_t options);
+
 /**
  * @brief Update path in the compile context, which is used for logging where the compilation failed.
  *
diff --git a/src/tree_data.c b/src/tree_data.c
index 246b6c7..60831e1 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -299,6 +299,7 @@
  * @brief Parse YANG data into a data tree.
  *
  * @param[in] ctx libyang context.
+ * @param[in] ext Optional extenion instance to parse data following the schema tree specified in the extension instance
  * @param[in] parent Parent to connect the parsed nodes to, if any.
  * @param[in,out] first_p Pointer to the first top-level parsed node, used only if @p parent is NULL.
  * @param[in] in Input handle to read the input from.
@@ -309,8 +310,8 @@
  * @return LY_ERR value.
  */
 static LY_ERR
-lyd_parse(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
-        LYD_FORMAT format, uint32_t parse_opts, uint32_t val_opts, struct lyd_node **op)
+lyd_parse(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent, struct lyd_node **first_p,
+        struct ly_in *in, LYD_FORMAT format, uint32_t parse_opts, uint32_t val_opts, struct lyd_node **op)
 {
     LY_ERR rc = LY_SUCCESS;
     struct lyd_ctx *lydctx = NULL;
@@ -331,13 +332,13 @@
     /* parse the data */
     switch (format) {
     case LYD_XML:
-        rc = lyd_parse_xml(ctx, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, NULL, &parsed, &lydctx);
+        rc = lyd_parse_xml(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, NULL, &parsed, &lydctx);
         break;
     case LYD_JSON:
-        rc = lyd_parse_json(ctx, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed, &lydctx);
+        rc = lyd_parse_json(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed, &lydctx);
         break;
     case LYD_LYB:
-        rc = lyd_parse_lyb(ctx, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed, &lydctx);
+        rc = lyd_parse_lyb(ctx, ext, parent, first_p, in, parse_opts, val_opts, LYD_TYPE_DATA_YANG, &parsed, &lydctx);
         break;
     case LYD_UNKNOWN:
         LOGARG(ctx, format);
@@ -386,6 +387,19 @@
 }
 
 API LY_ERR
+lyd_parse_ext_data(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
+        uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree)
+{
+    const struct ly_ctx *ctx = ext ? ext->module->ctx : NULL;
+
+    LY_CHECK_ARG_RET(ctx, ext, in, parent || tree, LY_EINVAL);
+    LY_CHECK_ARG_RET(ctx, !(parse_options & ~LYD_PARSE_OPTS_MASK), LY_EINVAL);
+    LY_CHECK_ARG_RET(ctx, !(validate_options & ~LYD_VALIDATE_OPTS_MASK), LY_EINVAL);
+
+    return lyd_parse(ctx, ext, parent, tree, in, format, parse_options, validate_options, NULL);
+}
+
+API LY_ERR
 lyd_parse_data(const struct ly_ctx *ctx, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
         uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree)
 {
@@ -393,7 +407,7 @@
     LY_CHECK_ARG_RET(ctx, !(parse_options & ~LYD_PARSE_OPTS_MASK), LY_EINVAL);
     LY_CHECK_ARG_RET(ctx, !(validate_options & ~LYD_VALIDATE_OPTS_MASK), LY_EINVAL);
 
-    return lyd_parse(ctx, parent, tree, in, format, parse_options, validate_options, NULL);
+    return lyd_parse(ctx, NULL, parent, tree, in, format, parse_options, validate_options, NULL);
 }
 
 API LY_ERR
@@ -438,9 +452,49 @@
     return ret;
 }
 
-API LY_ERR
-lyd_parse_op(const struct ly_ctx *ctx, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
-        enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op)
+/**
+ * @brief Parse YANG data into an operation data tree, in case the extension instance is specified, keep the searching
+ * for schema nodes locked inside the extension instance.
+ *
+ * At least one of @p parent, @p tree, or @p op must always be set.
+ *
+ * Specific @p data_type values have different parameter meaning as follows:
+ * - ::LYD_TYPE_RPC_NETCONF:
+ *   - @p parent - must be NULL, the whole RPC is expected;
+ *   - @p format - must be ::LYD_XML, NETCONF supports only this format;
+ *   - @p tree - must be provided, all the NETCONF-specific XML envelopes will be returned here as
+ *               a separate opaque data tree, even if the function fails, this may be returned;
+ *   - @p op - must be provided, the RPC/action data tree itself will be returned here, pointing to the operation;
+ *
+ * - ::LYD_TYPE_NOTIF_NETCONF:
+ *   - @p parent - must be NULL, the whole notification is expected;
+ *   - @p format - must be ::LYD_XML, NETCONF supports only this format;
+ *   - @p tree - must be provided, all the NETCONF-specific XML envelopes will be returned here as
+ *               a separate opaque data tree, even if the function fails, this may be returned;
+ *   - @p op - must be provided, the notification data tree itself will be returned here, pointing to the operation;
+ *
+ * - ::LYD_TYPE_REPLY_NETCONF:
+ *   - @p parent - must be set, pointing to the invoked RPC operation (RPC or action) node;
+ *   - @p format - must be ::LYD_XML, NETCONF supports only this format;
+ *   - @p tree - must be provided, all the NETCONF-specific XML envelopes will be returned here as
+ *               a separate opaque data tree, even if the function fails, this may be returned;
+ *   - @p op - must be NULL, the reply is appended to the RPC;
+ *   Note that there are 3 kinds of NETCONF replies - ok, error, and data. Only data reply appends any nodes to the RPC.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] ext Extension instance providing the specific schema tree to match with the data being parsed.
+ * @param[in] parent Optional parent to connect the parsed nodes to.
+ * @param[in] in Input handle to read the input from.
+ * @param[in] format Expected format of the data in @p in.
+ * @param[in] data_type Expected operation to parse (@ref datatype).
+ * @param[out] tree Optional full parsed data tree. If @p parent is set, set to NULL.
+ * @param[out] op Optional parsed operation node.
+ * @return LY_ERR value.
+ * @return LY_ENOT if @p data_type is a NETCONF message and the root XML element is not the expected one.
+ */
+static LY_ERR
+lyd_parse_op_(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
+        struct ly_in *in, LYD_FORMAT format, enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op)
 {
     LY_ERR rc = LY_SUCCESS;
     struct lyd_ctx *lydctx = NULL;
@@ -448,7 +502,6 @@
     struct lyd_node *first = NULL, *envp = NULL;
     uint32_t i, parse_opts, val_opts;
 
-    LY_CHECK_ARG_RET(ctx, ctx || parent, in, data_type, parent || tree || op, LY_EINVAL);
     if (!ctx) {
         ctx = LYD_CTX(parent);
     }
@@ -477,7 +530,7 @@
     /* parse the data */
     switch (format) {
     case LYD_XML:
-        rc = lyd_parse_xml(ctx, parent, &first, in, parse_opts, val_opts, data_type, &envp, &parsed, &lydctx);
+        rc = lyd_parse_xml(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &envp, &parsed, &lydctx);
         if (rc && envp) {
             /* special situation when the envelopes were parsed successfully */
             if (tree) {
@@ -488,10 +541,10 @@
         }
         break;
     case LYD_JSON:
-        rc = lyd_parse_json(ctx, parent, &first, in, parse_opts, val_opts, data_type, &parsed, &lydctx);
+        rc = lyd_parse_json(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &parsed, &lydctx);
         break;
     case LYD_LYB:
-        rc = lyd_parse_lyb(ctx, parent, &first, in, parse_opts, val_opts, data_type, &parsed, &lydctx);
+        rc = lyd_parse_lyb(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &parsed, &lydctx);
         break;
     case LYD_UNKNOWN:
         LOGARG(ctx, format);
@@ -538,6 +591,26 @@
     return rc;
 }
 
+API LY_ERR
+lyd_parse_op(const struct ly_ctx *ctx, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
+        enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op)
+{
+    LY_CHECK_ARG_RET(ctx, ctx || parent, in, data_type, parent || tree || op, LY_EINVAL);
+
+    return lyd_parse_op_(ctx, NULL, parent, in, format, data_type, tree, op);
+}
+
+API LY_ERR
+lyd_parse_ext_op(const struct lysc_ext_instance *ext, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
+        enum lyd_type data_type, struct lyd_node **tree, struct lyd_node **op)
+{
+    const struct ly_ctx *ctx = ext ? ext->module->ctx : NULL;
+
+    LY_CHECK_ARG_RET(ctx, ext, in, data_type, parent || tree || op, LY_EINVAL);
+
+    return lyd_parse_op_(ctx, ext, parent, in, format, data_type, tree, op);
+}
+
 LY_ERR
 lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_len, ly_bool *dynamic,
         LY_PREFIX_FORMAT format, void *prefix_data, uint32_t hints, ly_bool *incomplete, struct lyd_node **node)
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 9a6e3ff..4470fbe 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -400,6 +400,39 @@
     return lys_getnext_(last, parent, NULL, ext, options);
 }
 
+const struct lysc_node *
+lys_find_ext_instance_node(const struct lysc_ext_instance *ext, const struct lys_module *module, const char *name, size_t name_len,
+        uint16_t nodetype, uint32_t options)
+{
+    const struct lysc_node *node = NULL;
+
+    LY_CHECK_ARG_RET(NULL, ext, name, NULL);
+    if (!nodetype) {
+        nodetype = LYS_NODETYPE_MASK;
+    }
+
+    if (module && (module != ext->module)) {
+        return NULL;
+    }
+
+    while ((node = lys_getnext_ext(node, NULL, ext, options))) {
+        if (!(node->nodetype & nodetype)) {
+            continue;
+        }
+
+        if (name_len) {
+            if (!ly_strncmp(node->name, name, name_len)) {
+                return node;
+            }
+        } else {
+            if (!strcmp(node->name, name)) {
+                return node;
+            }
+        }
+    }
+    return NULL;
+}
+
 API const struct lysc_node *
 lys_find_child(const struct lysc_node *parent, const struct lys_module *module, const char *name, size_t name_len,
         uint16_t nodetype, uint32_t options)
diff --git a/tests/utests/extensions/test_yangdata.c b/tests/utests/extensions/test_yangdata.c
index 357dcab..9829e36 100644
--- a/tests/utests/extensions/test_yangdata.c
+++ b/tests/utests/extensions/test_yangdata.c
@@ -234,12 +234,40 @@
             "/a:{extension='rc:yang-data'}/template");
 }
 
+static void
+test_data(void **state)
+{
+    const struct lys_module *mod;
+    struct lysc_ext_instance *e;
+    struct lyd_node *tree = NULL;
+    const char *schema = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
+            "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
+            "rc:yang-data template { container x { leaf x { type string;}}}}";
+    const char *xml = "<x xmlns=\"urn:tests:extensions:yangdata:a\"><x>test</x></x>";
+    const char *json = "{\"a:x\":{\"x\":\"test\"}}";
+
+    assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, &mod));
+    assert_non_null(e = mod->compiled->exts);
+
+    assert_int_equal(LY_SUCCESS, ly_in_new_memory(xml, &UTEST_IN));
+    assert_int_equal(LY_SUCCESS, lyd_parse_ext_data(e, NULL, UTEST_IN, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+    CHECK_LYD_STRING_PARAM(tree, xml, LYD_XML, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
+    lyd_free_all(tree);
+
+    ly_in_memory(UTEST_IN, json);
+    assert_int_equal(LY_SUCCESS, lyd_parse_ext_data(e, NULL, UTEST_IN, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+    CHECK_LYD_STRING_PARAM(tree, json, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
+
+    lyd_free_all(tree);
+}
+
 int
 main(void)
 {
     const struct CMUnitTest tests[] = {
         UTEST(test_schema, setup),
         UTEST(test_schema_invalid, setup),
+        UTEST(test_data, setup),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);