tree schema REFACTOR move ext definitions to plugins_exts header
diff --git a/CMakeLists.txt b/CMakeLists.txt
index faad765..6ba8468 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -170,6 +170,7 @@
     src/plugins_exts.h
     src/plugins_exts_compile.h
     src/plugins_exts_print.h
+    src/plugins_exts/metadata.h
     src/plugins_types.h
     src/printer_data.h
     src/printer_schema.h
diff --git a/src/diff.c b/src/diff.c
index b01acbc..80b939c 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -27,6 +27,7 @@
 #include "context.h"
 #include "log.h"
 #include "plugins_exts.h"
+#include "plugins_exts/metadata.h"
 #include "plugins_types.h"
 #include "set.h"
 #include "tree.h"
diff --git a/src/libyang.h b/src/libyang.h
index 49657f7..9b636af 100644
--- a/src/libyang.h
+++ b/src/libyang.h
@@ -1,9 +1,10 @@
 /**
  * @file libyang.h
  * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief The main libyang public header.
  *
- * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
+ * Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -37,6 +38,7 @@
 
 /*
  * The following headers are supposed to be included explicitly:
+ * - metadata.h
  * - plugins_types.h
  * - plugins_exts.h
  */
diff --git a/src/parser_common.c b/src/parser_common.c
index 79a0f44..4a0e421 100644
--- a/src/parser_common.c
+++ b/src/parser_common.c
@@ -45,6 +45,7 @@
 #include "log.h"
 #include "parser_data.h"
 #include "path.h"
+#include "plugins_exts/metadata.h"
 #include "set.h"
 #include "tree.h"
 #include "tree_data.h"
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index 0e6bf9c..cacda64 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -31,6 +31,7 @@
 #include "parser_data.h"
 #include "parser_internal.h"
 #include "plugins_exts.h"
+#include "plugins_exts/metadata.h"
 #include "set.h"
 #include "tree.h"
 #include "tree_data.h"
diff --git a/src/plugins_exts.h b/src/plugins_exts.h
index 2c264a7..33199ca 100644
--- a/src/plugins_exts.h
+++ b/src/plugins_exts.h
@@ -30,6 +30,7 @@
 struct ly_in;
 struct lyd_node;
 struct lysc_ext_substmt;
+struct lysp_ctx;
 struct lysp_ext_instance;
 
 #ifdef __cplusplus
@@ -105,6 +106,254 @@
 #define LYPLG_EXT_API_VERSION 6
 
 /**
+ * @brief Generic test for operation statements.
+ *
+ * This macro matches a subset of schema nodes that maps to common ::lysc_node or ::lysp_node structures. To match all
+ * such nodes, use ::LY_STMT_IS_NODE()
+ *
+ * This macro matches action and RPC.
+ */
+#define LY_STMT_IS_OP(STMT) (((STMT) == LY_STMT_ACTION) || ((STMT) == LY_STMT_RPC))
+
+/**
+ * @brief Generic test for schema data nodes.
+ *
+ * This macro matches a subset of schema nodes that maps to common ::lysc_node or ::lysp_node structures. To match all
+ * such nodes, use ::LY_STMT_IS_NODE()
+ *
+ * This macro matches anydata, anyxml, case, choice, container, leaf, leaf-list, and list.
+ */
+#define LY_STMT_IS_DATA_NODE(STMT) (((STMT) == LY_STMT_ANYDATA) || ((STMT) == LY_STMT_ANYXML) || \
+        ((STMT) == LY_STMT_CASE) || ((STMT) == LY_STMT_CHOICE) || ((STMT) == LY_STMT_CONTAINER) || \
+        ((STMT) == LY_STMT_LEAF) || ((STMT) == LY_STMT_LEAF_LIST) || ((STMT) == LY_STMT_LIST))
+
+/**
+ * @brief Generic test for any schema node that maps to common ::lysc_node or ::lysp_node structures.
+ *
+ * Note that the list of statements that can appear in parsed or compiled schema trees differs (e.g. no uses in compiled tree).
+ *
+ * To check for some of the subsets of this test, try ::LY_STMT_IS_DATA_NODE() or ::LY_STMT_IS_OP().
+ *
+ * This macro matches action, anydata, anyxml, augment, case, choice, container, grouping, input, leaf, leaf-list, list,
+ * notification, output, RPC and uses.
+ */
+#define LY_STMT_IS_NODE(STMT) (((STMT) >= LY_STMT_NOTIFICATION) && ((STMT) <= LY_STMT_LIST))
+
+/**
+ * @brief List of YANG statements
+ */
+enum ly_stmt {
+    LY_STMT_NONE = 0,
+
+    LY_STMT_NOTIFICATION,       /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node_notif *`.
+                                     The RPCs/Actions and Notifications are expected in a separated lists than the rest of
+                                     data definition nodes as it is done in generic structures of libyang. */
+    LY_STMT_INPUT,
+    LY_STMT_OUTPUT,
+    LY_STMT_ACTION,             /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node_action *`.
+                                     The RPCs/Actions and Notifications are expected in a separated lists than the rest of
+                                     data definition nodes as it is done in generic structures of libyang. */
+    LY_STMT_RPC,                /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node_action *`.
+                                     The RPCs/Actions and Notifications are expected in a separated lists than the rest of
+                                     data definition nodes as it is done in generic structures of libyang. */
+    LY_STMT_ANYDATA,            /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
+                                     Note that due to ::lysc_node compatibility the anydata is expected to be actually
+                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
+                                     Notifications are expected in a separated lists as it is done in generic structures
+                                     of libyang. */
+    LY_STMT_ANYXML,             /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
+                                     Note that due to ::lysc_node compatibility the anyxml is expected to be actually
+                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
+                                     Notifications are expected in a separated lists as it is done in generic structures
+                                     of libyang. */
+    LY_STMT_AUGMENT,
+    LY_STMT_CASE,               /**< TODO is it possible to compile cases without the parent choice? */
+    LY_STMT_CHOICE,             /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
+                                     Note that due to ::lysc_node compatibility the choice is expected to be actually
+                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
+                                     Notifications are expected in a separated lists as it is done in generic structures
+                                     of libyang. */
+    LY_STMT_CONTAINER,          /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
+                                     Note that due to ::lysc_node compatibility the container is expected to be actually
+                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
+                                     Notifications are expected in a separated lists as it is done in generic structures
+                                     of libyang. */
+    LY_STMT_GROUPING,
+    LY_STMT_LEAF,               /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
+                                     Note that due to ::lysc_node compatibility the leaf is expected to be actually
+                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
+                                     Notifications are expected in a separated lists as it is done in generic structures
+                                     of libyang. */
+    LY_STMT_LEAF_LIST,          /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
+                                     Note that due to ::lysc_node compatibility the leaf-list is expected to be actually
+                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
+                                     Notifications are expected in a separated lists as it is done in generic structures
+                                     of libyang. */
+    LY_STMT_LIST,               /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
+                                     Note that due to ::lysc_node compatibility the list is expected to be actually
+                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
+                                     Notifications are expected in a separated lists as it is done in generic structures
+                                     of libyang. */
+    LY_STMT_USES,
+
+    LY_STMT_ARGUMENT,
+    LY_STMT_BASE,
+    LY_STMT_BELONGS_TO,
+    LY_STMT_BIT,
+    LY_STMT_CONFIG,             /**< in ::lysc_ext_substmt.storage stored as a pointer to `uint16_t`, only cardinality < #LY_STMT_CARD_SOME is allowed */
+    LY_STMT_CONTACT,
+    LY_STMT_DEFAULT,
+    LY_STMT_DESCRIPTION,        /**< in ::lysc_ext_substmt.storage stored as a pointer to `const char *` (cardinality < #LY_STMT_CARD_SOME)
+                                     or as a pointer to a [sized array](@ref sizedarrays) `const char **` */
+    LY_STMT_DEVIATE,
+    LY_STMT_DEVIATION,
+    LY_STMT_ENUM,
+    LY_STMT_ERROR_APP_TAG,
+    LY_STMT_ERROR_MESSAGE,
+    LY_STMT_EXTENSION,
+    LY_STMT_EXTENSION_INSTANCE,
+    LY_STMT_FEATURE,
+    LY_STMT_FRACTION_DIGITS,
+    LY_STMT_IDENTITY,
+    LY_STMT_IF_FEATURE,         /**< if-feature statements are not compiled, they are evaluated and the parent statement is
+                                     preserved only in case the evaluation of all the if-feature statements is true.
+                                     Therefore there is no storage expected. */
+    LY_STMT_IMPORT,
+    LY_STMT_INCLUDE,
+    LY_STMT_KEY,
+    LY_STMT_LENGTH,
+    LY_STMT_MANDATORY,          /**< in ::lysc_ext_substmt.storage stored as a pointer to `uint16_t`, only cardinality < #LY_STMT_CARD_SOME is allowed */
+    LY_STMT_MAX_ELEMENTS,
+    LY_STMT_MIN_ELEMENTS,
+    LY_STMT_MODIFIER,
+    LY_STMT_MODULE,
+    LY_STMT_MUST,
+    LY_STMT_NAMESPACE,
+    LY_STMT_ORDERED_BY,
+    LY_STMT_ORGANIZATION,
+    LY_STMT_PATH,
+    LY_STMT_PATTERN,
+    LY_STMT_POSITION,
+    LY_STMT_PREFIX,
+    LY_STMT_PRESENCE,
+    LY_STMT_RANGE,
+    LY_STMT_REFERENCE,          /**< in ::lysc_ext_substmt.storage stored as a pointer to `const char *` (cardinality < #LY_STMT_CARD_SOME)
+                                     or as a pointer to a [sized array](@ref sizedarrays) `const char **` */
+    LY_STMT_REFINE,
+    LY_STMT_REQUIRE_INSTANCE,
+    LY_STMT_REVISION,
+    LY_STMT_REVISION_DATE,
+    LY_STMT_STATUS,             /**< in ::lysc_ext_substmt.storage stored as a pointer to `uint16_t`, only cardinality < #LY_STMT_CARD_SOME is allowed */
+    LY_STMT_SUBMODULE,
+    LY_STMT_TYPE,               /**< in ::lysc_ext_substmt.storage stored as a pointer to `struct lysc_type *` (cardinality < #LY_STMT_CARD_SOME)
+                                     or as a pointer to a [sized array](@ref sizedarrays) `struct lysc_type **` */
+    LY_STMT_TYPEDEF,
+    LY_STMT_UNIQUE,
+    LY_STMT_UNITS,              /**< in ::lysc_ext_substmt.storage stored as a pointer to `const char *` (cardinality < #LY_STMT_CARD_SOME)
+                                     or as a pointer to a [sized array](@ref sizedarrays) `const char **` */
+    LY_STMT_VALUE,
+    LY_STMT_WHEN,
+    LY_STMT_YANG_VERSION,
+    LY_STMT_YIN_ELEMENT,
+
+    /* separated from the list of statements
+     * the following tokens are part of the syntax and parsers have to work
+     * with them, but they are not a standard YANG statements
+     */
+    LY_STMT_SYNTAX_SEMICOLON,
+    LY_STMT_SYNTAX_LEFT_BRACE,
+    LY_STMT_SYNTAX_RIGHT_BRACE,
+
+    /*
+     * YIN-specific tokens, still they are part of the syntax, but not the standard statements
+     */
+    LY_STMT_ARG_TEXT,
+    LY_STMT_ARG_VALUE
+};
+
+/**
+ * @brief Possible cardinalities of the YANG statements.
+ *
+ * Used in extensions plugins to define cardinalities of the extension instance substatements.
+ */
+enum ly_stmt_cardinality {
+    LY_STMT_CARD_OPT,    /* 0..1 */
+    LY_STMT_CARD_MAND,   /* 1 */
+    LY_STMT_CARD_SOME,   /* 1..n */
+    LY_STMT_CARD_ANY     /* 0..n */
+};
+
+/**
+ * @brief Helper structure for generic storage of the extension instances content.
+ */
+struct lysp_stmt {
+    const char *stmt;                /**< identifier of the statement */
+    const char *arg;                 /**< statement's argument */
+    LY_VALUE_FORMAT format;          /**< prefix format of the identifier/argument (::LY_VALUE_XML is YIN format) */
+    void *prefix_data;               /**< Format-specific data for prefix resolution (see ly_resolve_prefix()) */
+
+    struct lysp_stmt *next;          /**< link to the next statement */
+    struct lysp_stmt *child;         /**< list of the statement's substatements (linked list) */
+    uint16_t flags;                  /**< statement flags, can be set to LYS_YIN_ATTR */
+    enum ly_stmt kw;                 /**< numeric respresentation of the stmt value */
+};
+
+/**
+ * @brief YANG extension instance
+ */
+struct lysp_ext_instance {
+    const char *name;                       /**< extension identifier, including possible prefix */
+    const char *argument;                   /**< optional value of the extension's argument */
+    LY_VALUE_FORMAT format;                 /**< prefix format of the extension name/argument (::LY_VALUE_XML is YIN format) */
+    struct lysp_node *parsed;               /**< Simply parsed (unresolved) YANG schema tree serving as a cache.
+                                                 Only ::lys_compile_extension_instance() can set this. */
+    void *prefix_data;                      /**< Format-specific data for prefix resolution
+                                                 (see ly_resolve_prefix()) */
+
+    struct lysp_stmt *child;                /**< list of the extension's substatements (linked list) */
+
+    void *parent;                           /**< pointer to the parent element holding the extension instance(s), use
+                                                 ::lysp_ext_instance#parent_stmt to access the schema element */
+    enum ly_stmt parent_stmt;               /**< value identifying placement of the extension instance */
+    LY_ARRAY_COUNT_TYPE parent_stmt_index;  /**< in case the instance is in a substatement, this identifies
+                                                 the index of that substatement in its [sized array](@ref sizedarrays) (if any) */
+    uint16_t flags;                         /**< LYS_INTERNAL value (@ref snodeflags) */
+    const struct lyplg_ext_record *record;  /**< extension defintion plugin record, if any */
+};
+
+/**
+ * @brief Description of the extension instance substatements.
+ *
+ * Provided by extensions plugins to libyang to be able to correctly compile the content of extension instances.
+ * Note that order of the defined records matters - just follow the values of ::ly_stmt and order the records from lower to higher values.
+ */
+struct lysc_ext_substmt {
+    enum ly_stmt stmt;                     /**< allowed substatement */
+    enum ly_stmt_cardinality cardinality;  /**< cardinality of the substatement */
+    void *storage;                         /**< pointer to the storage of the compiled statement according to the specific
+                                                lysc_ext_substmt::stmt and lysc_ext_substmt::cardinality */
+};
+
+/**
+ * @brief YANG extension instance
+ */
+struct lysc_ext_instance {
+    struct lysc_ext *def;            /**< pointer to the extension definition */
+    const char *argument;            /**< optional value of the extension's argument */
+    struct lys_module *module;       /**< module where the extension instantiated is defined */
+    struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+    struct lysc_ext_substmt *substmts; /**< list of allowed substatements with the storage to access the present
+                                          substatements ([sized array](@ref sizedarrays)) */
+    void *data;                      /**< private plugins's data, not used by libyang */
+
+    void *parent;                    /**< pointer to the parent element holding the extension instance(s), use
+                                          ::lysc_ext_instance#parent_stmt to access the schema element */
+    enum ly_stmt parent_stmt;        /**< value identifying placement of the extension instance in specific statement */
+    LY_ARRAY_COUNT_TYPE parent_stmt_index; /**< in case the instance is in a substatement, this identifies
+                                          the index of that substatement in its [sized array](@ref sizedarrays) (if any) */
+};
+
+/**
  * @brief Macro to define plugin information in external plugins
  *
  * Use as follows:
@@ -114,14 +363,6 @@
     uint32_t plugins_extensions_apiver__ = LYPLG_EXT_API_VERSION; \
     const struct lyplg_ext_record plugins_extensions__[]
 
-/**
- * @brief Free the extension instance's data compiled with ::lys_compile_extension_instance().
- *
- * @param[in] ctx libyang context
- * @param[in] substmts The sized array of extension instance's substatements. The whole array is freed except the storage
- * places which are expected to be covered by the extension plugin.
- */
-LIBYANG_API_DECL void lyplg_ext_instance_substatements_free(struct ly_ctx *ctx, struct lysc_ext_substmt *substmts);
 
 /**
  * @brief Callback to compile extension from the lysp_ext_instance to the lysc_ext_instance. The later structure is generally prepared
@@ -247,6 +488,39 @@
 };
 
 /**
+ * @brief Stringify statement identifier.
+ *
+ * @param[in] stmt The statement identifier to stringify.
+ * @return Constant string representation of the given @p stmt.
+ */
+LIBYANG_API_DECL const char *ly_stmt2str(enum ly_stmt stmt);
+
+/**
+ * @brief Stringify statement cardinality.
+ *
+ * @param[in] card The cardinality to stringify.
+ * @return Constant string representation of the given @p card.
+ */
+LIBYANG_API_DECL const char *ly_cardinality2str(enum ly_stmt_cardinality card);
+
+/**
+ * @brief Convert nodetype to statement identifier
+ *
+ * @param[in] nodetype Nodetype to convert.
+ * @return Statement identifier representing the given @p nodetype.
+ */
+LIBYANG_API_DECL enum ly_stmt lys_nodetype2stmt(uint16_t nodetype);
+
+/**
+ * @brief Free the extension instance's data compiled with ::lys_compile_extension_instance().
+ *
+ * @param[in] ctx libyang context
+ * @param[in] substmts The sized array of extension instance's substatements. The whole array is freed except the storage
+ * places which are expected to be covered by the extension plugin.
+ */
+LIBYANG_API_DECL void lyplg_ext_instance_substatements_free(struct ly_ctx *ctx, struct lysc_ext_substmt *substmts);
+
+/**
  * @brief Get specific run-time extension instance data from a callback set by ::ly_ctx_set_ext_data_clb().
  *
  * @param[in] ctx Context with the callback.
@@ -302,6 +576,25 @@
  */
 LIBYANG_API_DECL LY_ERR lyplg_ext_schema_mount_create_context(const struct lysc_ext_instance *ext, struct ly_ctx **ctx);
 
+/**
+ * @brief Get pointer to the storage of the specified substatement in the given extension instance.
+ *
+ * The function simplifies access into the ::lysc_ext_instance.substmts sized array.
+ *
+ * @param[in] ext Compiled extension instance to process.
+ * @param[in] substmt Extension substatement to search for.
+ * @param[out] instance_p Pointer where the storage of the @p substmt will be provided. The specific type returned depends
+ * on the @p substmt and can be found in the documentation of each ::ly_stmt value. Also note that some of the substatements
+ * (::lysc_node based or flags) can share the storage with other substatements. In case the pointer is NULL, still the return
+ * code can be used to at least know if the substatement is allowed for the extension.
+ * @param[out] cardinality_p Pointer to provide allowed cardinality of the substatements in the extension. Note that in some
+ * cases, the type of the storage depends also on the cardinality of the substatement.
+ * @return LY_SUCCESS if the @p substmt found.
+ * @return LY_ENOT in case the @p ext is not able to store (does not allow) the specified @p substmt.
+ */
+LIBYANG_API_DECL LY_ERR lysc_ext_substmt(const struct lysc_ext_instance *ext, enum ly_stmt substmt,
+        void **instance_p, enum ly_stmt_cardinality *cardinality_p);
+
 /** @} pluginsExtensions */
 
 #ifdef __cplusplus
diff --git a/src/plugins_exts/metadata.h b/src/plugins_exts/metadata.h
index f9dbd12..6387e1f 100644
--- a/src/plugins_exts/metadata.h
+++ b/src/plugins_exts/metadata.h
@@ -1,9 +1,10 @@
 /**
  * @file metadata.h
  * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief ietf-yang-metadata API
  *
- * Copyright (c) 2019 CESNET, z.s.p.o.
+ * Copyright (c) 2019 - 2022 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -15,6 +16,9 @@
 #ifndef LY_PLUGINS_EXTS_METADATA_H_
 #define LY_PLUGINS_EXTS_METADATA_H_
 
+#include "plugins_exts.h"
+#include "tree_data.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -26,6 +30,42 @@
 #define ANNOTATION_SUBSTMT_DSC     4 /**< index for the LY_STMT_DSC substatement in annotation's ::lysc_ext_instance.substmts */
 #define ANNOTATION_SUBSTMT_REF     5 /**< index for the LY_STMT_REF substatement in annotation's ::lysc_ext_instance.substmts */
 
+/**
+ * @brief Metadata structure.
+ *
+ * The structure provides information about metadata of a data element. Such attributes must map to
+ * annotations as specified in RFC 7952. The only exception is the filter type (in NETCONF get operations)
+ * and edit-config's operation attributes. In XML, they are represented as standard XML attributes. In JSON,
+ * they are represented as JSON elements starting with the '@' character (for more information, see the
+ * YANG metadata RFC.
+ *
+ */
+struct lyd_meta {
+    struct lyd_node *parent;         /**< data node where the metadata is placed */
+    struct lyd_meta *next;           /**< pointer to the next metadata of the same element */
+    struct lysc_ext_instance *annotation; /**< pointer to the annotation's definition */
+    const char *name;                /**< metadata name */
+    struct lyd_value value;          /**< metadata value representation */
+};
+
+/**
+ * @brief Get the (canonical) value of a metadata node.
+ *
+ * @param[in] meta Metadata node to use.
+ * @return Canonical value.
+ */
+static inline const char *
+lyd_get_meta_value(const struct lyd_meta *meta)
+{
+    if (meta) {
+        const struct lyd_value *value = &meta->value;
+
+        return value->_canonical ? value->_canonical : lyd_value_get_canonical(meta->annotation->module->ctx, value);
+    }
+
+    return NULL;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/printer_json.c b/src/printer_json.c
index 31886c9..3c7a6fd 100644
--- a/src/printer_json.c
+++ b/src/printer_json.c
@@ -22,6 +22,7 @@
 #include "out.h"
 #include "out_internal.h"
 #include "parser_data.h"
+#include "plugins_exts/metadata.h"
 #include "plugins_types.h"
 #include "printer_data.h"
 #include "printer_internal.h"
diff --git a/src/printer_lyb.c b/src/printer_lyb.c
index cf373f9..f1583ee 100644
--- a/src/printer_lyb.c
+++ b/src/printer_lyb.c
@@ -27,6 +27,7 @@
 #include "log.h"
 #include "out.h"
 #include "out_internal.h"
+#include "plugins_exts/metadata.h"
 #include "printer_data.h"
 #include "printer_internal.h"
 #include "set.h"
diff --git a/src/printer_xml.c b/src/printer_xml.c
index 267fb09..b4921c0 100644
--- a/src/printer_xml.c
+++ b/src/printer_xml.c
@@ -25,6 +25,7 @@
 #include "out.h"
 #include "out_internal.h"
 #include "parser_data.h"
+#include "plugins_exts/metadata.h"
 #include "plugins_types.h"
 #include "printer_data.h"
 #include "printer_internal.h"
diff --git a/src/schema_compile.h b/src/schema_compile.h
index 919a994..5d60c26 100644
--- a/src/schema_compile.h
+++ b/src/schema_compile.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 
 #include "log.h"
+#include "plugins_exts.h"
 #include "set.h"
 #include "tree.h"
 #include "tree_schema.h"
diff --git a/src/tree_data.h b/src/tree_data.h
index 1414bcc..39a3344 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -710,24 +710,6 @@
 };
 
 /**
- * @brief Metadata structure.
- *
- * The structure provides information about metadata of a data element. Such attributes must map to
- * annotations as specified in RFC 7952. The only exception is the filter type (in NETCONF get operations)
- * and edit-config's operation attributes. In XML, they are represented as standard XML attributes. In JSON,
- * they are represented as JSON elements starting with the '@' character (for more information, see the
- * YANG metadata RFC.
- *
- */
-struct lyd_meta {
-    struct lyd_node *parent;         /**< data node where the metadata is placed */
-    struct lyd_meta *next;           /**< pointer to the next metadata of the same element */
-    struct lysc_ext_instance *annotation; /**< pointer to the annotation's definition */
-    const char *name;                /**< metadata name */
-    struct lyd_value value;          /**< metadata value representation */
-};
-
-/**
  * @brief Generic prefix and namespace mapping, meaning depends on the format.
  *
  * The union is used as a reference to the data's module and according to the format, it can be used as a key for
@@ -1170,24 +1152,6 @@
 }
 
 /**
- * @brief Get the (canonical) value of a metadata node.
- *
- * @param[in] meta Metadata node to use.
- * @return Canonical value.
- */
-static inline const char *
-lyd_get_meta_value(const struct lyd_meta *meta)
-{
-    if (meta) {
-        const struct lyd_value *value = &meta->value;
-
-        return value->_canonical ? value->_canonical : lyd_value_get_canonical(meta->annotation->module->ctx, value);
-    }
-
-    return NULL;
-}
-
-/**
  * @brief Get anydata string value.
  *
  * @param[in] any Anyxml/anydata node to read from.
diff --git a/src/tree_data_free.c b/src/tree_data_free.c
index 88c3b34..bf17a91 100644
--- a/src/tree_data_free.c
+++ b/src/tree_data_free.c
@@ -19,6 +19,7 @@
 #include "dict.h"
 #include "hash_table.h"
 #include "log.h"
+#include "plugins_exts/metadata.h"
 #include "plugins_types.h"
 #include "tree.h"
 #include "tree_data.h"
diff --git a/src/tree_schema.h b/src/tree_schema.h
index f23c6fb..8a6b2a3 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -260,208 +260,6 @@
 /** @} schemanodetypes */
 
 /**
- * @brief Generic test for operation statements.
- *
- * This macro matches a subset of schema nodes that maps to common ::lysc_node or ::lysp_node structures. To match all
- * such nodes, use ::LY_STMT_IS_NODE()
- *
- * This macro matches action and RPC.
- */
-#define LY_STMT_IS_OP(STMT) (((STMT) == LY_STMT_ACTION) || ((STMT) == LY_STMT_RPC))
-
-/**
- * @brief Generic test for schema data nodes.
- *
- * This macro matches a subset of schema nodes that maps to common ::lysc_node or ::lysp_node structures. To match all
- * such nodes, use ::LY_STMT_IS_NODE()
- *
- * This macro matches anydata, anyxml, case, choice, container, leaf, leaf-list, and list.
- */
-#define LY_STMT_IS_DATA_NODE(STMT) (((STMT) == LY_STMT_ANYDATA) || ((STMT) == LY_STMT_ANYXML) || \
-        ((STMT) == LY_STMT_CASE) || ((STMT) == LY_STMT_CHOICE) || ((STMT) == LY_STMT_CONTAINER) || \
-        ((STMT) == LY_STMT_LEAF) || ((STMT) == LY_STMT_LEAF_LIST) || ((STMT) == LY_STMT_LIST))
-
-/**
- * @brief Generic test for any schema node that maps to common ::lysc_node or ::lysp_node structures.
- *
- * Note that the list of statements that can appear in parsed or compiled schema trees differs (e.g. no uses in compiled tree).
- *
- * To check for some of the subsets of this test, try ::LY_STMT_IS_DATA_NODE() or ::LY_STMT_IS_OP().
- *
- * This macro matches action, anydata, anyxml, augment, case, choice, container, grouping, input, leaf, leaf-list, list,
- * notification, output, RPC and uses.
- */
-#define LY_STMT_IS_NODE(STMT) (((STMT) >= LY_STMT_NOTIFICATION) && ((STMT) <= LY_STMT_LIST))
-
-/**
- * @brief List of YANG statements
- */
-enum ly_stmt {
-    LY_STMT_NONE = 0,
-
-    LY_STMT_NOTIFICATION,       /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node_notif *`.
-                                     The RPCs/Actions and Notifications are expected in a separated lists than the rest of
-                                     data definition nodes as it is done in generic structures of libyang. */
-    LY_STMT_INPUT,
-    LY_STMT_OUTPUT,
-    LY_STMT_ACTION,             /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node_action *`.
-                                     The RPCs/Actions and Notifications are expected in a separated lists than the rest of
-                                     data definition nodes as it is done in generic structures of libyang. */
-    LY_STMT_RPC,                /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node_action *`.
-                                     The RPCs/Actions and Notifications are expected in a separated lists than the rest of
-                                     data definition nodes as it is done in generic structures of libyang. */
-    LY_STMT_ANYDATA,            /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
-                                     Note that due to ::lysc_node compatibility the anydata is expected to be actually
-                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
-                                     Notifications are expected in a separated lists as it is done in generic structures
-                                     of libyang. */
-    LY_STMT_ANYXML,             /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
-                                     Note that due to ::lysc_node compatibility the anyxml is expected to be actually
-                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
-                                     Notifications are expected in a separated lists as it is done in generic structures
-                                     of libyang. */
-    LY_STMT_AUGMENT,
-    LY_STMT_CASE,               /**< TODO is it possible to compile cases without the parent choice? */
-    LY_STMT_CHOICE,             /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
-                                     Note that due to ::lysc_node compatibility the choice is expected to be actually
-                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
-                                     Notifications are expected in a separated lists as it is done in generic structures
-                                     of libyang. */
-    LY_STMT_CONTAINER,          /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
-                                     Note that due to ::lysc_node compatibility the container is expected to be actually
-                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
-                                     Notifications are expected in a separated lists as it is done in generic structures
-                                     of libyang. */
-    LY_STMT_GROUPING,
-    LY_STMT_LEAF,               /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
-                                     Note that due to ::lysc_node compatibility the leaf is expected to be actually
-                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
-                                     Notifications are expected in a separated lists as it is done in generic structures
-                                     of libyang. */
-    LY_STMT_LEAF_LIST,          /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
-                                     Note that due to ::lysc_node compatibility the leaf-list is expected to be actually
-                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
-                                     Notifications are expected in a separated lists as it is done in generic structures
-                                     of libyang. */
-    LY_STMT_LIST,               /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
-                                     Note that due to ::lysc_node compatibility the list is expected to be actually
-                                     mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
-                                     Notifications are expected in a separated lists as it is done in generic structures
-                                     of libyang. */
-    LY_STMT_USES,
-
-    LY_STMT_ARGUMENT,
-    LY_STMT_BASE,
-    LY_STMT_BELONGS_TO,
-    LY_STMT_BIT,
-    LY_STMT_CONFIG,             /**< in ::lysc_ext_substmt.storage stored as a pointer to `uint16_t`, only cardinality < #LY_STMT_CARD_SOME is allowed */
-    LY_STMT_CONTACT,
-    LY_STMT_DEFAULT,
-    LY_STMT_DESCRIPTION,        /**< in ::lysc_ext_substmt.storage stored as a pointer to `const char *` (cardinality < #LY_STMT_CARD_SOME)
-                                     or as a pointer to a [sized array](@ref sizedarrays) `const char **` */
-    LY_STMT_DEVIATE,
-    LY_STMT_DEVIATION,
-    LY_STMT_ENUM,
-    LY_STMT_ERROR_APP_TAG,
-    LY_STMT_ERROR_MESSAGE,
-    LY_STMT_EXTENSION,
-    LY_STMT_EXTENSION_INSTANCE,
-    LY_STMT_FEATURE,
-    LY_STMT_FRACTION_DIGITS,
-    LY_STMT_IDENTITY,
-    LY_STMT_IF_FEATURE,         /**< if-feature statements are not compiled, they are evaluated and the parent statement is
-                                     preserved only in case the evaluation of all the if-feature statements is true.
-                                     Therefore there is no storage expected. */
-    LY_STMT_IMPORT,
-    LY_STMT_INCLUDE,
-    LY_STMT_KEY,
-    LY_STMT_LENGTH,
-    LY_STMT_MANDATORY,          /**< in ::lysc_ext_substmt.storage stored as a pointer to `uint16_t`, only cardinality < #LY_STMT_CARD_SOME is allowed */
-    LY_STMT_MAX_ELEMENTS,
-    LY_STMT_MIN_ELEMENTS,
-    LY_STMT_MODIFIER,
-    LY_STMT_MODULE,
-    LY_STMT_MUST,
-    LY_STMT_NAMESPACE,
-    LY_STMT_ORDERED_BY,
-    LY_STMT_ORGANIZATION,
-    LY_STMT_PATH,
-    LY_STMT_PATTERN,
-    LY_STMT_POSITION,
-    LY_STMT_PREFIX,
-    LY_STMT_PRESENCE,
-    LY_STMT_RANGE,
-    LY_STMT_REFERENCE,          /**< in ::lysc_ext_substmt.storage stored as a pointer to `const char *` (cardinality < #LY_STMT_CARD_SOME)
-                                     or as a pointer to a [sized array](@ref sizedarrays) `const char **` */
-    LY_STMT_REFINE,
-    LY_STMT_REQUIRE_INSTANCE,
-    LY_STMT_REVISION,
-    LY_STMT_REVISION_DATE,
-    LY_STMT_STATUS,             /**< in ::lysc_ext_substmt.storage stored as a pointer to `uint16_t`, only cardinality < #LY_STMT_CARD_SOME is allowed */
-    LY_STMT_SUBMODULE,
-    LY_STMT_TYPE,               /**< in ::lysc_ext_substmt.storage stored as a pointer to `struct lysc_type *` (cardinality < #LY_STMT_CARD_SOME)
-                                     or as a pointer to a [sized array](@ref sizedarrays) `struct lysc_type **` */
-    LY_STMT_TYPEDEF,
-    LY_STMT_UNIQUE,
-    LY_STMT_UNITS,              /**< in ::lysc_ext_substmt.storage stored as a pointer to `const char *` (cardinality < #LY_STMT_CARD_SOME)
-                                     or as a pointer to a [sized array](@ref sizedarrays) `const char **` */
-    LY_STMT_VALUE,
-    LY_STMT_WHEN,
-    LY_STMT_YANG_VERSION,
-    LY_STMT_YIN_ELEMENT,
-
-    /* separated from the list of statements
-     * the following tokens are part of the syntax and parsers have to work
-     * with them, but they are not a standard YANG statements
-     */
-    LY_STMT_SYNTAX_SEMICOLON,
-    LY_STMT_SYNTAX_LEFT_BRACE,
-    LY_STMT_SYNTAX_RIGHT_BRACE,
-
-    /*
-     * YIN-specific tokens, still they are part of the syntax, but not the standard statements
-     */
-    LY_STMT_ARG_TEXT,
-    LY_STMT_ARG_VALUE
-};
-
-/**
- * @brief Stringify statement identifier.
- *
- * @param[in] stmt The statement identifier to stringify.
- * @return Constant string representation of the given @p stmt.
- */
-LIBYANG_API_DECL const char *ly_stmt2str(enum ly_stmt stmt);
-
-/**
- * @brief Possible cardinalities of the YANG statements.
- *
- * Used in extensions plugins to define cardinalities of the extension instance substatements.
- */
-enum ly_stmt_cardinality {
-    LY_STMT_CARD_OPT,    /* 0..1 */
-    LY_STMT_CARD_MAND,   /* 1 */
-    LY_STMT_CARD_SOME,   /* 1..n */
-    LY_STMT_CARD_ANY     /* 0..n */
-};
-
-/**
- * @brief Stringify statement cardinality.
- *
- * @param[in] card The cardinality to stringify.
- * @return Constant string representation of the given @p card.
- */
-LIBYANG_API_DECL const char *ly_cardinality2str(enum ly_stmt_cardinality card);
-
-/**
- * @brief Convert nodetype to statement identifier
- *
- * @param[in] nodetype Nodetype to convert.
- * @return Statement identifier representing the given @p nodetype.
- */
-LIBYANG_API_DECL enum ly_stmt lys_nodetype2stmt(uint16_t nodetype);
-
-/**
  * @brief YANG import-stmt
  */
 struct lysp_import {
@@ -510,46 +308,6 @@
 };
 
 /**
- * @brief Helper structure for generic storage of the extension instances content.
- */
-struct lysp_stmt {
-    const char *stmt;                /**< identifier of the statement */
-    const char *arg;                 /**< statement's argument */
-    LY_VALUE_FORMAT format;          /**< prefix format of the identifier/argument (::LY_VALUE_XML is YIN format) */
-    void *prefix_data;               /**< Format-specific data for prefix resolution (see ly_resolve_prefix()) */
-
-    struct lysp_stmt *next;          /**< link to the next statement */
-    struct lysp_stmt *child;         /**< list of the statement's substatements (linked list) */
-    uint16_t flags;                  /**< statement flags, can be set to LYS_YIN_ATTR */
-    enum ly_stmt kw;                 /**< numeric respresentation of the stmt value */
-};
-
-#define LYS_YIN 0x1 /**< used to specify input format of extension instance */
-
-/**
- * @brief YANG extension instance
- */
-struct lysp_ext_instance {
-    const char *name;                       /**< extension identifier, including possible prefix */
-    const char *argument;                   /**< optional value of the extension's argument */
-    LY_VALUE_FORMAT format;                 /**< prefix format of the extension name/argument (::LY_VALUE_XML is YIN format) */
-    struct lysp_node *parsed;               /**< Simply parsed (unresolved) YANG schema tree serving as a cache.
-                                                 Only ::lys_compile_extension_instance() can set this. */
-    void *prefix_data;                      /**< Format-specific data for prefix resolution
-                                                 (see ly_resolve_prefix()) */
-
-    struct lysp_stmt *child;                /**< list of the extension's substatements (linked list) */
-
-    void *parent;                           /**< pointer to the parent element holding the extension instance(s), use
-                                                 ::lysp_ext_instance#parent_stmt to access the schema element */
-    enum ly_stmt parent_stmt;               /**< value identifying placement of the extension instance */
-    LY_ARRAY_COUNT_TYPE parent_stmt_index;  /**< in case the instance is in a substatement, this identifies
-                                                 the index of that substatement in its [sized array](@ref sizedarrays) (if any) */
-    uint16_t flags;                         /**< LYS_INTERNAL value (@ref snodeflags) */
-    const struct lyplg_ext_record *record;  /**< extension defintion plugin record, if any */
-};
-
-/**
  * @brief YANG feature-stmt
  */
 struct lysp_feature {
@@ -1434,38 +1192,6 @@
 };
 
 /**
- * @brief Description of the extension instance substatements.
- *
- * Provided by extensions plugins to libyang to be able to correctly compile the content of extension instances.
- * Note that order of the defined records matters - just follow the values of ::ly_stmt and order the records from lower to higher values.
- */
-struct lysc_ext_substmt {
-    enum ly_stmt stmt;                     /**< allowed substatement */
-    enum ly_stmt_cardinality cardinality;  /**< cardinality of the substatement */
-    void *storage;                         /**< pointer to the storage of the compiled statement according to the specific
-                                                lysc_ext_substmt::stmt and lysc_ext_substmt::cardinality */
-};
-
-/**
- * @brief YANG extension instance
- */
-struct lysc_ext_instance {
-    struct lysc_ext *def;            /**< pointer to the extension definition */
-    const char *argument;            /**< optional value of the extension's argument */
-    struct lys_module *module;       /**< module where the extension instantiated is defined */
-    struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-    struct lysc_ext_substmt *substmts; /**< list of allowed substatements with the storage to access the present
-                                          substatements ([sized array](@ref sizedarrays)) */
-    void *data;                      /**< private plugins's data, not used by libyang */
-
-    void *parent;                    /**< pointer to the parent element holding the extension instance(s), use
-                                          ::lysc_ext_instance#parent_stmt to access the schema element */
-    enum ly_stmt parent_stmt;        /**< value identifying placement of the extension instance in specific statement */
-    LY_ARRAY_COUNT_TYPE parent_stmt_index; /**< in case the instance is in a substatement, this identifies
-                                          the index of that substatement in its [sized array](@ref sizedarrays) (if any) */
-};
-
-/**
  * @brief YANG when-stmt
  */
 struct lysc_when {
@@ -2239,25 +1965,6 @@
         uint32_t *idx);
 
 /**
- * @brief Get pointer to the storage of the specified substatement in the given extension instance.
- *
- * The function simplifies access into the ::lysc_ext_instance.substmts sized array.
- *
- * @param[in] ext Compiled extension instance to process.
- * @param[in] substmt Extension substatement to search for.
- * @param[out] instance_p Pointer where the storage of the @p substmt will be provided. The specific type returned depends
- * on the @p substmt and can be found in the documentation of each ::ly_stmt value. Also note that some of the substatements
- * (::lysc_node based or flags) can share the storage with other substatements. In case the pointer is NULL, still the return
- * code can be used to at least know if the substatement is allowed for the extension.
- * @param[out] cardinality_p Pointer to provide allowed cardinality of the substatements in the extension. Note that in some
- * cases, the type of the storage depends also on the cardinality of the substatement.
- * @return LY_SUCCESS if the @p substmt found.
- * @return LY_ENOT in case the @p ext is not able to store (does not allow) the specified @p substmt.
- */
-LIBYANG_API_DECL LY_ERR lysc_ext_substmt(const struct lysc_ext_instance *ext, enum ly_stmt substmt,
-        void **instance_p, enum ly_stmt_cardinality *cardinality_p);
-
-/**
  * @defgroup findxpathoptions Atomize XPath options
  * Options to modify behavior of ::lys_find_xpath() and ::lys_find_xpath_atoms() searching for schema nodes in schema tree.
  * @{
diff --git a/src/xpath.c b/src/xpath.c
index 49b87d6..1d5ad53 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -32,6 +32,7 @@
 #include "out.h"
 #include "parser_data.h"
 #include "path.h"
+#include "plugins_exts/metadata.h"
 #include "plugins_types.h"
 #include "printer_data.h"
 #include "schema_compile_node.h"
diff --git a/tests/utests/extensions/test_schema_mount.c b/tests/utests/extensions/test_schema_mount.c
index 6f33d01..b9b81c0 100644
--- a/tests/utests/extensions/test_schema_mount.c
+++ b/tests/utests/extensions/test_schema_mount.c
@@ -156,7 +156,7 @@
             "  }\n"
             "}\n";
     assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, &mod));
-    lys_print_mem(&str, mod, LYS_YIN, 0);
+    lys_print_mem(&str, mod, LYS_OUT_YIN, 0);
     assert_string_equal(str, schema);
     free(str);
 }
diff --git a/tests/utests/utests.h b/tests/utests/utests.h
index d40c5ab..b1af68d 100644
--- a/tests/utests/utests.h
+++ b/tests/utests/utests.h
@@ -2,9 +2,10 @@
  * @file   utests.h
  * @author Radek Iša <isa@cesnet.cz>
  * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief  this file contains macros for simplification test writing
  *
- * Copyright (c) 2021 CESNET, z.s.p.o.
+ * Copyright (c) 2021 - 2022 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -29,6 +30,7 @@
 #include <string.h>
 
 #include "libyang.h"
+#include "plugins_exts/metadata.h"
 #include "plugins_internal.h"
 #include "plugins_types.h"
 #include "tests_config.h"