Merge branch 'libyang2' of https://github.com/CESNET/libyang into libyang2
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 879b6e7..9b325cc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -42,6 +42,8 @@
     option(ENABLE_VALGRIND_TESTS "Build tests with valgrind" OFF)
     option(ENABLE_COVERAGE "Build code coverage report from tests" OFF)
 endif()
+
+option(ENABLE_FUZZ_TARGETS "Build target programs suitable for fuzzing with AFL" OFF)
 #option(ENABLE_CALLGRIND_TESTS "Build performance tests to be run with callgrind" OFF)
 
 #option(ENABLE_CACHE "Enable data caching for schemas and hash tables for data (time-efficient at the cost of increased space-complexity)" ON)
@@ -217,6 +219,7 @@
     src/tree_schema_compile.c
     src/tree_schema_helpers.c
     src/parser_yang.c
+    src/parser_yin.c
     src/printer.c
     src/printer_schema.c
     src/printer_yang.c
@@ -408,6 +411,10 @@
     endif(CMOCKA_FOUND)
 endif(ENABLE_BUILD_TESTS)
 
+if(ENABLE_FUZZ_TARGETS)
+	add_subdirectory(tests/fuzz)
+endif(ENABLE_FUZZ_TARGETS)
+
 #if(GEN_LANGUAGE_BINDINGS AND GEN_CPP_BINDINGS)
 #    add_subdirectory(swig)
 #endif()
diff --git a/README.md b/README.md
index a185d0b..f5c641b 100644
--- a/README.md
+++ b/README.md
@@ -252,5 +252,9 @@
 * JavaScript
  * cmake option: `JAVASCRIPT_BINDING`
  * [README](./swig/javascript/README.md)
+ 
+## Fuzzing
 
+A YANG fuzzing target and fuzzing instructions are available in the `tests/fuzz` directory.
 
+An asciinema example describing the process of fuzzing libyang2 with the yangfuzz fuzz harness is available at https://asciinema.org/a/260417.
diff --git a/src/common.c b/src/common.c
index 6f8cfe9..a59d5af 100644
--- a/src/common.c
+++ b/src/common.c
@@ -54,7 +54,7 @@
     [YANG_FEATURE] = "feature",
     [YANG_FRACTION_DIGITS] = "fraction-digits",
     [YANG_GROUPING] = "grouping",
-    [YANG_IDENTITY] = "identitiy",
+    [YANG_IDENTITY] = "identity",
     [YANG_IF_FEATURE] = "if-feature",
     [YANG_IMPORT] = "import",
     [YANG_INCLUDE] = "include",
@@ -101,6 +101,8 @@
     [YANG_SEMICOLON] = ";",
     [YANG_LEFT_BRACE] = "{",
     [YANG_RIGHT_BRACE] = "}",
+    [YIN_TEXT] = "text",
+    [YIN_VALUE] = "value",
 };
 
 const char *const lyext_substmt_list[] = {
diff --git a/src/common.h b/src/common.h
index 021eca8..10637ee 100644
--- a/src/common.h
+++ b/src/common.h
@@ -178,6 +178,12 @@
 #define LY_VCODE_EOF         LYVE_SYNTAX, "Unexpected end-of-input."
 #define LY_VCODE_NTERM       LYVE_SYNTAX, "%s not terminated."
 #define LY_VCODE_NSUPP       LYVE_SYNTAX, "%s not supported."
+#define LY_VCODE_MOD_SUBOMD  LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\"."
+#define LY_VCODE_TRAILING_MOD LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after module, expected end-of-input."
+#define LY_VCODE_TRAILING_SUBMOD LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after submodule, expected end-of-input."
+
+#define LY_VCODE_INVAL_MINMAX LYVE_SEMANTICS, "Invalid combination of min-elements and max-elements: min value %u is bigger than the max value %u."
+
 #define LY_VCODE_INSTMT      LYVE_SYNTAX_YANG, "Invalid keyword \"%s\"."
 #define LY_VCODE_INCHILDSTMT LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s\"."
 #define LY_VCODE_INCHILDSTMT2 LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s\" - the statement is allowed only in YANG 1.1 modules."
@@ -191,8 +197,24 @@
 #define LY_VCODE_OOB         LYVE_SYNTAX_YANG, "Value \"%.*s\" is out of \"%s\" bounds."
 #define LY_VCODE_INDEV       LYVE_SYNTAX_YANG, "Deviate \"%s\" does not support keyword \"%s\"."
 #define LY_VCODE_INREGEXP    LYVE_SYNTAX_YANG, "Regular expression \"%s\" is not valid (\"%s\": %s)."
+
+#define LY_VCODE_INSUBELEM2   LYVE_SYNTAX_YIN, "Invalid sub-elemnt \"%s\" of \"%s\" element - this sub-element is allowed only in modules with version 1.1 or newer."
+#define LY_VCODE_INVAL_YIN   LYVE_SYNTAX_YIN, "Invalid value \"%s\" of \"%s\" attribute in \"%s\" element."
+#define LY_VCODE_UNEXP_SUBELEM LYVE_SYNTAX_YIN, "Unexpected sub-element \"%.*s\" of \"%s\" element."
+#define LY_VCODE_INDEV_YIN   LYVE_SYNTAX_YIN, "Deviate of this type doesn't allow \"%s\" as it's sub-element."
+#define LY_VCODE_INORDER_YIN LYVE_SYNTAX_YIN, "Invalid order of %s\'s sub-elements \"%s\" can't appear after \"%s\"."
+#define LY_VCODE_OOB_YIN      LYVE_SYNTAX_YIN, "Value \"%s\" of \"%s\" attribute in \"%s\" element is out of bounds."
+#define LY_VCODE_INCHILDSTMSCOMB_YIN LYVE_SYNTAX_YIN, "Invalid combination of sub-elemnts \"%s\" and \"%s\" in \"%s\" element."
+#define LY_VCODE_DUP_ATTR LYVE_SYNTAX_YIN, "Duplicit definition of \"%s\" attribute in \"%s\" element."
+#define LY_VCODE_UNEXP_ATTR LYVE_SYNTAX_YIN, "Unexpected attribute \"%.*s\" of \"%s\" element."
+#define LY_VCODE_MAND_SUBELEM LYVE_SYNTAX_YIN, "Missing mandatory sub-element \"%s\" of \"%s\" element."
+#define LY_VCODE_FIRT_SUBELEM LYVE_SYNTAX_YIN, "Sub-element \"%s\" of \"%s\" element must be defined as it's first sub-element."
+#define LY_VCODE_NAME_COL LYVE_SYNTAX_YIN, "Name collision between module and submodule of name \"%s\"."
+#define LY_VCODE_SUBELEM_REDEF LYVE_SYNTAX_YIN, "Redefinition of \"%s\" sub-element in \"%s\" element."
+
 #define LY_VCODE_XP_EOE      LYVE_XPATH, "Unterminated string delimited with %c (%.15s)."
 #define LY_VCODE_XP_INEXPR   LYVE_XPATH, "Invalid character number %u of expression \'%s\'."
+
 #define LY_VCODE_DEV_NODETYPE LYVE_REFERENCE, "Invalid deviation of %s node - it is not possible to %s \"%s\" property."
 #define LY_VCODE_DEV_NOT_PRESENT LYVE_REFERENCE, "Invalid deviation %s \"%s\" property \"%s\" which is not present."
 
@@ -320,7 +342,10 @@
     YANG_SEMICOLON,
     YANG_LEFT_BRACE,
     YANG_RIGHT_BRACE,
-    YANG_CUSTOM
+    YANG_CUSTOM,
+
+    YIN_TEXT,
+    YIN_VALUE
 };
 
 /* list of the YANG statements strings */
@@ -599,4 +624,36 @@
  */
 #define LY_ARRAY_FREE(ARRAY) \
         if (ARRAY){free((uint32_t*)(ARRAY) - 1);}
+
+/**
+ * @brief insert item into linked list.
+ *
+ * @param[in,out] LIST Linked list to add to.
+ * @param[in] NEW_ITEM New item, that will be appended to the list, must be already allocated.
+ * @param[in] LINKER name of structuin member that is used to connect items together.
+ */
+#define LY_LIST_INSERT(LIST, NEW_ITEM, LINKER)\
+    if (!(*LIST)) { \
+        *LIST = (__typeof__(*(LIST)))NEW_ITEM; \
+    } else { \
+        do { \
+            __typeof__(*(LIST)) iterator; \
+            for (iterator = *(LIST); iterator->LINKER; iterator = iterator->LINKER); \
+            iterator->LINKER = (__typeof__(*(LIST)))NEW_ITEM; \
+        } while (0); \
+    }
+
+/**
+ * @brief allocate and insert new item inro linked list.
+ *
+ * @param[in] CTX used for loggin.
+ * @param[in,out] LIST Linker list to add to.
+ * @param[out] NEW_ITEM New item that was appended to the list.
+ * @param[in] LINKER name of structuin member that is used to connect items together.
+ */
+#define LY_LIST_NEW_RET(CTX, LIST, NEW_ITEM, LINKER) \
+    NEW_ITEM = calloc(1, sizeof *NEW_ITEM); \
+    LY_CHECK_ERR_RET(!(NEW_ITEM), LOGMEM(CTX), LY_EMEM); \
+    LY_LIST_INSERT(LIST, NEW_ITEM, LINKER)
+
 #endif /* LY_COMMON_H_ */
diff --git a/src/hash_table.c b/src/hash_table.c
index f26d04c..2d9af2a 100644
--- a/src/hash_table.c
+++ b/src/hash_table.c
@@ -206,6 +206,9 @@
     } else {
         /* lyht_insert returned error */
         LOGINT(ctx);
+        if (zerocopy) {
+            free(value);
+        }
         return NULL;
     }
 
diff --git a/src/log.h b/src/log.h
index 83fc240..c7ee0a3 100644
--- a/src/log.h
+++ b/src/log.h
@@ -167,6 +167,7 @@
     LYVE_SUCCESS = 0,  /**< no error */
     LYVE_SYNTAX,       /**< generic syntax error */
     LYVE_SYNTAX_YANG,  /**< YANG-related syntax error */
+    LYVE_SYNTAX_YIN,   /**< YIN-related syntax error */
     LYVE_REFERENCE,    /**< invalid referencing or using an item */
     LYVE_XPATH,        /**< invalid XPath expression */
     LYVE_SEMANTICS,    /**< generic semantic error */
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 34db6e5..3949b4a 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -31,38 +31,6 @@
 #include "tree_schema.h"
 #include "tree_schema_internal.h"
 
-/* Macro to check YANG's yang-char grammar rule */
-#define is_yangutf8char(c) ((c >= 0x20 && c <= 0xd7ff) || c == 0x09 || c == 0x0a || c == 0x0d || \
-        (c >= 0xe000 && c <= 0xfdcf) || (c >= 0xfdf0 && c <= 0xfffd) || \
-        (c >= 0x10000 && c <= 0x1fffd) || (c >= 0x20000 && c <= 0x2fffd) || \
-        (c >= 0x30000 && c <= 0x3fffd) || (c >= 0x40000 && c <= 0x2fffd) || \
-        (c >= 0x50000 && c <= 0x5fffd) || (c >= 0x60000 && c <= 0x6fffd) || \
-        (c >= 0x70000 && c <= 0x7fffd) || (c >= 0x80000 && c <= 0x8fffd) || \
-        (c >= 0x90000 && c <= 0x9fffd) || (c >= 0xa0000 && c <= 0xafffd) || \
-        (c >= 0xb0000 && c <= 0xbfffd) || (c >= 0xc0000 && c <= 0xcfffd) || \
-        (c >= 0xd0000 && c <= 0xdfffd) || (c >= 0xe0000 && c <= 0xefffd) || \
-        (c >= 0xf0000 && c <= 0xffffd) || (c >= 0x100000 && c <= 0x10fffd))
-
-/**
- * @brief Try to find object with MEMBER string matching the IDENT in the given ARRAY.
- * Macro logs an error message and returns LY_EVALID in case of existence of a matching object.
- *
- * @param[in] CTX yang parser context for logging.
- * @param[in] ARRAY [sized array](@ref sizedarrays) of a generic objects with member named MEMBER to search.
- * @param[in] MEMBER Name of the member of the objects in the ARRAY to compare.
- * @param[in] STMT Name of the compared YANG statements for logging.
- * @param[in] IDENT String trying to find in the ARRAY's objects inside the MEMBER member.
- */
-#define CHECK_UNIQUENESS(CTX, ARRAY, MEMBER, STMT, IDENT) \
-    if (ARRAY) { \
-        for (unsigned int u = 0; u < LY_ARRAY_SIZE(ARRAY) - 1; ++u) { \
-            if (!strcmp((ARRAY)[u].MEMBER, IDENT)) { \
-                LOGVAL_YANG(CTX, LY_VCODE_DUPIDENT, IDENT, STMT); \
-                return LY_EVALID; \
-            } \
-        } \
-    }
-
 /**
  * @brief Insert WORD into the libyang context's dictionary and store as TARGET.
  * @param[in] CTX yang parser context to access libyang context.
@@ -102,7 +70,7 @@
         return LY_SUCCESS; \
     } \
     if (KW != YANG_LEFT_BRACE) { \
-        LOGVAL_YANG(CTX, LYVE_SYNTAX_YANG, "Invalid keyword \"%s\", expected \";\" or \"{\".", ly_stmt2str(KW)); \
+        LOGVAL_PARSER(CTX, LYVE_SYNTAX_YANG, "Invalid keyword \"%s\", expected \";\" or \"{\".", ly_stmt2str(KW)); \
         return LY_EVALID; \
     } \
     for (ERR = get_keyword(CTX, DATA, &KW, &WORD, &WORD_LEN); \
@@ -117,12 +85,7 @@
  * @param[in] PARENT parent statement where the KW is present - for logging.
  */
 #define YANG_CHECK_STMTVER2_RET(CTX, KW, PARENT) \
-    if ((CTX)->mod_version < 2) {LOGVAL_YANG((CTX), LY_VCODE_INCHILDSTMT2, KW, PARENT); return LY_EVALID;}
-
-#define YANG_CHECK_NONEMPTY(CTX, OBJECT, VALUE_LEN, STMT) \
-    if (!VALUE_LEN) { \
-        LOGWRN((CTX)->ctx, "Empty argument of %s statement does not make sense.", STMT); \
-    }
+    if ((CTX)->mod_version < 2) {LOGVAL_PARSER((CTX), LY_VCODE_INCHILDSTMT2, KW, PARENT); return LY_EVALID;}
 
 LY_ERR parse_container(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
 LY_ERR parse_uses(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
@@ -131,9 +94,6 @@
 LY_ERR parse_list(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
 LY_ERR parse_grouping(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_grp **groupings);
 
-static LY_ERR parse_finalize_reallocated(struct lys_parser_ctx *ctx, struct lysp_grp *groupings, struct lysp_augment *augments,
-                                         struct lysp_action *actions, struct lysp_notif *notifs);
-
 /**
  * @brief Add another character to dynamic buffer, a low-level function.
  *
@@ -169,62 +129,6 @@
 }
 
 /**
- * @brief Check that \p c is valid UTF8 code point for YANG string.
- *
- * @param[in] ctx yang parser context for logging.
- * @param[in] c UTF8 code point of a character to check.
- * @return LY_ERR values.
- */
-static LY_ERR
-check_stringchar(struct lys_parser_ctx *ctx, unsigned int c)
-{
-    if (!is_yangutf8char(c)) {
-        LOGVAL_YANG(ctx, LY_VCODE_INCHAR, c);
-        return LY_EVALID;
-    }
-    return LY_SUCCESS;
-}
-
-/**
- * @brief Check that \p c is valid UTF8 code point for YANG identifier.
- *
- * @param[in] ctx yang parser context for logging.
- * @param[in] c UTF8 code point of a character to check.
- * @param[in] first Flag to check the first character of an identifier, which is more restricted.
- * @param[in,out] prefix Storage for internally used flag in case of possible prefixed identifiers:
- * 0 - colon not yet found (no prefix)
- * 1 - \p c is the colon character
- * 2 - prefix already processed, now processing the identifier
- *
- * If the identifier cannot be prefixed, NULL is expected.
- * @return LY_ERR values.
- */
-LY_ERR
-check_identifierchar(struct lys_parser_ctx *ctx, unsigned int c, int first, int *prefix)
-{
-    if (first || (prefix && (*prefix) == 1)) {
-        if (!is_yangidentstartchar(c)) {
-            LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Invalid identifier first character '%c'.", c);
-            return LY_EVALID;
-        }
-        if (prefix) {
-            if (first) {
-                (*prefix) = 0;
-            } else {
-                (*prefix) = 2;
-            }
-        }
-    } else if (c == ':' && prefix && (*prefix) == 0) {
-        (*prefix) = 1;
-    } else if (!is_yangidentchar(c)) {
-        LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Invalid identifier character '%c'.", c);
-        return LY_EVALID;
-    }
-
-    return LY_SUCCESS;
-}
-
-/**
  * @brief Store a single UTF8 character. It depends whether in a dynamically-allocated buffer or just as a pointer to the data.
  *
  * @param[in] ctx yang parser context for logging.
@@ -237,14 +141,17 @@
  * @param[in,out] word_b Word buffer. Is kept NULL as long as it is not requested (word is a substring of the data).
  * @param[in,out] buf_len Current length of \p word_b.
  * @param[in] need_buf Flag if the dynamically allocated buffer is required.
+ * @param[in,out] prefix Storage for internally used flag in case of possible prefixed identifiers:
+ * 0 - colon not yet found (no prefix)
+ * 1 - \p c is the colon character
+ * 2 - prefix already processed, now processing the identifier
  *
  * @return LY_ERR values.
  */
 LY_ERR
-buf_store_char(struct lys_parser_ctx *ctx, const char **input, enum yang_arg arg,
-               char **word_p, size_t *word_len, char **word_b, size_t *buf_len, int need_buf)
+buf_store_char(struct lys_parser_ctx *ctx, const char **input, enum yang_arg arg, char **word_p,
+               size_t *word_len, char **word_b, size_t *buf_len, int need_buf, int *prefix)
 {
-    int prefix = 0;
     unsigned int c;
     size_t len;
 
@@ -253,7 +160,7 @@
 
     /* get UTF8 code point (and number of bytes coding the character) */
     LY_CHECK_ERR_RET(ly_getutf8(input, &c, &len),
-                     LOGVAL_YANG(ctx, LY_VCODE_INCHAR, (*input)[-len]), LY_EVALID);
+                     LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, (*input)[-len]), LY_EVALID);
     (*input) -= len;
     if (c == '\n') {
         ctx->indent = 0;
@@ -265,14 +172,14 @@
     /* check character validity */
     switch (arg) {
     case Y_IDENTIF_ARG:
-        LY_CHECK_RET(check_identifierchar(ctx, c, !(*word_len), NULL));
+        LY_CHECK_RET(lysp_check_identifierchar(ctx, c, !(*word_len), NULL));
         break;
     case Y_PREF_IDENTIF_ARG:
-        LY_CHECK_RET(check_identifierchar(ctx, c, !(*word_len), &prefix));
+        LY_CHECK_RET(lysp_check_identifierchar(ctx, c, !(*word_len), prefix));
         break;
     case Y_STR_ARG:
     case Y_MAYBE_STR_ARG:
-        LY_CHECK_RET(check_stringchar(ctx, c));
+        LY_CHECK_RET(lysp_check_stringchar(ctx, c));
         break;
     }
 
@@ -370,7 +277,7 @@
     }
 
     if (!**data && (comment > 1)) {
-        LOGVAL_YANG(ctx, LYVE_SYNTAX, "Unexpected end-of-input, non-terminated comment.");
+        LOGVAL_PARSER(ctx, LYVE_SYNTAX, "Unexpected end-of-input, non-terminated comment.");
         return LY_EVALID;
     }
 
@@ -402,6 +309,7 @@
      *         5 - string continues after +, skipping whitespaces */
     unsigned int string, block_indent = 0, current_indent = 0, need_buf = 0;
     const char *c;
+    int prefix = 0;
 
     if (**data == '\"') {
         string = 2;
@@ -423,7 +331,7 @@
                 break;
             default:
                 /* check and store character */
-                LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf));
+                LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
                 break;
             }
             break;
@@ -445,7 +353,7 @@
                     MOVE_INPUT(ctx, data, 1);
                 } else {
                     /* check and store character */
-                    LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf));
+                    LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
                 }
                 break;
             case '\t':
@@ -456,12 +364,12 @@
                     for (; current_indent > block_indent; --current_indent, --ctx->indent) {
                         /* store leftover spaces from the tab */
                         c = " ";
-                        LY_CHECK_RET(buf_store_char(ctx, &c, arg, word_p, word_len, word_b, buf_len, need_buf));
+                        LY_CHECK_RET(buf_store_char(ctx, &c, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
                     }
                     ++(*data);
                 } else {
                     /* check and store character */
-                    LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf));
+                    LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
                     /* additional characters for indentation - only 1 was count in buf_store_char */
                     ctx->indent += 7;
                 }
@@ -481,7 +389,7 @@
                 }
 
                 /* check and store character */
-                LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf));
+                LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
 
                 /* maintain line number */
                 ++ctx->line;
@@ -494,7 +402,7 @@
                 current_indent = block_indent;
 
                 /* check and store character */
-                LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf));
+                LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
                 break;
             }
             break;
@@ -514,12 +422,12 @@
                 c = *data;
                 break;
             default:
-                LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Double-quoted string unknown special character '\\%c'.", **data);
+                LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Double-quoted string unknown special character '\\%c'.", **data);
                 return LY_EVALID;
             }
 
             /* check and store character */
-            LY_CHECK_RET(buf_store_char(ctx, &c, arg, word_p, word_len, word_b, buf_len, need_buf));
+            LY_CHECK_RET(buf_store_char(ctx, &c, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
 
             string = 2;
             ++(*data);
@@ -561,7 +469,7 @@
                 break;
             default:
                 /* it must be quoted again */
-                LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Both string parts divided by '+' must be quoted.");
+                LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Both string parts divided by '+' must be quoted.");
                 return LY_EVALID;
             }
             MOVE_INPUT(ctx, data, 1);
@@ -574,7 +482,7 @@
 string_end:
     if (arg <= Y_PREF_IDENTIF_ARG && !(*word_len)) {
         /* empty identifier */
-        LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Statement argument is required.");
+        LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Statement argument is required.");
         return LY_EVALID;
     }
     return LY_SUCCESS;
@@ -599,7 +507,7 @@
              uint16_t *flags, char **word_p, char **word_b, size_t *word_len)
 {
     size_t buf_len = 0;
-
+    int prefix = 0;
     /* word buffer - dynamically allocated */
     *word_b = NULL;
 
@@ -613,7 +521,7 @@
         case '\"':
             if (*word_len) {
                 /* invalid - quotes cannot be in unquoted string and only optsep, ; or { can follow it */
-                LOGVAL_YANG(ctx, LY_VCODE_INSTREXP, 1, *data,
+                LOGVAL_PARSER(ctx, LY_VCODE_INSTREXP, 1, *data,
                             "unquoted string character, optsep, semicolon or opening brace");
                 return LY_EVALID;
             }
@@ -633,7 +541,7 @@
                 LY_CHECK_RET(skip_comment(ctx, data, 2));
             } else {
                 /* not a comment after all */
-                LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, &buf_len, 0));
+                LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, &buf_len, 0, &prefix));
             }
             break;
         case ' ':
@@ -673,21 +581,21 @@
                 goto str_end;
             }
 
-            LOGVAL_YANG(ctx, LY_VCODE_INSTREXP, 1, *data, "an argument");
+            LOGVAL_PARSER(ctx, LY_VCODE_INSTREXP, 1, *data, "an argument");
             return LY_EVALID;
         case '}':
             /* invalid - braces cannot be in unquoted string (opening braces terminates the string and can follow it) */
-            LOGVAL_YANG(ctx, LY_VCODE_INSTREXP, 1, *data,
+            LOGVAL_PARSER(ctx, LY_VCODE_INSTREXP, 1, *data,
                         "unquoted string character, optsep, semicolon or opening brace");
             return LY_EVALID;
         default:
-            LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, &buf_len, 0));
+            LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, &buf_len, 0, &prefix));
             break;
         }
     }
 
     /* unexpected end of loop */
-    LOGVAL_YANG(ctx, LY_VCODE_EOF);
+    LOGVAL_PARSER(ctx, LY_VCODE_EOF);
     return LY_EVALID;
 
 str_end:
@@ -740,7 +648,7 @@
                 LY_CHECK_RET(skip_comment(ctx, data, 2));
             } else {
                 /* error - not a comment after all, keyword cannot start with slash */
-                LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Invalid identifier first character '/'.");
+                LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Invalid identifier first character '/'.");
                 return LY_EVALID;
             }
             continue;
@@ -765,197 +673,14 @@
         ++(*data);
     }
 
-#define IF_KW(STR, LEN, STMT) if (!strncmp(*(data), STR, LEN)) {MOVE_INPUT(ctx, data, LEN);*kw=STMT;}
-#define IF_KW_PREFIX(STR, LEN) if (!strncmp(*(data), STR, LEN)) {MOVE_INPUT(ctx, data, LEN);
-#define IF_KW_PREFIX_END }
-
 keyword_start:
     word_start = *data;
-    *kw = YANG_NONE;
+    *kw = lysp_match_kw(ctx, data);
 
-    /* read the keyword itself */
-    switch (**data) {
-    case 'a':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW("rgument", 7, YANG_ARGUMENT)
-        else IF_KW("ugment", 6, YANG_AUGMENT)
-        else IF_KW("ction", 5, YANG_ACTION)
-        else IF_KW_PREFIX("ny", 2)
-            IF_KW("data", 4, YANG_ANYDATA)
-            else IF_KW("xml", 3, YANG_ANYXML)
-        IF_KW_PREFIX_END
-        break;
-    case 'b':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW("ase", 3, YANG_BASE)
-        else IF_KW("elongs-to", 9, YANG_BELONGS_TO)
-        else IF_KW("it", 2, YANG_BIT)
-        break;
-    case 'c':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW("ase", 3, YANG_CASE)
-        else IF_KW("hoice", 5, YANG_CHOICE)
-        else IF_KW_PREFIX("on", 2)
-            IF_KW("fig", 3, YANG_CONFIG)
-            else IF_KW_PREFIX("ta", 2)
-                IF_KW("ct", 2, YANG_CONTACT)
-                else IF_KW("iner", 4, YANG_CONTAINER)
-            IF_KW_PREFIX_END
-        IF_KW_PREFIX_END
-        break;
-    case 'd':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW_PREFIX("e", 1)
-            IF_KW("fault", 5, YANG_DEFAULT)
-            else IF_KW("scription", 9, YANG_DESCRIPTION)
-            else IF_KW_PREFIX("viat", 4)
-                IF_KW("e", 1, YANG_DEVIATE)
-                else IF_KW("ion", 3, YANG_DEVIATION)
-            IF_KW_PREFIX_END
-        IF_KW_PREFIX_END
-        break;
-    case 'e':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW("num", 3, YANG_ENUM)
-        else IF_KW_PREFIX("rror-", 5)
-            IF_KW("app-tag", 7, YANG_ERROR_APP_TAG)
-            else IF_KW("message", 7, YANG_ERROR_MESSAGE)
-        IF_KW_PREFIX_END
-        else IF_KW("xtension", 8, YANG_EXTENSION)
-        break;
-    case 'f':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW("eature", 6, YANG_FEATURE)
-        else IF_KW("raction-digits", 14, YANG_FRACTION_DIGITS)
-        break;
-    case 'g':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW("rouping", 7, YANG_GROUPING)
-        break;
-    case 'i':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW("dentity", 7, YANG_IDENTITY)
-        else IF_KW("f-feature", 9, YANG_IF_FEATURE)
-        else IF_KW("mport", 5, YANG_IMPORT)
-        else IF_KW_PREFIX("n", 1)
-            IF_KW("clude", 5, YANG_INCLUDE)
-            else IF_KW("put", 3, YANG_INPUT)
-        IF_KW_PREFIX_END
-        break;
-    case 'k':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW("ey", 2, YANG_KEY)
-        break;
-    case 'l':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW_PREFIX("e", 1)
-            IF_KW("af-list", 7, YANG_LEAF_LIST)
-            else IF_KW("af", 2, YANG_LEAF)
-            else IF_KW("ngth", 4, YANG_LENGTH)
-        IF_KW_PREFIX_END
-        else IF_KW("ist", 3, YANG_LIST)
-        break;
-    case 'm':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW_PREFIX("a", 1)
-            IF_KW("ndatory", 7, YANG_MANDATORY)
-            else IF_KW("x-elements", 10, YANG_MAX_ELEMENTS)
-        IF_KW_PREFIX_END
-        else IF_KW("in-elements", 11, YANG_MIN_ELEMENTS)
-        else IF_KW("ust", 3, YANG_MUST)
-        else IF_KW_PREFIX("od", 2)
-            IF_KW("ule", 3, YANG_MODULE)
-            else IF_KW("ifier", 5, YANG_MODIFIER)
-        IF_KW_PREFIX_END
-        break;
-    case 'n':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW("amespace", 8, YANG_NAMESPACE)
-        else IF_KW("otification", 11, YANG_NOTIFICATION)
-        break;
-    case 'o':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW_PREFIX("r", 1)
-            IF_KW("dered-by", 8, YANG_ORDERED_BY)
-            else IF_KW("ganization", 10, YANG_ORGANIZATION)
-        IF_KW_PREFIX_END
-        else IF_KW("utput", 5, YANG_OUTPUT)
-        break;
-    case 'p':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW("ath", 3, YANG_PATH)
-        else IF_KW("attern", 6, YANG_PATTERN)
-        else IF_KW("osition", 7, YANG_POSITION)
-        else IF_KW_PREFIX("re", 2)
-            IF_KW("fix", 3, YANG_PREFIX)
-            else IF_KW("sence", 5, YANG_PRESENCE)
-        IF_KW_PREFIX_END
-        break;
-    case 'r':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW("ange", 4, YANG_RANGE)
-        else IF_KW_PREFIX("e", 1)
-            IF_KW_PREFIX("f", 1)
-                IF_KW("erence", 6, YANG_REFERENCE)
-                else IF_KW("ine", 3, YANG_REFINE)
-            IF_KW_PREFIX_END
-            else IF_KW("quire-instance", 14, YANG_REQUIRE_INSTANCE)
-            else IF_KW("vision-date", 11, YANG_REVISION_DATE)
-            else IF_KW("vision", 6, YANG_REVISION)
-        IF_KW_PREFIX_END
-        else IF_KW("pc", 2, YANG_RPC)
-        break;
-    case 's':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW("tatus", 5, YANG_STATUS)
-        else IF_KW("ubmodule", 8, YANG_SUBMODULE)
-        break;
-    case 't':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW("ypedef", 6, YANG_TYPEDEF)
-        else IF_KW("ype", 3, YANG_TYPE)
-        break;
-    case 'u':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW_PREFIX("ni", 2)
-            IF_KW("que", 3, YANG_UNIQUE)
-            else IF_KW("ts", 2, YANG_UNITS)
-        IF_KW_PREFIX_END
-        else IF_KW("ses", 3, YANG_USES)
-        break;
-    case 'v':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW("alue", 4, YANG_VALUE)
-        break;
-    case 'w':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW("hen", 3, YANG_WHEN)
-        break;
-    case 'y':
-        MOVE_INPUT(ctx, data, 1);
-        IF_KW("ang-version", 11, YANG_YANG_VERSION)
-        else IF_KW("in-element", 10, YANG_YIN_ELEMENT)
-        break;
-    case ';':
-        MOVE_INPUT(ctx, data, 1);
-        *kw = YANG_SEMICOLON;
+    if (*kw == YANG_SEMICOLON || *kw == YANG_LEFT_BRACE || *kw == YANG_RIGHT_BRACE) {
         goto success;
-    case '{':
-        MOVE_INPUT(ctx, data, 1);
-        *kw = YANG_LEFT_BRACE;
-        goto success;
-    case '}':
-        MOVE_INPUT(ctx, data, 1);
-        *kw = YANG_RIGHT_BRACE;
-        goto success;
-    default:
-        break;
     }
 
-#undef IF_KW
-#undef IF_KW_PREFIX
-#undef IF_KW_PREFIX_END
-
     if (*kw != YANG_NONE) {
         /* make sure we have the whole keyword */
         switch (**data) {
@@ -979,7 +704,7 @@
             /* fallthrough */
         default:
             MOVE_INPUT(ctx, data, 1);
-            LOGVAL_YANG(ctx, LY_VCODE_INSTREXP, (int)(*data - word_start), word_start,
+            LOGVAL_PARSER(ctx, LY_VCODE_INSTREXP, (int)(*data - word_start), word_start,
                         "a keyword followed by a separator");
             return LY_EVALID;
         }
@@ -989,19 +714,19 @@
 extension:
         while (**data && (**data != ' ') && (**data != '\t') && (**data != '\n') && (**data != '{') && (**data != ';')) {
             LY_CHECK_ERR_RET(ly_getutf8(data, &c, &len),
-                             LOGVAL_YANG(ctx, LY_VCODE_INCHAR, (*data)[-len]), LY_EVALID);
+                             LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, (*data)[-len]), LY_EVALID);
             ++ctx->indent;
             /* check character validity */
-            LY_CHECK_RET(check_identifierchar(ctx, c, *data - len == word_start ? 1 : 0, &prefix));
+            LY_CHECK_RET(lysp_check_identifierchar(ctx, c, *data - len == word_start ? 1 : 0, &prefix));
         }
         if (!**data) {
-            LOGVAL_YANG(ctx, LY_VCODE_EOF);
+            LOGVAL_PARSER(ctx, LY_VCODE_EOF);
             return LY_EVALID;
         }
 
         /* prefix is mandatory for extension instances */
         if (prefix != 2) {
-            LOGVAL_YANG(ctx, LY_VCODE_INSTREXP, (int)(*data - word_start), word_start, "a keyword");
+            LOGVAL_PARSER(ctx, LY_VCODE_INSTREXP, (int)(*data - word_start), word_start, "a keyword");
             return LY_EVALID;
         }
 
@@ -1133,7 +858,7 @@
     enum yang_keyword kw;
 
     if (*value) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, lyext_substmt2str(substmt));
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, lyext_substmt2str(substmt));
         return LY_EVALID;
     }
 
@@ -1149,7 +874,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, substmt, substmt_index, exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
             return LY_EVALID;
         }
     }
@@ -1175,7 +900,7 @@
     enum yang_keyword kw;
 
     if (*version) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "yang-version");
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "yang-version");
         return LY_EVALID;
     }
 
@@ -1187,7 +912,7 @@
     } else if ((word_len == 3) && !strncmp(word, "1.1", word_len)) {
         *version = LYS_VERSION_1_1;
     } else {
-        LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "yang-version");
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "yang-version");
         free(buf);
         return LY_EVALID;
     }
@@ -1199,7 +924,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_VERSION, 0, exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yang-version");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yang-version");
             return LY_EVALID;
         }
     }
@@ -1226,7 +951,7 @@
     enum yang_keyword kw;
 
     if (*belongsto) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "belongs-to");
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "belongs-to");
         return LY_EVALID;
     }
 
@@ -1244,7 +969,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_BELONGSTO, 0, exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "belongs-to");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "belongs-to");
             return LY_EVALID;
         }
     }
@@ -1252,7 +977,7 @@
 checks:
     /* mandatory substatements */
     if (!*prefix) {
-        LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "prefix", "belongs-to");
+        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "prefix", "belongs-to");
         return LY_EVALID;
     }
     return ret;
@@ -1277,7 +1002,7 @@
     enum yang_keyword kw;
 
     if (rev[0]) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "revision-date");
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "revision-date");
         return LY_EVALID;
     }
 
@@ -1300,7 +1025,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_REVISIONDATE, 0, exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision-date");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision-date");
             return LY_EVALID;
         }
     }
@@ -1336,7 +1061,7 @@
     /* submodules share the namespace with the module names, so there must not be
      * a module of the same name in the context, no need for revision matching */
     if (!strcmp(module_name, inc->name) || ly_ctx_get_module_latest(ctx->ctx, inc->name)) {
-        LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Name collision between module and submodule of name \"%s\".", inc->name);
+        LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Name collision between module and submodule of name \"%s\".", inc->name);
         return LY_EVALID;
     }
 
@@ -1357,7 +1082,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &inc->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "include");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "include");
             return LY_EVALID;
         }
     }
@@ -1410,14 +1135,14 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &imp->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "import");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "import");
             return LY_EVALID;
         }
     }
     LY_CHECK_RET(ret);
 checks:
     /* mandatory substatements */
-    LY_CHECK_ERR_RET(!imp->prefix, LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "prefix", "import"), LY_EVALID);
+    LY_CHECK_ERR_RET(!imp->prefix, LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "prefix", "import"), LY_EVALID);
 
     return ret;
 }
@@ -1447,6 +1172,7 @@
 
     /* check value */
     if (lysp_check_date(ctx, word, word_len, "revision")) {
+        free(buf);
         return LY_EVALID;
     }
 
@@ -1465,7 +1191,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &rev->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision");
             return LY_EVALID;
         }
     }
@@ -1507,7 +1233,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, substmt, LY_ARRAY_SIZE(*texts) - 1, exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
             return LY_EVALID;
         }
     }
@@ -1533,7 +1259,7 @@
     enum yang_keyword kw;
 
     if (*flags & LYS_CONFIG_MASK) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "config");
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "config");
         return LY_EVALID;
     }
 
@@ -1545,7 +1271,7 @@
     } else if ((word_len == 5) && !strncmp(word, "false", word_len)) {
         *flags |= LYS_CONFIG_R;
     } else {
-        LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "config");
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "config");
         free(buf);
         return LY_EVALID;
     }
@@ -1557,7 +1283,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_CONFIG, 0, exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "config");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "config");
             return LY_EVALID;
         }
     }
@@ -1583,7 +1309,7 @@
     enum yang_keyword kw;
 
     if (*flags & LYS_MAND_MASK) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "mandatory");
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "mandatory");
         return LY_EVALID;
     }
 
@@ -1595,7 +1321,7 @@
     } else if ((word_len == 5) && !strncmp(word, "false", word_len)) {
         *flags |= LYS_MAND_FALSE;
     } else {
-        LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "mandatory");
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "mandatory");
         free(buf);
         return LY_EVALID;
     }
@@ -1607,7 +1333,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MANDATORY, 0, exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "mandatory");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "mandatory");
             return LY_EVALID;
         }
     }
@@ -1635,7 +1361,7 @@
     /* get value */
     LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
 
-    YANG_CHECK_NONEMPTY(ctx, NULL, word_len, ly_stmt2str(restr_kw));
+    YANG_CHECK_NONEMPTY(ctx, word_len, ly_stmt2str(restr_kw));
     INSERT_WORD(ctx, buf, restr->arg, word, word_len);
     YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
         switch (kw) {
@@ -1655,7 +1381,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &restr->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(restr_kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(restr_kw));
             return LY_EVALID;
         }
     }
@@ -1700,7 +1426,7 @@
     enum yang_keyword kw;
 
     if (*flags & LYS_STATUS_MASK) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "status");
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "status");
         return LY_EVALID;
     }
 
@@ -1714,7 +1440,7 @@
     } else if ((word_len == 8) && !strncmp(word, "obsolete", word_len)) {
         *flags |= LYS_STATUS_OBSLT;
     } else {
-        LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "status");
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "status");
         free(buf);
         return LY_EVALID;
     }
@@ -1726,7 +1452,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_STATUS, 0, exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "status");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "status");
             return LY_EVALID;
         }
     }
@@ -1752,7 +1478,7 @@
     struct lysp_when *when;
 
     if (*when_p) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "when");
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "when");
         return LY_EVALID;
     }
 
@@ -1761,7 +1487,7 @@
 
     /* get value */
     LY_CHECK_ERR_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len), free(when), LY_EMEM);
-    YANG_CHECK_NONEMPTY(ctx, when, word_len, "when");
+    YANG_CHECK_NONEMPTY(ctx, word_len, "when");
     INSERT_WORD(ctx, buf, when->cond, word, word_len);
 
     *when_p = when;
@@ -1778,7 +1504,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &when->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "when");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "when");
             return LY_EVALID;
         }
     }
@@ -1801,23 +1527,14 @@
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
     size_t word_len;
-    struct lysp_node *iter;
     struct lysp_node_anydata *any;
 
-    /* create structure */
-    any = calloc(1, sizeof *any);
-    LY_CHECK_ERR_RET(!any, LOGMEM(ctx->ctx), LY_EMEM);
+    /* create new structure and insert into siblings */
+    LY_LIST_NEW_RET(ctx->ctx, siblings, any, next);
+
     any->nodetype = kw == YANG_ANYDATA ? LYS_ANYDATA : LYS_ANYXML;
     any->parent = parent;
 
-    /* insert into siblings */
-    if (!*siblings) {
-        *siblings = (struct lysp_node *)any;
-    } else {
-        for (iter = *siblings; iter->next; iter = iter->next);
-        iter->next = (struct lysp_node *)any;
-    }
-
     /* get name */
     LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     INSERT_WORD(ctx, buf, any->name, word, word_len);
@@ -1853,7 +1570,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &any->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
                    (any->nodetype & LYS_ANYDATA) == LYS_ANYDATA ? ly_stmt2str(YANG_ANYDATA) : ly_stmt2str(YANG_ANYXML));
             return LY_EVALID;
         }
@@ -1873,7 +1590,7 @@
  *
  * @return LY_ERR values.
  */
-static LY_ERR
+LY_ERR
 parse_type_enum_value_pos(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword val_kw, int64_t *value, uint16_t *flags,
                           struct lysp_ext_instance **exts)
 {
@@ -1885,7 +1602,7 @@
     enum yang_keyword kw;
 
     if (*flags & LYS_SET_VALUE) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(val_kw));
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(val_kw));
         return LY_EVALID;
     }
     *flags |= LYS_SET_VALUE;
@@ -1893,8 +1610,8 @@
     /* get value */
     LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
 
-    if (!word_len || (word[0] == '+') || ((word[0] == '0') && (word_len > 1)) || ((val_kw == YANG_VALUE) && !strncmp(word, "-0", 2))) {
-        LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
+    if (!word_len || (word[0] == '+') || ((word[0] == '0') && (word_len > 1)) || ((val_kw == YANG_POSITION) && !strncmp(word, "-0", 2))) {
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
         goto error;
     }
 
@@ -1902,23 +1619,23 @@
     if (val_kw == YANG_VALUE) {
         num = strtol(word, &ptr, 10);
         if (num < INT64_C(-2147483648) || num > INT64_C(2147483647)) {
-            LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
             goto error;
         }
     } else {
         unum = strtoul(word, &ptr, 10);
         if (unum > UINT64_C(4294967295)) {
-            LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
             goto error;
         }
     }
     /* we have not parsed the whole argument */
     if ((size_t)(ptr - word) != word_len) {
-        LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
         goto error;
     }
     if (errno == ERANGE) {
-        LOGVAL_YANG(ctx, LY_VCODE_OOB, word_len, word, ly_stmt2str(val_kw));
+        LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, ly_stmt2str(val_kw));
         goto error;
     }
     if (val_kw == YANG_VALUE) {
@@ -1934,7 +1651,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, val_kw == YANG_VALUE ? LYEXT_SUBSTMT_VALUE : LYEXT_SUBSTMT_POSITION, 0, exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(val_kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(val_kw));
             return LY_EVALID;
         }
     }
@@ -1960,7 +1677,7 @@
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
-    size_t word_len, u;
+    size_t word_len;
     enum yang_keyword kw;
     struct lysp_type_enum *enm;
 
@@ -1969,29 +1686,13 @@
     /* get value */
     LY_CHECK_RET(get_argument(ctx, data, enum_kw == YANG_ENUM ? Y_STR_ARG : Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     if (enum_kw == YANG_ENUM) {
-        if (!word_len) {
-            LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Enum name must not be zero-length.");
-            free(buf);
-            return LY_EVALID;
-        } else if (isspace(word[0]) || isspace(word[word_len - 1])) {
-            LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Enum name must not have any leading or trailing whitespaces (\"%.*s\").",
-                        word_len, word);
-            free(buf);
-            return LY_EVALID;
-        } else {
-            for (u = 0; u < word_len; ++u) {
-                if (iscntrl(word[u])) {
-                    LOGWRN(ctx->ctx, "Control characters in enum name should be avoided (\"%.*s\", character number %d).",
-                           word_len, word, u + 1);
-                    break;
-                }
-            }
-        }
+        ret = lysp_check_enum_name(ctx, (const char *)word, word_len);
+        LY_CHECK_ERR_RET(ret, free(buf), ret);
     } else { /* YANG_BIT */
 
     }
     if (enum_kw == YANG_ENUM) {
-        YANG_CHECK_NONEMPTY(ctx, NULL, word_len, "enum");
+        YANG_CHECK_NONEMPTY(ctx, word_len, "enum");
     }
     INSERT_WORD(ctx, buf, enm->name, word, word_len);
     CHECK_UNIQUENESS(ctx, *enums, name, ly_stmt2str(enum_kw), enm->name);
@@ -2012,14 +1713,20 @@
             LY_CHECK_RET(parse_status(ctx, data, &enm->flags, &enm->exts));
             break;
         case YANG_VALUE:
+            LY_CHECK_ERR_RET(enum_kw == YANG_BIT, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
+                             ly_stmt2str(enum_kw)), LY_EVALID);
+            LY_CHECK_RET(parse_type_enum_value_pos(ctx, data, kw, &enm->value, &enm->flags, &enm->exts));
+            break;
         case YANG_POSITION:
+            LY_CHECK_ERR_RET(enum_kw == YANG_ENUM, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
+                             ly_stmt2str(enum_kw)), LY_EVALID);
             LY_CHECK_RET(parse_type_enum_value_pos(ctx, data, kw, &enm->value, &enm->flags, &enm->exts));
             break;
         case YANG_CUSTOM:
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &enm->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(enum_kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(enum_kw));
             return LY_EVALID;
         }
     }
@@ -2046,7 +1753,7 @@
     enum yang_keyword kw;
 
     if (*fracdig) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "fraction-digits");
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "fraction-digits");
         return LY_EVALID;
     }
 
@@ -2054,7 +1761,7 @@
     LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
 
     if (!word_len || (word[0] == '0') || !isdigit(word[0])) {
-        LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "fraction-digits");
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "fraction-digits");
         free(buf);
         return LY_EVALID;
     }
@@ -2063,12 +1770,12 @@
     num = strtoul(word, &ptr, 10);
     /* we have not parsed the whole argument */
     if ((size_t)(ptr - word) != word_len) {
-        LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "fraction-digits");
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "fraction-digits");
         free(buf);
         return LY_EVALID;
     }
     if ((errno == ERANGE) || (num > 18)) {
-        LOGVAL_YANG(ctx, LY_VCODE_OOB, word_len, word, "fraction-digits");
+        LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, "fraction-digits");
         free(buf);
         return LY_EVALID;
     }
@@ -2081,7 +1788,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_FRACDIGITS, 0, exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "fraction-digits");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "fraction-digits");
             return LY_EVALID;
         }
     }
@@ -2109,7 +1816,7 @@
     enum yang_keyword kw;
 
     if (*flags & LYS_SET_REQINST) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "require-instance");
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "require-instance");
         return LY_EVALID;
     }
     *flags |= LYS_SET_REQINST;
@@ -2120,7 +1827,7 @@
     if ((word_len == 4) && !strncmp(word, "true", word_len)) {
         *reqinst = 1;
     } else if ((word_len != 5) || strncmp(word, "false", word_len)) {
-        LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "require-instance");
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "require-instance");
         free(buf);
         return LY_EVALID;
     }
@@ -2132,7 +1839,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_REQINSTANCE, 0, exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "require-instance");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "require-instance");
             return LY_EVALID;
         }
     }
@@ -2158,7 +1865,7 @@
     enum yang_keyword kw;
 
     if ((*pat)[0] == 0x15) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "modifier");
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "modifier");
         return LY_EVALID;
     }
 
@@ -2166,7 +1873,7 @@
     LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
 
     if ((word_len != 12) || strncmp(word, "invert-match", word_len)) {
-        LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "modifier");
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "modifier");
         free(buf);
         return LY_EVALID;
     }
@@ -2188,7 +1895,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MODIFIER, 0, exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "modifier");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "modifier");
             return LY_EVALID;
         }
     }
@@ -2253,7 +1960,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &restr->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "pattern");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "pattern");
             return LY_EVALID;
         }
     }
@@ -2279,7 +1986,7 @@
     struct lysp_type *nest_type;
 
     if (type->name) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "type");
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "type");
         return LY_EVALID;
     }
 
@@ -2307,7 +2014,7 @@
             break;
         case YANG_LENGTH:
             if (type->length) {
-                LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
                 return LY_EVALID;
             }
             type->length = calloc(1, sizeof *type->length);
@@ -2326,11 +2033,11 @@
             break;
         case YANG_RANGE:
             if (type->range) {
-                LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
                 return LY_EVALID;
             }
             type->range = calloc(1, sizeof *type->range);
-            LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx->ctx), LY_EVALID);
+            LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx->ctx), LY_EMEM);
 
             LY_CHECK_RET(parse_restr(ctx, data, kw, type->range));
             type->flags |= LYS_SET_RANGE;
@@ -2348,7 +2055,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &type->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "type");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "type");
             return LY_EVALID;
         }
     }
@@ -2371,23 +2078,13 @@
     char *buf, *word;
     size_t word_len;
     enum yang_keyword kw;
-    struct lysp_node *iter;
     struct lysp_node_leaf *leaf;
 
-    /* create structure */
-    leaf = calloc(1, sizeof *leaf);
-    LY_CHECK_ERR_RET(!leaf, LOGMEM(ctx->ctx), LY_EMEM);
+    /* create new leaf structure */
+    LY_LIST_NEW_RET(ctx->ctx, siblings, leaf, next);
     leaf->nodetype = LYS_LEAF;
     leaf->parent = parent;
 
-    /* insert into siblings */
-    if (!*siblings) {
-        *siblings = (struct lysp_node *)leaf;
-    } else {
-        for (iter = *siblings; iter->next; iter = iter->next);
-        iter->next = (struct lysp_node *)leaf;
-    }
-
     /* get name */
     LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     INSERT_WORD(ctx, buf, leaf->name, word, word_len);
@@ -2432,7 +2129,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &leaf->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "leaf");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "leaf");
             return LY_EVALID;
         }
     }
@@ -2440,11 +2137,11 @@
 checks:
     /* mandatory substatements */
     if (!leaf->type.name) {
-        LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "type", "leaf");
+        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "type", "leaf");
         return LY_EVALID;
     }
     if ((leaf->flags & LYS_MAND_TRUE) && (leaf->dflt)) {
-        LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMSCOMB, "mandatory", "default", "leaf");
+        LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMSCOMB, "mandatory", "default", "leaf");
         return LY_EVALID;
     }
 
@@ -2472,7 +2169,7 @@
     enum yang_keyword kw;
 
     if (*flags & LYS_SET_MAX) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "max-elements");
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "max-elements");
         return LY_EVALID;
     }
     *flags |= LYS_SET_MAX;
@@ -2481,7 +2178,7 @@
     LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
 
     if (!word_len || (word[0] == '0') || ((word[0] != 'u') && !isdigit(word[0]))) {
-        LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "max-elements");
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "max-elements");
         free(buf);
         return LY_EVALID;
     }
@@ -2491,12 +2188,12 @@
         num = strtoul(word, &ptr, 10);
         /* we have not parsed the whole argument */
         if ((size_t)(ptr - word) != word_len) {
-            LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "max-elements");
+            LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "max-elements");
             free(buf);
             return LY_EVALID;
         }
         if ((errno == ERANGE) || (num > UINT32_MAX)) {
-            LOGVAL_YANG(ctx, LY_VCODE_OOB, word_len, word, "max-elements");
+            LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, "max-elements");
             free(buf);
             return LY_EVALID;
         }
@@ -2511,7 +2208,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MAX, 0, exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "max-elements");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "max-elements");
             return LY_EVALID;
         }
     }
@@ -2539,7 +2236,7 @@
     enum yang_keyword kw;
 
     if (*flags & LYS_SET_MIN) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "min-elements");
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "min-elements");
         return LY_EVALID;
     }
     *flags |= LYS_SET_MIN;
@@ -2548,7 +2245,7 @@
     LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
 
     if (!word_len || !isdigit(word[0]) || ((word[0] == '0') && (word_len > 1))) {
-        LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "min-elements");
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "min-elements");
         free(buf);
         return LY_EVALID;
     }
@@ -2557,12 +2254,12 @@
     num = strtoul(word, &ptr, 10);
     /* we have not parsed the whole argument */
     if ((size_t)(ptr - word) != word_len) {
-        LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "min-elements");
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "min-elements");
         free(buf);
         return LY_EVALID;
     }
     if ((errno == ERANGE) || (num > UINT32_MAX)) {
-        LOGVAL_YANG(ctx, LY_VCODE_OOB, word_len, word, "min-elements");
+        LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, "min-elements");
         free(buf);
         return LY_EVALID;
     }
@@ -2575,7 +2272,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MIN, 0, exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "min-elements");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "min-elements");
             return LY_EVALID;
         }
     }
@@ -2601,7 +2298,7 @@
     enum yang_keyword kw;
 
     if (*flags & LYS_ORDBY_MASK) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "ordered-by");
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "ordered-by");
         return LY_EVALID;
     }
 
@@ -2613,7 +2310,7 @@
     } else if ((word_len == 4) && !strncmp(word, "user", word_len)) {
         *flags |= LYS_ORDBY_USER;
     } else {
-        LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "ordered-by");
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "ordered-by");
         free(buf);
         return LY_EVALID;
     }
@@ -2625,7 +2322,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_ORDEREDBY, 0, exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "ordered-by");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "ordered-by");
             return LY_EVALID;
         }
     }
@@ -2648,23 +2345,13 @@
     char *buf, *word;
     size_t word_len;
     enum yang_keyword kw;
-    struct lysp_node *iter;
     struct lysp_node_leaflist *llist;
 
-    /* create structure */
-    llist = calloc(1, sizeof *llist);
-    LY_CHECK_ERR_RET(!llist, LOGMEM(ctx->ctx), LY_EMEM);
+    /* create new leaf-list structure */
+    LY_LIST_NEW_RET(ctx->ctx, siblings, llist, next);
     llist->nodetype = LYS_LEAFLIST;
     llist->parent = parent;
 
-    /* insert into siblings */
-    if (!*siblings) {
-        *siblings = (struct lysp_node *)llist;
-    } else {
-        for (iter = *siblings; iter->next; iter = iter->next);
-        iter->next = (struct lysp_node *)llist;
-    }
-
     /* get name */
     LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     INSERT_WORD(ctx, buf, llist->name, word, word_len);
@@ -2716,7 +2403,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &llist->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "llist");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "llist");
             return LY_EVALID;
         }
     }
@@ -2724,15 +2411,15 @@
 checks:
     /* mandatory substatements */
     if (!llist->type.name) {
-        LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "type", "leaf-list");
+        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "type", "leaf-list");
         return LY_EVALID;
     }
     if ((llist->min) && (llist->dflts)) {
-        LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMSCOMB, "min-elements", "default", "leaf-list");
+        LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMSCOMB, "min-elements", "default", "leaf-list");
         return LY_EVALID;
     }
     if (llist->max && llist->min > llist->max) {
-        LOGVAL_YANG(ctx, LYVE_SEMANTICS,
+        LOGVAL_PARSER(ctx, LYVE_SEMANTICS,
                     "Invalid combination of min-elements and max-elements: min value %u is bigger than the max value %u.",
                     llist->min, llist->max);
         return LY_EVALID;
@@ -2763,7 +2450,7 @@
 
     /* get value */
     LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
-    YANG_CHECK_NONEMPTY(ctx, NULL, word_len, "refine");
+    YANG_CHECK_NONEMPTY(ctx, word_len, "refine");
     INSERT_WORD(ctx, buf, rf->nodeid, word, word_len);
 
     YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
@@ -2803,7 +2490,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &rf->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "refine");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "refine");
             return LY_EVALID;
         }
     }
@@ -2859,7 +2546,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &tpdf->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "typedef");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "typedef");
             return LY_EVALID;
         }
     }
@@ -2867,13 +2554,13 @@
 checks:
     /* mandatory substatements */
     if (!tpdf->type.name) {
-        LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "type", "typedef");
+        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "type", "typedef");
         return LY_EVALID;
     }
 
     /* store data for collision check */
     if (parent && !(parent->nodetype & (LYS_GROUPING | LYS_ACTION | LYS_INOUT | LYS_NOTIF))) {
-        ly_set_add(&ctx->tpdfs_nodes, parent, 0);
+        LY_CHECK_RET(ly_set_add(&ctx->tpdfs_nodes, parent, 0) == -1, LY_EMEM);
     }
 
     return ret;
@@ -2898,7 +2585,7 @@
     enum yang_keyword kw;
 
     if (inout_p->nodetype) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(inout_kw));
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(inout_kw));
         return LY_EVALID;
     }
 
@@ -2947,14 +2634,14 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &inout_p->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(inout_kw));
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(inout_kw));
             return LY_EVALID;
         }
     }
     LY_CHECK_RET(ret);
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(parse_finalize_reallocated(ctx, inout_p->groupings, NULL, NULL, NULL));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, inout_p->groupings, NULL, NULL, NULL));
 
     return ret;
 }
@@ -3017,14 +2704,14 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &act->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), parent ? "action" : "rpc");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), parent ? "action" : "rpc");
             return LY_EVALID;
         }
     }
     LY_CHECK_RET(ret);
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(parse_finalize_reallocated(ctx, act->groupings, NULL, NULL, NULL));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, act->groupings, NULL, NULL, NULL));
 
     return ret;
 }
@@ -3109,14 +2796,14 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &notif->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "notification");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "notification");
             return LY_EVALID;
         }
     }
     LY_CHECK_RET(ret);
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(parse_finalize_reallocated(ctx, notif->groupings, NULL, NULL, NULL));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, notif->groupings, NULL, NULL, NULL));
 
     return ret;
 }
@@ -3202,20 +2889,20 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &grp->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "grouping");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "grouping");
             return LY_EVALID;
         }
     }
     LY_CHECK_RET(ret);
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(parse_finalize_reallocated(ctx, grp->groupings, NULL, grp->actions, grp->notifs));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, grp->groupings, NULL, grp->actions, grp->notifs));
 
     return ret;
 }
 
 /**
- * @brief Parse the refine statement.
+ * @brief Parse the augment statement.
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] data Data to read from, always moved to currently handled character.
@@ -3236,7 +2923,7 @@
 
     /* get value */
     LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
-    YANG_CHECK_NONEMPTY(ctx, NULL, word_len, "augment");
+    YANG_CHECK_NONEMPTY(ctx, word_len, "augment");
     INSERT_WORD(ctx, buf, aug->nodeid, word, word_len);
     aug->nodetype = LYS_AUGMENT;
     aug->parent = parent;
@@ -3299,119 +2986,19 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &aug->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "augment");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "augment");
             return LY_EVALID;
         }
     }
     LY_CHECK_RET(ret);
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(parse_finalize_reallocated(ctx, NULL, NULL, aug->actions, aug->notifs));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, NULL, NULL, aug->actions, aug->notifs));
 
     return ret;
 }
 
 /**
- * @brief Finalize some of the structures in case they are stored in sized array,
- * which can be possibly reallocated and some other data may point to them.
- *
- * Update parent pointers in the nodes inside grouping/augment/RPC/Notification, which could be reallocated.
- *
- * @param[in] mod Parsed module to be updated.
- * @return LY_ERR value (currently only LY_SUCCESS, but it can change in future).
- */
-static LY_ERR
-parse_finalize_reallocated(struct lys_parser_ctx *ctx, struct lysp_grp *groupings, struct lysp_augment *augments,
-                           struct lysp_action *actions, struct lysp_notif *notifs)
-{
-    unsigned int u, v;
-    struct lysp_node *child;
-
-    /* finalize parent pointers to the reallocated items */
-
-    /* gropings */
-    LY_ARRAY_FOR(groupings, u) {
-        LY_LIST_FOR(groupings[u].data, child) {
-            child->parent = (struct lysp_node*)&groupings[u];
-        }
-        LY_ARRAY_FOR(groupings[u].actions, v) {
-            groupings[u].actions[v].parent = (struct lysp_node*)&groupings[u];
-        }
-        LY_ARRAY_FOR(groupings[u].notifs, v) {
-            groupings[u].notifs[v].parent = (struct lysp_node*)&groupings[u];
-        }
-        LY_ARRAY_FOR(groupings[u].groupings, v) {
-            groupings[u].groupings[v].parent = (struct lysp_node*)&groupings[u];
-        }
-        if (groupings[u].typedefs) {
-            ly_set_add(&ctx->tpdfs_nodes, &groupings[u], 0);
-        }
-    }
-
-    /* augments */
-    LY_ARRAY_FOR(augments, u) {
-        LY_LIST_FOR(augments[u].child, child) {
-            child->parent = (struct lysp_node*)&augments[u];
-        }
-        LY_ARRAY_FOR(augments[u].actions, v) {
-            augments[u].actions[v].parent = (struct lysp_node*)&augments[u];
-        }
-        LY_ARRAY_FOR(augments[u].notifs, v) {
-            augments[u].notifs[v].parent = (struct lysp_node*)&augments[u];
-        }
-    }
-
-    /* actions */
-    LY_ARRAY_FOR(actions, u) {
-        if (actions[u].input.parent) {
-            actions[u].input.parent = (struct lysp_node*)&actions[u];
-            LY_LIST_FOR(actions[u].input.data, child) {
-                child->parent = (struct lysp_node*)&actions[u].input;
-            }
-            LY_ARRAY_FOR(actions[u].input.groupings, v) {
-                actions[u].input.groupings[v].parent = (struct lysp_node*)&actions[u].input;
-            }
-            if (actions[u].input.typedefs) {
-                ly_set_add(&ctx->tpdfs_nodes, &actions[u].input, 0);
-            }
-        }
-        if (actions[u].output.parent) {
-            actions[u].output.parent = (struct lysp_node*)&actions[u];
-            LY_LIST_FOR(actions[u].output.data, child) {
-                child->parent = (struct lysp_node*)&actions[u].output;
-            }
-            LY_ARRAY_FOR(actions[u].output.groupings, v) {
-                actions[u].output.groupings[v].parent = (struct lysp_node*)&actions[u].output;
-            }
-            if (actions[u].output.typedefs) {
-                ly_set_add(&ctx->tpdfs_nodes, &actions[u].output, 0);
-            }
-        }
-        LY_ARRAY_FOR(actions[u].groupings, v) {
-            actions[u].groupings[v].parent = (struct lysp_node*)&actions[u];
-        }
-        if (actions[u].typedefs) {
-            ly_set_add(&ctx->tpdfs_nodes, &actions[u], 0);
-        }
-    }
-
-    /* notifications */
-    LY_ARRAY_FOR(notifs, u) {
-        LY_LIST_FOR(notifs[u].data, child) {
-            child->parent = (struct lysp_node*)&notifs[u];
-        }
-        LY_ARRAY_FOR(notifs[u].groupings, v) {
-            notifs[u].groupings[v].parent = (struct lysp_node*)&notifs[u];
-        }
-        if (notifs[u].typedefs) {
-            ly_set_add(&ctx->tpdfs_nodes, &notifs[u], 0);
-        }
-    }
-
-    return LY_SUCCESS;
-}
-
-/**
  * @brief Parse the uses statement.
  *
  * @param[in] ctx yang parser context for logging.
@@ -3427,23 +3014,13 @@
     char *buf, *word;
     size_t word_len;
     enum yang_keyword kw;
-    struct lysp_node *iter;
     struct lysp_node_uses *uses;
 
-    /* create structure */
-    uses = calloc(1, sizeof *uses);
-    LY_CHECK_ERR_RET(!uses, LOGMEM(ctx->ctx), LY_EMEM);
+    /* create uses structure */
+    LY_LIST_NEW_RET(ctx->ctx, siblings, uses, next);
     uses->nodetype = LYS_USES;
     uses->parent = parent;
 
-    /* insert into siblings */
-    if (!*siblings) {
-        *siblings = (struct lysp_node *)uses;
-    } else {
-        for (iter = *siblings; iter->next; iter = iter->next);
-        iter->next = (struct lysp_node *)uses;
-    }
-
     /* get name */
     LY_CHECK_RET(get_argument(ctx, data, Y_PREF_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     INSERT_WORD(ctx, buf, uses->name, word, word_len);
@@ -3477,13 +3054,13 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &uses->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "uses");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "uses");
             return LY_EVALID;
         }
     }
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(parse_finalize_reallocated(ctx, NULL, uses->augments, NULL, NULL));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, NULL, uses->augments, NULL, NULL));
 
     return ret;
 }
@@ -3504,23 +3081,13 @@
     char *buf, *word;
     size_t word_len;
     enum yang_keyword kw;
-    struct lysp_node *iter;
     struct lysp_node_case *cas;
 
-    /* create structure */
-    cas = calloc(1, sizeof *cas);
-    LY_CHECK_ERR_RET(!cas, LOGMEM(ctx->ctx), LY_EMEM);
+    /* create new case structure */
+    LY_LIST_NEW_RET(ctx->ctx, siblings, cas, next);
     cas->nodetype = LYS_CASE;
     cas->parent = parent;
 
-    /* insert into siblings */
-    if (!*siblings) {
-        *siblings = (struct lysp_node *)cas;
-    } else {
-        for (iter = *siblings; iter->next; iter = iter->next);
-        iter->next = (struct lysp_node *)cas;
-    }
-
     /* get name */
     LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     INSERT_WORD(ctx, buf, cas->name, word, word_len);
@@ -3572,7 +3139,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &cas->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "case");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "case");
             return LY_EVALID;
         }
     }
@@ -3595,23 +3162,13 @@
     char *buf, *word;
     size_t word_len;
     enum yang_keyword kw;
-    struct lysp_node *iter;
     struct lysp_node_choice *choice;
 
-    /* create structure */
-    choice = calloc(1, sizeof *choice);
-    LY_CHECK_ERR_RET(!choice, LOGMEM(ctx->ctx), LY_EMEM);
+    /* create new choice structure */
+    LY_LIST_NEW_RET(ctx->ctx, siblings, choice, next);
     choice->nodetype = LYS_CHOICE;
     choice->parent = parent;
 
-    /* insert into siblings */
-    if (!*siblings) {
-        *siblings = (struct lysp_node *)choice;
-    } else {
-        for (iter = *siblings; iter->next; iter = iter->next);
-        iter->next = (struct lysp_node *)choice;
-    }
-
     /* get name */
     LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     INSERT_WORD(ctx, buf, choice->name, word, word_len);
@@ -3673,14 +3230,14 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &choice->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "choice");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "choice");
             return LY_EVALID;
         }
     }
     LY_CHECK_RET(ret);
 checks:
     if ((choice->flags & LYS_MAND_TRUE) && choice->dflt) {
-        LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMSCOMB, "mandatory", "default", "choice");
+        LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMSCOMB, "mandatory", "default", "choice");
         return LY_EVALID;
     }
     return ret;
@@ -3702,23 +3259,13 @@
     char *buf, *word;
     size_t word_len;
     enum yang_keyword kw;
-    struct lysp_node *iter;
     struct lysp_node_container *cont;
 
-    /* create structure */
-    cont = calloc(1, sizeof *cont);
-    LY_CHECK_ERR_RET(!cont, LOGMEM(ctx->ctx), LY_EMEM);
+    /* create new container structure */
+    LY_LIST_NEW_RET(ctx->ctx, siblings, cont, next);
     cont->nodetype = LYS_CONTAINER;
     cont->parent = parent;
 
-    /* insert into siblings */
-    if (!*siblings) {
-        *siblings = (struct lysp_node *)cont;
-    } else {
-        for (iter = *siblings; iter->next; iter = iter->next);
-        iter->next = (struct lysp_node *)cont;
-    }
-
     /* get name */
     LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     INSERT_WORD(ctx, buf, cont->name, word, word_len);
@@ -3794,13 +3341,13 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &cont->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "container");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "container");
             return LY_EVALID;
         }
     }
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(parse_finalize_reallocated(ctx, cont->groupings, NULL, cont->actions, cont->notifs));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, cont->groupings, NULL, cont->actions, cont->notifs));
     return ret;
 }
 
@@ -3820,23 +3367,13 @@
     char *buf, *word;
     size_t word_len;
     enum yang_keyword kw;
-    struct lysp_node *iter;
     struct lysp_node_list *list;
 
-    /* create structure */
-    list = calloc(1, sizeof *list);
-    LY_CHECK_ERR_RET(!list, LOGMEM(ctx->ctx), LY_EMEM);
+    /* create new list structure */
+    LY_LIST_NEW_RET(ctx->ctx, siblings, list, next);
     list->nodetype = LYS_LIST;
     list->parent = parent;
 
-    /* insert into siblings */
-    if (!*siblings) {
-        *siblings = (struct lysp_node *)list;
-    } else {
-        for (iter = *siblings; iter->next; iter = iter->next);
-        iter->next = (struct lysp_node *)list;
-    }
-
     /* get name */
     LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     INSERT_WORD(ctx, buf, list->name, word, word_len);
@@ -3924,17 +3461,17 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &list->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "list");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "list");
             return LY_EVALID;
         }
     }
     LY_CHECK_RET(ret);
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(parse_finalize_reallocated(ctx, list->groupings, NULL, list->actions, list->notifs));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, list->groupings, NULL, list->actions, list->notifs));
 
     if (list->max && list->min > list->max) {
-        LOGVAL_YANG(ctx, LYVE_SEMANTICS,
+        LOGVAL_PARSER(ctx, LYVE_SEMANTICS,
                     "Invalid combination of min-elements and max-elements: min value %u is bigger than the max value %u.",
                     list->min, list->max);
         return LY_EVALID;
@@ -3962,7 +3499,7 @@
     enum yang_keyword kw;
 
     if (*flags & LYS_YINELEM_MASK) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "yin-element");
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "yin-element");
         return LY_EVALID;
     }
 
@@ -3974,7 +3511,7 @@
     } else if ((word_len == 5) && !strncmp(word, "false", word_len)) {
         *flags |= LYS_YINELEM_FALSE;
     } else {
-        LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "yin-element");
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "yin-element");
         free(buf);
         return LY_EVALID;
     }
@@ -3986,7 +3523,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_YINELEM, 0, exts));
             LY_CHECK_RET(ret);            break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yin-element");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yin-element");
             return LY_EVALID;
         }
     }
@@ -3994,7 +3531,7 @@
 }
 
 /**
- * @brief Parse the yin-element statement.
+ * @brief Parse the argument statement.
  *
  * @param[in] ctx yang parser context for logging.
  * @param[in,out] data Data to read from, always moved to currently handled character.
@@ -4013,12 +3550,12 @@
     enum yang_keyword kw;
 
     if (*argument) {
-        LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "argument");
+        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "argument");
         return LY_EVALID;
     }
 
     /* get value */
-    LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
+    LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     INSERT_WORD(ctx, buf, *argument, word, word_len);
 
     YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
@@ -4030,7 +3567,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_ARGUMENT, 0, exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "argument");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "argument");
             return LY_EVALID;
         }
     }
@@ -4079,7 +3616,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &ex->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "extension");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "extension");
             return LY_EVALID;
         }
     }
@@ -4102,7 +3639,7 @@
     char *buf, *word;
     size_t word_len, dev_mod;
     enum yang_keyword kw;
-    struct lysp_deviate *iter, *d;
+    struct lysp_deviate *d;
     struct lysp_deviate_add *d_add = NULL;
     struct lysp_deviate_rpl *d_rpl = NULL;
     struct lysp_deviate_del *d_del = NULL;
@@ -4123,7 +3660,7 @@
     } else if ((word_len == 6) && !strncmp(word, "delete", word_len)) {
         dev_mod = LYS_DEV_DELETE;
     } else {
-        LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "deviate");
+        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "deviate");
         free(buf);
         return LY_EVALID;
     }
@@ -4164,7 +3701,6 @@
         d_uniques = &d_del->uniques;
         d_dflts = &d_del->dflts;
         d_musts = &d_del->musts;
-        d_flags = &d_del->flags;
         break;
     default:
         assert(0);
@@ -4173,12 +3709,7 @@
     d->mod = dev_mod;
 
     /* insert into siblings */
-    if (!*deviates) {
-        *deviates = d;
-    } else {
-        for (iter = *deviates; iter->next; iter = iter->next);
-        iter->next = d;
-    }
+    LY_LIST_INSERT(deviates, d, next);
 
     YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
         switch (kw) {
@@ -4186,7 +3717,7 @@
             switch (dev_mod) {
             case LYS_DEV_NOT_SUPPORTED:
             case LYS_DEV_DELETE:
-                LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
                 return LY_EVALID;
             default:
                 LY_CHECK_RET(parse_config(ctx, data, d_flags, &d->exts));
@@ -4196,7 +3727,7 @@
         case YANG_DEFAULT:
             switch (dev_mod) {
             case LYS_DEV_NOT_SUPPORTED:
-                LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
                 return LY_EVALID;
             case LYS_DEV_REPLACE:
                 LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_DEFAULT, 0, &d_rpl->dflt, Y_STR_ARG, &d->exts));
@@ -4210,7 +3741,7 @@
             switch (dev_mod) {
             case LYS_DEV_NOT_SUPPORTED:
             case LYS_DEV_DELETE:
-                LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
                 return LY_EVALID;
             default:
                 LY_CHECK_RET(parse_mandatory(ctx, data, d_flags, &d->exts));
@@ -4221,7 +3752,7 @@
             switch (dev_mod) {
             case LYS_DEV_NOT_SUPPORTED:
             case LYS_DEV_DELETE:
-                LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
                 return LY_EVALID;
             default:
                 LY_CHECK_RET(parse_maxelements(ctx, data, d_max, d_flags, &d->exts));
@@ -4232,7 +3763,7 @@
             switch (dev_mod) {
             case LYS_DEV_NOT_SUPPORTED:
             case LYS_DEV_DELETE:
-                LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
                 return LY_EVALID;
             default:
                 LY_CHECK_RET(parse_minelements(ctx, data, d_min, d_flags, &d->exts));
@@ -4243,7 +3774,7 @@
             switch (dev_mod) {
             case LYS_DEV_NOT_SUPPORTED:
             case LYS_DEV_REPLACE:
-                LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
                 return LY_EVALID;
             default:
                 LY_CHECK_RET(parse_restrs(ctx, data, kw, d_musts));
@@ -4255,11 +3786,11 @@
             case LYS_DEV_NOT_SUPPORTED:
             case LYS_DEV_ADD:
             case LYS_DEV_DELETE:
-                LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
                 return LY_EVALID;
             default:
                 if (d_rpl->type) {
-                    LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
+                    LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
                     return LY_EVALID;
                 }
                 d_rpl->type = calloc(1, sizeof *d_rpl->type);
@@ -4272,7 +3803,7 @@
             switch (dev_mod) {
             case LYS_DEV_NOT_SUPPORTED:
             case LYS_DEV_REPLACE:
-                LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
                 return LY_EVALID;
             default:
                 LY_CHECK_RET(parse_text_fields(ctx, data, LYEXT_SUBSTMT_UNIQUE, d_uniques, Y_STR_ARG, &d->exts));
@@ -4282,7 +3813,7 @@
         case YANG_UNITS:
             switch (dev_mod) {
             case LYS_DEV_NOT_SUPPORTED:
-                LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
                 return LY_EVALID;
             default:
                 LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_UNITS, 0, d_units, Y_STR_ARG, &d->exts));
@@ -4293,7 +3824,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &d->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviate");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviate");
             return LY_EVALID;
         }
     }
@@ -4322,7 +3853,7 @@
 
     /* get value */
     LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
-    YANG_CHECK_NONEMPTY(ctx, NULL, word_len, "deviation");
+    YANG_CHECK_NONEMPTY(ctx, word_len, "deviation");
     INSERT_WORD(ctx, buf, dev->nodeid, word, word_len);
 
     YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
@@ -4340,7 +3871,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &dev->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviation");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviation");
             return LY_EVALID;
         }
     }
@@ -4348,7 +3879,7 @@
 checks:
     /* mandatory substatements */
     if (!dev->deviates) {
-        LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "deviate", "deviation");
+        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "deviate", "deviation");
         return LY_EVALID;
     }
 
@@ -4397,7 +3928,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &feat->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "feature");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "feature");
             return LY_EVALID;
         }
     }
@@ -4445,7 +3976,7 @@
             break;
         case YANG_BASE:
             if (ident->bases && ctx->mod_version < 2) {
-                LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Identity can be derived from multiple base identities only in YANG 1.1 modules");
+                LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Identity can be derived from multiple base identities only in YANG 1.1 modules");
                 return LY_EVALID;
             }
             LY_CHECK_RET(parse_text_fields(ctx, data, LYEXT_SUBSTMT_BASE, &ident->bases, Y_PREF_IDENTIF_ARG, &ident->exts));
@@ -4454,7 +3985,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &ident->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "identity");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "identity");
             return LY_EVALID;
         }
     }
@@ -4487,7 +4018,7 @@
     YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
 
 #define CHECK_ORDER(SECTION) \
-        if (mod_stmt > SECTION) {LOGVAL_YANG(ctx, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw)); return LY_EVALID;}mod_stmt = SECTION
+        if (mod_stmt > SECTION) {LOGVAL_PARSER(ctx, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw)); return LY_EVALID;}mod_stmt = SECTION
 
         switch (kw) {
         /* module header */
@@ -4641,7 +4172,7 @@
             break;
 
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "module");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "module");
             return LY_EVALID;
         }
     }
@@ -4649,14 +4180,14 @@
 
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(parse_finalize_reallocated(ctx, mod->groupings, mod->augments, mod->rpcs, mod->notifs));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, mod->groupings, mod->augments, mod->rpcs, mod->notifs));
 
     /* mandatory substatements */
     if (!mod->mod->ns) {
-        LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "namespace", "module");
+        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "namespace", "module");
         return LY_EVALID;
     } else if (!mod->mod->prefix) {
-        LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "prefix", "module");
+        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "prefix", "module");
         return LY_EVALID;
     }
 
@@ -4664,7 +4195,7 @@
      * a submodule of the same name in the context, no need for revision matching */
     dup = ly_ctx_get_submodule(ctx->ctx, NULL, mod->mod->name, NULL);
     if (dup) {
-        LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Name collision between module and submodule of name \"%s\".", mod->mod->name);
+        LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Name collision between module and submodule of name \"%s\".", mod->mod->name);
         return LY_EVALID;
     }
 
@@ -4697,7 +4228,7 @@
     YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
 
 #define CHECK_ORDER(SECTION) \
-        if (mod_stmt > SECTION) {LOGVAL_YANG(ctx, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw)); return LY_EVALID;}mod_stmt = SECTION
+        if (mod_stmt > SECTION) {LOGVAL_PARSER(ctx, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw)); return LY_EVALID;}mod_stmt = SECTION
 
         switch (kw) {
         /* module header */
@@ -4847,7 +4378,7 @@
             break;
 
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "submodule");
+            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "submodule");
             return LY_EVALID;
         }
     }
@@ -4855,11 +4386,11 @@
 
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(parse_finalize_reallocated(ctx, submod->groupings, submod->augments, submod->rpcs, submod->notifs));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, submod->groupings, submod->augments, submod->rpcs, submod->notifs));
 
     /* mandatory substatements */
     if (!submod->belongsto) {
-        LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "belongs-to", "submodule");
+        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "belongs-to", "submodule");
         return LY_EVALID;
     }
 
@@ -4867,7 +4398,7 @@
      * a submodule of the same name in the context, no need for revision matching */
     dup = ly_ctx_get_submodule(ctx->ctx, NULL, submod->name, NULL);
     if (dup && strcmp(dup->belongsto, submod->belongsto)) {
-        LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Name collision between submodules of name \"%s\".", dup->name);
+        LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Name collision between submodules of name \"%s\".", dup->name);
         return LY_EVALID;
     }
 
@@ -4875,7 +4406,7 @@
 }
 
 LY_ERR
-yang_parse_submodule(struct lys_parser_ctx *context, const char *data, struct lysp_submodule **submod)
+yang_parse_submodule(struct lys_parser_ctx **context, struct ly_ctx *ly_ctx, struct lys_parser_ctx *main_ctx, const char *data, struct lysp_submodule **submod)
 {
     LY_ERR ret = LY_SUCCESS;
     char *word;
@@ -4883,27 +4414,36 @@
     enum yang_keyword kw;
     struct lysp_submodule *mod_p = NULL;
 
+    /* create context */
+    *context = calloc(1, sizeof **context);
+    LY_CHECK_ERR_RET(!(*context), LOGMEM(ly_ctx), LY_EMEM);
+    (*context)->ctx = ly_ctx;
+    (*context)->line = 1;
+
+    /* map the typedefs and groupings list from main context to the submodule's context */
+    memcpy(&(*context)->tpdfs_nodes, &main_ctx->tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
+    memcpy(&(*context)->grps_nodes, &main_ctx->grps_nodes, sizeof main_ctx->grps_nodes);
+
     /* "module"/"submodule" */
-    ret = get_keyword(context, &data, &kw, &word, &word_len);
+    ret = get_keyword(*context, &data, &kw, &word, &word_len);
     LY_CHECK_GOTO(ret, cleanup);
 
     if (kw == YANG_MODULE) {
-        LOGERR(context->ctx, LY_EDENIED, "Input data contains module in situation when a submodule is expected.");
+        LOGERR((*context)->ctx, LY_EDENIED, "Input data contains module in situation when a submodule is expected.");
         ret = LY_EINVAL;
         goto cleanup;
     } else if (kw != YANG_SUBMODULE) {
-        LOGVAL_YANG(context, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".",
-               ly_stmt2str(kw));
+        LOGVAL_PARSER(*context, LY_VCODE_MOD_SUBOMD, ly_stmt2str(kw));
         ret = LY_EVALID;
         goto cleanup;
     }
 
     mod_p = calloc(1, sizeof *mod_p);
-    LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(context->ctx), cleanup);
+    LY_CHECK_ERR_GOTO(!mod_p, LOGMEM((*context)->ctx), cleanup);
     mod_p->parsing = 1;
 
     /* substatements */
-    ret = parse_submodule(context, &data, mod_p);
+    ret = parse_submodule(*context, &data, mod_p);
     LY_CHECK_GOTO(ret, cleanup);
 
     /* read some trailing spaces or new lines */
@@ -4911,8 +4451,7 @@
         data++;
     }
     if (*data) {
-        LOGVAL_YANG(context, LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after submodule, expected end-of-input.",
-                    15, data, strlen(data) > 15 ? "..." : "");
+        LOGVAL_PARSER(*context, LY_VCODE_TRAILING_SUBMOD, 15, data, strlen(data) > 15 ? "..." : "");
         ret = LY_EVALID;
         goto cleanup;
     }
@@ -4922,14 +4461,16 @@
 
 cleanup:
     if (ret) {
-        lysp_submodule_free(context->ctx, mod_p);
+        lysp_submodule_free((*context)->ctx, mod_p);
+        lys_parser_ctx_free(*context);
+        *context = NULL;
     }
 
     return ret;
 }
 
 LY_ERR
-yang_parse_module(struct lys_parser_ctx *context, const char *data, struct lys_module *mod)
+yang_parse_module(struct lys_parser_ctx **context, const char *data, struct lys_module *mod)
 {
     LY_ERR ret = LY_SUCCESS;
     char *word;
@@ -4937,28 +4478,33 @@
     enum yang_keyword kw;
     struct lysp_module *mod_p = NULL;
 
+    /* create context */
+    *context = calloc(1, sizeof **context);
+    LY_CHECK_ERR_RET(!(*context), LOGMEM(mod->ctx), LY_EMEM);
+    (*context)->ctx = mod->ctx;
+    (*context)->line = 1;
+
     /* "module"/"submodule" */
-    ret = get_keyword(context, &data, &kw, &word, &word_len);
+    ret = get_keyword(*context, &data, &kw, &word, &word_len);
     LY_CHECK_GOTO(ret, cleanup);
 
     if (kw == YANG_SUBMODULE) {
-        LOGERR(context->ctx, LY_EDENIED, "Input data contains submodule which cannot be parsed directly without its main module.");
+        LOGERR((*context)->ctx, LY_EDENIED, "Input data contains submodule which cannot be parsed directly without its main module.");
         ret = LY_EINVAL;
         goto cleanup;
     } else if (kw != YANG_MODULE) {
-        LOGVAL_YANG(context, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".",
-               ly_stmt2str(kw));
+        LOGVAL_PARSER((*context), LY_VCODE_MOD_SUBOMD, ly_stmt2str(kw));
         ret = LY_EVALID;
         goto cleanup;
     }
 
     mod_p = calloc(1, sizeof *mod_p);
-    LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(context->ctx), cleanup);
+    LY_CHECK_ERR_GOTO(!mod_p, LOGMEM((*context)->ctx), cleanup);
     mod_p->mod = mod;
     mod_p->parsing = 1;
 
     /* substatements */
-    ret = parse_module(context, &data, mod_p);
+    ret = parse_module(*context, &data, mod_p);
     LY_CHECK_GOTO(ret, cleanup);
 
     /* read some trailing spaces or new lines */
@@ -4966,8 +4512,7 @@
         data++;
     }
     if (*data) {
-        LOGVAL_YANG(context, LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after module, expected end-of-input.",
-                    15, data, strlen(data) > 15 ? "..." : "");
+        LOGVAL_PARSER(*context, LY_VCODE_TRAILING_MOD, 15, data, strlen(data) > 15 ? "..." : "");
         ret = LY_EVALID;
         goto cleanup;
     }
@@ -4978,6 +4523,8 @@
 cleanup:
     if (ret) {
         lysp_module_free(mod_p);
+        lys_parser_ctx_free(*context);
+        *context = NULL;
     }
 
     return ret;
diff --git a/src/parser_yin.c b/src/parser_yin.c
new file mode 100644
index 0000000..2ce5ccc
--- /dev/null
+++ b/src/parser_yin.c
@@ -0,0 +1,3556 @@
+/**
+ * @file parser_yin.c
+ * @author David Sedlák <xsedla1d@stud.fit.vutbr.cz>
+ * @brief YIN parser.
+ *
+ * Copyright (c) 2015 - 2019 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.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+#include "common.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#include "context.h"
+#include "dict.h"
+#include "xml.h"
+#include "tree.h"
+#include "tree_schema.h"
+#include "tree_schema_internal.h"
+#include "parser_yin.h"
+
+/**
+ * @brief check if given string is URI of yin namespace.
+ *
+ * @param ns Namespace URI to check.
+ *
+ * @return true if ns equals YIN_NS_URI false otherwise.
+ */
+#define IS_YIN_NS(ns) (strcmp(ns, YIN_NS_URI) == 0)
+
+const char *const yin_attr_list[] = {
+    [YIN_ARG_NAME] = "name",
+    [YIN_ARG_TARGET_NODE] = "target-node",
+    [YIN_ARG_MODULE] = "module",
+    [YIN_ARG_VALUE] = "value",
+    [YIN_ARG_TEXT] = "text",
+    [YIN_ARG_CONDITION] = "condition",
+    [YIN_ARG_URI] = "uri",
+    [YIN_ARG_DATE] = "date",
+    [YIN_ARG_TAG] = "tag",
+};
+
+enum yang_keyword
+yin_match_keyword(struct yin_parser_ctx *ctx, const char *name, size_t name_len,
+                  const char *prefix, size_t prefix_len, enum yang_keyword parrent)
+{
+    const char *start = NULL;
+    enum yang_keyword kw = YANG_NONE;
+    const struct lyxml_ns *ns = NULL;
+
+    if (!name || name_len == 0) {
+        return YANG_NONE;
+    }
+
+    ns = lyxml_ns_get(&ctx->xml_ctx, prefix, prefix_len);
+    if (ns) {
+        if (!IS_YIN_NS(ns->uri)) {
+            return YANG_CUSTOM;
+        }
+    } else {
+        /* elements without namespace are automatically unknown */
+        return YANG_NONE;
+    }
+
+    start = name;
+    kw = lysp_match_kw(NULL, &name);
+
+    if (name - start == (long int)name_len) {
+        /* this is done because of collision in yang statement value and yang argument mapped to yin element value */
+        if (kw == YANG_VALUE && parrent == YANG_ERROR_MESSAGE) {
+            return YIN_VALUE;
+        }
+        return kw;
+    } else {
+        if (strncmp(start, "text", name_len) == 0) {
+            return YIN_TEXT;
+        } else {
+            return YANG_NONE;
+        }
+    }
+}
+
+enum yin_argument
+yin_match_argument_name(const char *name, size_t len)
+{
+    enum yin_argument arg = YIN_ARG_UNKNOWN;
+    size_t already_read = 0;
+    LY_CHECK_RET(len == 0, YIN_ARG_NONE);
+
+#define IF_ARG(STR, LEN, STMT) if (!strncmp((name) + already_read, STR, LEN)) {already_read+=LEN;arg=STMT;}
+#define IF_ARG_PREFIX(STR, LEN) if (!strncmp((name) + already_read, STR, LEN)) {already_read+=LEN;
+#define IF_ARG_PREFIX_END }
+
+    switch (*name) {
+    case 'c':
+        already_read += 1;
+        IF_ARG("ondition", 8, YIN_ARG_CONDITION);
+        break;
+
+    case 'd':
+        already_read += 1;
+        IF_ARG("ate", 3, YIN_ARG_DATE);
+        break;
+
+    case 'm':
+        already_read += 1;
+        IF_ARG("odule", 5, YIN_ARG_MODULE);
+        break;
+
+    case 'n':
+        already_read += 1;
+        IF_ARG("ame", 3, YIN_ARG_NAME);
+        break;
+
+    case 't':
+        already_read += 1;
+        IF_ARG_PREFIX("a", 1)
+            IF_ARG("g", 1, YIN_ARG_TAG)
+            else IF_ARG("rget-node", 9, YIN_ARG_TARGET_NODE)
+        IF_ARG_PREFIX_END
+        else IF_ARG("ext", 3, YIN_ARG_TEXT)
+        break;
+
+    case 'u':
+        already_read += 1;
+        IF_ARG("ri", 2, YIN_ARG_URI)
+        break;
+
+    case 'v':
+        already_read += 1;
+        IF_ARG("alue", 4, YIN_ARG_VALUE);
+        break;
+    }
+
+    /* whole argument must be matched */
+    if (already_read != len) {
+        arg = YIN_ARG_UNKNOWN;
+    }
+
+#undef IF_ARG
+#undef IF_ARG_PREFIX
+#undef IF_ARG_PREFIX_END
+
+    return arg;
+}
+
+void free_arg_rec(struct yin_parser_ctx *ctx, struct yin_arg_record *record) {
+    (void)ctx; /* unused */
+    if (record && record->dynamic_content) {
+        free(record->content);
+    }
+}
+
+#define IS_NODE_ELEM(kw) (kw == YANG_ANYXML || kw == YANG_ANYDATA || kw == YANG_LEAF || kw == YANG_LEAF_LIST || \
+                          kw == YANG_TYPEDEF || kw == YANG_USES || kw == YANG_LIST || kw == YANG_NOTIFICATION || \
+                          kw == YANG_GROUPING || kw == YANG_CONTAINER || kw == YANG_CASE || kw == YANG_CHOICE || \
+                          kw == YANG_ACTION || kw == YANG_RPC || kw == YANG_AUGMENT)
+
+#define HAS_META(kw) (IS_NODE_ELEM(kw) || kw == YANG_IMPORT || kw == YANG_INCLUDE || kw == YANG_INPUT || kw == YANG_OUTPUT)
+
+/**
+ * @brief Free subelems information allocated on heap.
+ *
+ * @param[in] count Size of subelems array.
+ * @param[in] subelems Subelems array to free.
+ */
+static void
+subelems_deallocator(size_t count, struct yin_subelement *subelems)
+{
+    for(size_t i = 0; i < count; ++i) {
+        if (HAS_META(subelems[i].type)) {
+            free(subelems[i].dest);
+        }
+    }
+
+    free(subelems);
+}
+
+/**
+ * @brief Allocate subelems information on heap.
+ *
+ * @param[in] ctx YIN parser context, used for logging.
+ * @param[in] count Number of subelements.
+ * @param[in] parent Parent node if any.
+ * @param[out] result Allocated subelems array.
+ *
+ * @return LY_SUCCESS on success LY_EMEM on memmory allocation failure.
+ */
+static LY_ERR
+subelems_allocator(struct yin_parser_ctx *ctx, size_t count, struct lysp_node *parent,
+                   struct yin_subelement **result, ...)
+{
+    va_list ap;
+
+    *result = calloc(count, sizeof **result);
+    LY_CHECK_GOTO(!(*result), mem_err);
+
+    va_start(ap, result);
+    for (size_t i = 0; i < count; ++i) {
+        /* TYPE */
+        (*result)[i].type = va_arg(ap, enum yang_keyword);
+        /* DEST */
+        if (IS_NODE_ELEM((*result)[i].type)) {
+            struct tree_node_meta *node_meta = NULL;
+            node_meta = calloc(1, sizeof *node_meta);
+            LY_CHECK_GOTO(!node_meta, mem_err);
+            node_meta->parent = parent;
+            node_meta->nodes = va_arg(ap, void *);
+            (*result)[i].dest = node_meta;
+        } else if ((*result)[i].type == YANG_IMPORT) {
+            struct import_meta *imp_meta = NULL;
+            imp_meta = calloc(1, sizeof *imp_meta);
+            LY_CHECK_GOTO(!imp_meta, mem_err);
+            imp_meta->prefix = va_arg(ap, const char *);
+            imp_meta->imports = va_arg(ap, struct lysp_import **);
+            (*result)[i].dest = imp_meta;
+        } else if ((*result)[i].type == YANG_INCLUDE) {
+            struct include_meta *inc_meta = NULL;
+            inc_meta = calloc(1, sizeof *inc_meta);
+            LY_CHECK_GOTO(!inc_meta, mem_err);
+            inc_meta->name = va_arg(ap, const char *);
+            inc_meta->includes = va_arg(ap, struct lysp_include **);
+            (*result)[i].dest = inc_meta;
+        } else if ((*result)[i].type == YANG_INPUT || (*result)[i].type == YANG_OUTPUT) {
+            struct inout_meta *inout_meta = NULL;
+            inout_meta = calloc(1, sizeof *inout_meta);
+            LY_CHECK_GOTO(!inout_meta, mem_err);
+            inout_meta->parent = parent;
+            inout_meta->inout_p = va_arg(ap, struct lysp_action_inout *);
+            (*result)[i].dest = inout_meta;
+        } else {
+            (*result)[i].dest = va_arg(ap, void *);
+        }
+        /* FLAGS */
+        (*result)[i].flags = va_arg(ap, int);
+    }
+    va_end(ap);
+
+    return LY_SUCCESS;
+
+mem_err:
+    subelems_deallocator(count, *result);
+    LOGMEM(ctx->xml_ctx.ctx);
+    return LY_EMEM;
+}
+
+LY_ERR
+yin_load_attributes(struct yin_parser_ctx *ctx, const char **data, struct yin_arg_record **attrs)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct yin_arg_record *argument_record = NULL;
+    const char *prefix, *name;
+    size_t prefix_len, name_len;
+
+    /* load all attributes */
+    while (ctx->xml_ctx.status == LYXML_ATTRIBUTE) {
+        ret = lyxml_get_attribute(&ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
+        LY_CHECK_GOTO(ret, cleanup);
+
+        if (ctx->xml_ctx.status == LYXML_ATTR_CONTENT) {
+            LY_ARRAY_NEW_GOTO(ctx->xml_ctx.ctx, *attrs, argument_record, ret, cleanup);
+            argument_record->name = name;
+            argument_record->name_len = name_len;
+            argument_record->prefix = prefix;
+            argument_record->prefix_len = prefix_len;
+            ret = lyxml_get_string(&ctx->xml_ctx, data, &argument_record->content, &argument_record->content_len,
+                                   &argument_record->content, &argument_record->content_len, &argument_record->dynamic_content);
+            LY_CHECK_GOTO(ret, cleanup);
+        }
+    }
+
+cleanup:
+    if (ret != LY_SUCCESS) {
+        FREE_ARRAY(ctx, *attrs, free_arg_rec);
+        *attrs = NULL;
+    }
+    return ret;
+}
+
+LY_ERR
+yin_validate_value(struct yin_parser_ctx *ctx, enum yang_arg val_type, char *val, size_t len)
+{
+    int prefix = 0;
+    unsigned int c;
+    size_t utf8_char_len;
+    size_t already_read = 0;
+    while (already_read < len) {
+        LY_CHECK_ERR_RET(ly_getutf8((const char **)&val, &c, &utf8_char_len),
+                         LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INCHAR, (val)[-utf8_char_len]), LY_EVALID);
+        already_read += utf8_char_len;
+        LY_CHECK_ERR_RET(already_read > len, LOGINT(ctx->xml_ctx.ctx), LY_EINT);
+
+        switch (val_type) {
+        case Y_IDENTIF_ARG:
+            LY_CHECK_RET(lysp_check_identifierchar((struct lys_parser_ctx *)ctx, c, !already_read, NULL));
+            break;
+        case Y_PREF_IDENTIF_ARG:
+            LY_CHECK_RET(lysp_check_identifierchar((struct lys_parser_ctx *)ctx, c, !already_read, &prefix));
+            break;
+        case Y_STR_ARG:
+        case Y_MAYBE_STR_ARG:
+            LY_CHECK_RET(lysp_check_stringchar((struct lys_parser_ctx *)ctx, c));
+            break;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse yin attribute.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs ([Sized array](@ref sizedarrays)) of attributes.
+ * @param[in] arg_type Type of argument that is expected in parsed element (use YIN_ARG_NONE for elements without
+ *            special argument).
+ * @param[out] arg_val Where value of argument should be stored. Can be NULL iff arg_type is specified as YIN_ARG_NONE.
+ * @param[in] val_type Type of expected value of attribute.
+ * @param[in] current_element Identification of current element, used for logging.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_attribute(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, enum yin_argument arg_type,
+                    const char **arg_val, enum yang_arg val_type, enum yang_keyword current_element)
+{
+    enum yin_argument arg = YIN_ARG_UNKNOWN;
+    struct yin_arg_record *iter = NULL;
+    bool found = false;
+
+    /* validation of attributes */
+    LY_ARRAY_FOR(attrs, struct yin_arg_record, iter) {
+        /* yin arguments represented as attributes have no namespace, which in this case means no prefix */
+        if (!iter->prefix) {
+            arg = yin_match_argument_name(iter->name, iter->name_len);
+            if (arg == YIN_ARG_NONE) {
+                continue;
+            } else if (arg == arg_type) {
+                LY_CHECK_ERR_RET(found, LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_DUP_ATTR,
+                                 yin_attr2str(arg), ly_stmt2str(current_element)), LY_EVALID);
+                found = true;
+                LY_CHECK_RET(yin_validate_value(ctx, val_type, iter->content, iter->content_len));
+                INSERT_STRING(ctx->xml_ctx.ctx, *arg_val, iter->dynamic_content, iter->content, iter->content_len);
+                iter->dynamic_content = 0;
+                LY_CHECK_RET(!(*arg_val), LY_EMEM);
+            } else {
+                LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_UNEXP_ATTR, iter->name_len, iter->name, ly_stmt2str(current_element));
+                return LY_EVALID;
+            }
+        }
+    }
+
+    /* anything else than Y_MAYBE_STR_ARG is mandatory */
+    if (val_type != Y_MAYBE_STR_ARG && !found) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LYVE_SYNTAX_YIN, "Missing mandatory attribute %s of %s element.", yin_attr2str(arg_type), ly_stmt2str(current_element));
+        return LY_EVALID;
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Get record with given type. Array must be sorted in ascending order by array[n].type.
+ *
+ * @param[in] type Type of wanted record.
+ * @param[in] array_size Size of array.
+ * @param[in] array Searched array.
+ *
+ * @return Pointer to desired record on success, NULL if element is not in the array.
+ */
+static struct yin_subelement *
+get_record(enum yang_keyword type, signed char array_size, struct yin_subelement *array)
+{
+    signed char left = 0, right = array_size - 1, middle;
+
+    while (left <= right) {
+        middle = left + (right - left) / 2;
+
+        if (array[middle].type == type) {
+            return &array[middle];
+        }
+
+        if (array[middle].type < type) {
+            left = middle + 1;
+        } else {
+            right = middle - 1;
+        }
+    }
+
+    return NULL;
+}
+
+/**
+ * @brief Helper function to check mandatory constraint of subelement.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] subelem_info Array of information about subelements.
+ * @param[in] subelem_info_size Size of subelem_info array.
+ * @param[in] current_element Identification of element that is currently being parsed, used for logging.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_check_subelem_mandatory_constraint(struct yin_parser_ctx *ctx, struct yin_subelement *subelem_info,
+                                       signed char subelem_info_size, enum yang_keyword current_element)
+{
+    for (signed char i = 0; i < subelem_info_size; ++i) {
+        /* if there is element that is mandatory and isn't parsed log error and return LY_EVALID */
+        if (subelem_info[i].flags & YIN_SUBELEM_MANDATORY && !(subelem_info[i].flags & YIN_SUBELEM_PARSED)) {
+            LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_MAND_SUBELEM,
+                          ly_stmt2str(subelem_info[i].type), ly_stmt2str(current_element));
+            return LY_EVALID;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Helper function to check "first" constraint of subelement.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] subelem_info Array of information about subelements.
+ * @param[in] subelem_info_size Size of subelem_info array.
+ * @param[in] current_element Identification of element that is currently being parsed, used for logging.
+ * @param[in] exp_first Record in subelem_info array that is expected to be defined as first subelement, used for logging.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_check_subelem_first_constraint(struct yin_parser_ctx *ctx, struct yin_subelement *subelem_info,
+                                   signed char subelem_info_size, enum yang_keyword current_element,
+                                   struct yin_subelement *exp_first)
+{
+    for (signed char i = 0; i < subelem_info_size; ++i) {
+        if (subelem_info[i].flags & YIN_SUBELEM_PARSED) {
+            LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_FIRT_SUBELEM,
+                           ly_stmt2str(exp_first->type), ly_stmt2str(current_element));
+            return LY_EVALID;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Helper function to check if array of information about subelements is in ascending order.
+ *
+ * @param[in] subelem_info Array of information about subelements.
+ * @param[in] subelem_info_size Size of subelem_info array.
+ *
+ * @return True iff subelem_info array is in ascending order, False otherwise.
+ */
+#ifndef NDEBUG
+static bool
+is_ordered(struct yin_subelement *subelem_info, signed char subelem_info_size)
+{
+    enum yang_keyword current = YANG_NONE; /* 0 (minimal value) */
+
+    for (signed char i = 0; i < subelem_info_size; ++i) {
+        if (subelem_info[i].type <= current) {
+            return false;
+        }
+        current = subelem_info[i].type;
+    }
+
+    return true;
+}
+#endif
+
+/**
+ * @brief Parse simple element without any special constraints and argument mapped to yin attribute,
+ * for example prefix or namespace element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] kw Type of current element.
+ * @param[out] value Where value of attribute should be stored.
+ * @param[in] arg_type Expected type of attribute.
+ * @param[in] arg_val_type Type of expected value of attribute.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_simple_element(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, enum yang_keyword kw,
+                         const char **value, enum yin_argument arg_type, enum yang_arg arg_val_type, struct lysp_ext_instance **exts)
+{
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, arg_type, value, arg_val_type, kw));
+    struct yin_subelement subelems[1] = {
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+
+    return yin_parse_content(ctx, subelems, 1, data, kw, NULL, exts);
+}
+
+/**
+ * @brief Parse path element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] kw Type of current element.
+ * @param[out] type Type structure to store parsed value, flags and extension instances.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_path(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, enum yang_keyword kw,
+               struct lysp_type *type)
+{
+    LY_CHECK_RET(yin_parse_simple_element(ctx, attrs, data, kw, &type->path,
+                                          YIN_ARG_VALUE, Y_STR_ARG, &type->exts));
+    type->flags |= LYS_SET_PATH;
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse pattern element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] type Type structure to store parsed value, flags and extension instances.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_pattern(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                  struct lysp_type *type)
+{
+    const char *real_value = NULL;
+    char *saved_value = NULL;
+    struct lysp_restr *restr;
+
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, type->patterns, restr, LY_EMEM);
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &real_value, Y_STR_ARG, YANG_PATTERN));
+    size_t len = strlen(real_value);
+
+    saved_value = malloc(len + 2);
+    LY_CHECK_ERR_RET(!saved_value, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+    memmove(saved_value + 1, real_value, len);
+    FREE_STRING(ctx->xml_ctx.ctx, real_value);
+    saved_value[0] = 0x06;
+    saved_value[len + 1] = '\0';
+    restr->arg = lydict_insert_zc(ctx->xml_ctx.ctx, saved_value);
+    LY_CHECK_ERR_RET(!restr->arg, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+    type->flags |= LYS_SET_PATTERN;
+
+    struct yin_subelement subelems[6] = {
+                                            {YANG_DESCRIPTION, &restr->dsc, YIN_SUBELEM_UNIQUE},
+                                            {YANG_ERROR_APP_TAG, &restr->eapptag, YIN_SUBELEM_UNIQUE},
+                                            {YANG_ERROR_MESSAGE, &restr->emsg, YIN_SUBELEM_UNIQUE},
+                                            {YANG_MODIFIER, &restr->arg, YIN_SUBELEM_UNIQUE},
+                                            {YANG_REFERENCE, &restr->ref, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+    return yin_parse_content(ctx, subelems, 6, data, YANG_PATTERN, NULL, &restr->exts);
+}
+
+/**
+ * @brief Parse fraction-digits element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] type Type structure to store value, flags and extension instances.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_fracdigits(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                     struct lysp_type *type)
+{
+    const char *temp_val = NULL;
+    char *ptr;
+    unsigned long int num;
+
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_FRACTION_DIGITS));
+
+    if (temp_val[0] == '\0' || (temp_val[0] == '0') || !isdigit(temp_val[0])) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", "fraction-digits");
+        FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+        return LY_EVALID;
+    }
+
+    errno = 0;
+    num = strtoul(temp_val, &ptr, 10);
+    if (*ptr != '\0') {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", "fraction-digits");
+        FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+        return LY_EVALID;
+    }
+    if ((errno == ERANGE) || (num > 18)) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", "fraction-digits");
+        FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+        return LY_EVALID;
+    }
+    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+    type->fraction_digits = num;
+    type->flags |= LYS_SET_FRDIGITS;
+    struct yin_subelement subelems[1] = {
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+    return yin_parse_content(ctx, subelems, 1, data, YANG_FRACTION_DIGITS, NULL, &type->exts);
+}
+
+/**
+ * @brief Parse enum element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] type Type structure to store parsed value, flags and extension instances.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_enum(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, struct lysp_type *type)
+{
+    struct lysp_type_enum *en;
+
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, type->enums, en, LY_EMEM);
+    type->flags |= LYS_SET_ENUM;
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &en->name, Y_IDENTIF_ARG, YANG_ENUM));
+    LY_CHECK_RET(lysp_check_enum_name((struct lys_parser_ctx *)ctx, en->name, strlen(en->name)));
+    YANG_CHECK_NONEMPTY((struct lys_parser_ctx *)ctx, strlen(en->name), "enum");
+    CHECK_UNIQUENESS((struct lys_parser_ctx *)ctx, type->enums, name, "enum", en->name);
+
+    struct yin_subelement subelems[6] = {
+                                            {YANG_DESCRIPTION, &en->dsc, YIN_SUBELEM_UNIQUE},
+                                            {YANG_IF_FEATURE, &en->iffeatures, 0},
+                                            {YANG_REFERENCE, &en->ref, YIN_SUBELEM_UNIQUE},
+                                            {YANG_STATUS, &en->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_VALUE, en, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+    return yin_parse_content(ctx, subelems, 6, data, YANG_ENUM, NULL, &en->exts);
+}
+
+/**
+ * @brief Parse bit element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] type Type structure to store parsed value, flags and extension instances.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_bit(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                   struct lysp_type *type)
+{
+    struct lysp_type_enum *en;
+
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, type->bits, en, LY_EMEM);
+    type->flags |= LYS_SET_BIT;
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &en->name, Y_IDENTIF_ARG, YANG_BIT));
+    CHECK_UNIQUENESS((struct lys_parser_ctx *)ctx, type->enums, name, "bit", en->name);
+
+    struct yin_subelement subelems[6] = {
+                                            {YANG_DESCRIPTION, &en->dsc, YIN_SUBELEM_UNIQUE},
+                                            {YANG_IF_FEATURE, &en->iffeatures, 0},
+                                            {YANG_POSITION, en, YIN_SUBELEM_UNIQUE},
+                                            {YANG_REFERENCE, &en->ref, YIN_SUBELEM_UNIQUE},
+                                            {YANG_STATUS, &en->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+    return yin_parse_content(ctx, subelems, 6, data, YANG_BIT, NULL, &en->exts);
+}
+
+/**
+ * @brief Parse simple element without any special constraints and argument mapped to yin attribute, that can have
+ * more instances, such as base or if-feature.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] kw Type of current element.
+ * @param[out] values Parsed values to add to.
+ * @param[in] arg_type Expected type of attribute.
+ * @param[in] arg_val_type Type of expected value of attribute.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_simple_elements(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, enum yang_keyword kw,
+                          const char ***values, enum yin_argument arg_type, enum yang_arg arg_val_type, struct lysp_ext_instance **exts)
+{
+    const char **value;
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *values, value, LY_EMEM);
+    uint32_t index = LY_ARRAY_SIZE(*values) - 1;
+    struct yin_subelement subelems[1] = {
+                                            {YANG_CUSTOM, &index, 0}
+                                        };
+
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, arg_type, value, arg_val_type, kw));
+
+    return yin_parse_content(ctx, subelems, 1, data, kw, NULL, exts);
+}
+
+/**
+ * @brief Parse simple element without any special constraints and argument mapped to yin attribute.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] kw Type of current element.
+ * @param[in] subinfo Information about subelement, is used to determin which function should be called and where to store parsed value.
+ * @param[in] arg_type Expected type of attribute.
+ * @param[in] arg_val_type Type of expected value of attribute.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_simple_elem(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, enum yang_keyword kw,
+                      struct yin_subelement *subinfo, enum yin_argument arg_type, enum yang_arg arg_val_type, struct lysp_ext_instance **exts)
+{
+    if (subinfo->flags & YIN_SUBELEM_UNIQUE) {
+        LY_CHECK_RET(yin_parse_simple_element(ctx, attrs, data, kw, (const char **)subinfo->dest,
+                                              arg_type, arg_val_type, exts));
+    } else {
+        LY_CHECK_RET(yin_parse_simple_elements(ctx, attrs, data, kw, (const char ***)subinfo->dest,
+                                               arg_type, arg_val_type, exts));
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse base element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] parent Identification of parent element.
+ * @param[out] dest Where parsed values should be stored.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_base(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, enum yang_keyword parent,
+               void *dest, struct lysp_ext_instance **exts)
+{
+    struct lysp_type *type = NULL;
+
+    if (parent == YANG_TYPE) {
+        type = (struct lysp_type *)dest;
+        LY_CHECK_RET(yin_parse_simple_elements(ctx, attrs, data, YANG_BASE, &type->bases, YIN_ARG_NAME,
+                                               Y_PREF_IDENTIF_ARG, exts));
+        type->flags |= LYS_SET_BASE;
+    } else if (parent == YANG_IDENTITY) {
+        LY_CHECK_RET(yin_parse_simple_elements(ctx, attrs, data, YANG_BASE, (const char ***)dest,
+                                               YIN_ARG_NAME, Y_PREF_IDENTIF_ARG, exts));
+    } else {
+        LOGINT(ctx->xml_ctx.ctx);
+        return LY_EINT;
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse require-instance element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @prama[out] type Type structure to store value, flag and extensions.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_pasrse_reqinstance(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs,
+                       const char **data,  struct lysp_type *type)
+{
+    const char *temp_val = NULL;
+    struct yin_subelement subelems[1] = {
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+
+    type->flags |= LYS_SET_REQINST;
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_REQUIRE_INSTANCE));
+    if (strcmp(temp_val, "true") == 0) {
+        type->require_instance = 1;
+    } else if (strcmp(temp_val, "false") != 0) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS2, temp_val, "value",
+                       "require-instance", "true", "false");
+        FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+        return LY_EVALID;
+    }
+    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+
+    return yin_parse_content(ctx, subelems, 1, data, YANG_REQUIRE_INSTANCE, NULL, &type->exts);
+}
+
+/**
+ * @brief Parse modifier element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] pat Value to write to.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_modifier(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                   const char **pat, struct lysp_ext_instance **exts)
+{
+    assert(**pat == 0x06);
+    const char *temp_val;
+    char *modified_val;
+    struct yin_subelement subelems[1] = {
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_MODIFIER));
+    if (strcmp(temp_val, "invert-match") != 0) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS1, temp_val, "value",
+                       "modifier", "invert-match");
+        FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+        return LY_EVALID;
+    }
+    lydict_remove(ctx->xml_ctx.ctx, temp_val);
+
+    /* allocate new value */
+    modified_val = malloc(strlen(*pat) + 1);
+    LY_CHECK_ERR_RET(!modified_val, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+    strcpy(modified_val, *pat);
+    lydict_remove(ctx->xml_ctx.ctx, *pat);
+
+    /* modify the new value */
+    modified_val[0] = 0x15;
+    *pat = lydict_insert_zc(ctx->xml_ctx.ctx, modified_val);
+
+    return yin_parse_content(ctx, subelems, 1, data, YANG_MODIFIER, NULL, exts);
+}
+
+/**
+ * @brief Parse a restriction element (length, range or one instance of must).
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] restr_kw Identificaton of element that is being parsed, can be set to YANG_MUST, YANG_LENGTH or YANG_RANGE.
+ * @param[in] restr Value to write to.
+ */
+static LY_ERR
+yin_parse_restriction(struct yin_parser_ctx *ctx,  struct yin_arg_record *attrs, const char **data,
+                      enum yang_keyword restr_kw, struct lysp_restr *restr)
+{
+    assert(restr_kw == YANG_MUST || restr_kw == YANG_LENGTH || restr_kw == YANG_RANGE);
+    struct yin_subelement subelems[5] = {
+                                            {YANG_DESCRIPTION, &restr->dsc, YIN_SUBELEM_UNIQUE},
+                                            {YANG_ERROR_APP_TAG, &restr->eapptag, YIN_SUBELEM_UNIQUE},
+                                            {YANG_ERROR_MESSAGE, &restr->emsg, YIN_SUBELEM_UNIQUE},
+                                            {YANG_REFERENCE, &restr->ref, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+    /* argument of must is called condition, but argument of length and range is called value */
+    enum yin_argument arg_type = (restr_kw == YANG_MUST) ? YIN_ARG_CONDITION : YIN_ARG_VALUE;
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, arg_type, &restr->arg, Y_STR_ARG, restr_kw));
+
+    return yin_parse_content(ctx, subelems, 5, data, restr_kw, NULL, &restr->exts);
+}
+
+/**
+ * @brief Parse range element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[out] type Type structure to store parsed value and flags.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_range(struct yin_parser_ctx *ctx,  struct yin_arg_record *attrs,
+                const char **data, struct lysp_type *type)
+{
+    type->range = calloc(1, sizeof *type->range);
+    LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+    LY_CHECK_RET(yin_parse_restriction(ctx, attrs, data, YANG_RANGE, type->range));
+    type->flags |=  LYS_SET_RANGE;
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse length element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[out] type Type structure to store parsed value and flags.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_length(struct yin_parser_ctx *ctx,  struct yin_arg_record *attrs,
+                const char **data, struct lysp_type *type)
+{
+    type->length = calloc(1, sizeof *type->length);
+    LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+    LY_CHECK_RET(yin_parse_restriction(ctx, attrs, data, YANG_LENGTH, type->length));
+    type->flags |= LYS_SET_LENGTH;
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse must element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] restrs Restrictions to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_must(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, struct lysp_restr **restrs)
+{
+    struct lysp_restr *restr;
+
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *restrs, restr, LY_EMEM);
+    return yin_parse_restriction(ctx, attrs, data, YANG_MUST, restr);
+}
+
+/**
+ * @brief Parse position or value element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] kw Type of current element, can be set to YANG_POSITION or YANG_VALUE.
+ * @param[out] enm Enum structure to save value, flags and extension instances.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_value_pos(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                            enum yang_keyword kw, struct lysp_type_enum *enm)
+{
+    assert(kw == YANG_POSITION || kw == YANG_VALUE);
+    const char *temp_val = NULL;
+    char *ptr;
+    long int num;
+    unsigned long int unum;
+
+    /* set value flag */
+    enm->flags |= LYS_SET_VALUE;
+
+    /* get attribute value */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, kw));
+    if (!temp_val || temp_val[0] == '\0' || (temp_val[0] == '+') ||
+        ((temp_val[0] == '0') && (temp_val[1] != '\0')) || ((kw == YANG_POSITION) && !strcmp(temp_val, "-0"))) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", ly_stmt2str(kw));
+        goto error;
+    }
+
+    /* convert value */
+    errno = 0;
+    if (kw == YANG_VALUE) {
+        num = strtol(temp_val, &ptr, 10);
+        if (num < INT64_C(-2147483648) || num > INT64_C(2147483647)) {
+            LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", ly_stmt2str(kw));
+            goto error;
+        }
+    } else {
+        unum = strtoul(temp_val, &ptr, 10);
+        if (unum > UINT64_C(4294967295)) {
+            LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", ly_stmt2str(kw));
+            goto error;
+        }
+    }
+    /* check if whole argument value was converted */
+    if (*ptr != '\0') {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", ly_stmt2str(kw));
+        goto error;
+    }
+    if (errno == ERANGE) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_OOB_YIN, temp_val, "value", ly_stmt2str(kw));
+        goto error;
+    }
+    /* save correctly ternary operator can't be used because num and unum have different signes */
+    if (kw == YANG_VALUE) {
+        enm->value = num;
+    } else {
+        enm->value = unum;
+    }
+    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+
+    /* parse subelements */
+    struct yin_subelement subelems[1] = {
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+    return yin_parse_content(ctx, subelems, 1, data, kw, NULL, &enm->exts);
+
+error:
+        FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+        return LY_EVALID;
+}
+
+
+/**
+ * @brief Parse belongs-to element.
+ *
+ * @param[in] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[out] submod Structure of submodule that is being parsed.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values
+ */
+static LY_ERR
+yin_parse_belongs_to(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                     struct lysp_submodule *submod, struct lysp_ext_instance **exts)
+{
+    struct yin_subelement subelems[2] = {
+                                            {YANG_PREFIX, &submod->prefix, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_MODULE, &submod->belongsto, Y_IDENTIF_ARG, YANG_BELONGS_TO));
+
+    return yin_parse_content(ctx, subelems, 2, data, YANG_BELONGS_TO, NULL, exts);
+}
+
+/**
+ * @brief Function to parse meta tags (description, contact, ...) eg. elements with
+ * text element as child.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] elem_type Type of element can be set to YANG_ORGANIZATION or YANG_CONTACT or YANG_DESCRIPTION or YANG_REFERENCE.
+ * @param[out] value Where the content of meta element should be stored.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_meta(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                       enum yang_keyword elem_type, const char **value, struct lysp_ext_instance **exts)
+{
+    assert(elem_type == YANG_ORGANIZATION || elem_type == YANG_CONTACT || elem_type == YANG_DESCRIPTION || elem_type == YANG_REFERENCE);
+
+    struct yin_subelement subelems[2] = {
+                                            {YANG_CUSTOM, NULL, 0},
+                                            {YIN_TEXT, value, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE | YIN_SUBELEM_FIRST}
+                                        };
+    /* check attributes */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NONE, NULL, Y_MAYBE_STR_ARG, elem_type));
+
+    /* parse content */
+    return yin_parse_content(ctx, subelems, 2, data, elem_type, NULL, exts);
+}
+
+/**
+ * @brief Parse error-message element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from.
+ * @param[out] value Where the content of error-message element should be stored.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_err_msg(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                          const char **value, struct lysp_ext_instance **exts)
+{
+    struct yin_subelement subelems[2] = {
+                                            {YANG_CUSTOM, NULL, 0},
+                                            {YIN_VALUE, value, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE | YIN_SUBELEM_FIRST}
+                                        };
+
+    /* check attributes */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NONE, NULL, Y_MAYBE_STR_ARG, YANG_ERROR_MESSAGE));
+
+    return yin_parse_content(ctx, subelems, 2, data, YANG_ERROR_MESSAGE, NULL, exts);
+}
+
+/**
+ * @brief Parse type element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] parent Identification of parent element.
+ * @param[in,out] type Type to write to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_type(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+               enum yang_keyword parent, struct yin_subelement *subinfo)
+{
+    struct lysp_type *type = NULL;
+    if (parent == YANG_DEVIATE) {
+        *(struct lysp_type **)subinfo->dest = calloc(1, sizeof **(struct lysp_type **)subinfo->dest);
+        LY_CHECK_ERR_RET(!(*(struct lysp_type **)subinfo->dest), LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+        type = *((struct lysp_type **)subinfo->dest);
+    } else  {
+        type = (struct lysp_type *)subinfo->dest;
+    }
+    /* type as child of another type */
+    if (parent == YANG_TYPE) {
+        struct lysp_type *nested_type = NULL;
+        LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, type->types, nested_type, LY_EMEM);
+        type->flags |= LYS_SET_TYPE;
+        type = nested_type;
+    }
+    struct yin_subelement subelems[11] = {
+                                            {YANG_BASE, type, 0},
+                                            {YANG_BIT, type, 0},
+                                            {YANG_ENUM, type, 0},
+                                            {YANG_FRACTION_DIGITS, type, YIN_SUBELEM_UNIQUE},
+                                            {YANG_LENGTH, type, YIN_SUBELEM_UNIQUE},
+                                            {YANG_PATH, type, YIN_SUBELEM_UNIQUE},
+                                            {YANG_PATTERN, type, 0},
+                                            {YANG_RANGE, type, YIN_SUBELEM_UNIQUE},
+                                            {YANG_REQUIRE_INSTANCE, type, YIN_SUBELEM_UNIQUE},
+                                            {YANG_TYPE, type},
+                                            {YANG_CUSTOM, NULL, 0},
+                                        };
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &type->name, Y_PREF_IDENTIF_ARG, YANG_TYPE));
+    return yin_parse_content(ctx, subelems, 11, data, YANG_TYPE, NULL, &type->exts);
+}
+
+/**
+ * @brief Parse max-elements element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] max Value to write to.
+ * @param[in] flags Flags to write to.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_maxelements(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, uint32_t *max,
+                      uint16_t *flags, struct lysp_ext_instance **exts)
+{
+    const char *temp_val = NULL;
+    char *ptr;
+    unsigned long int num;
+    struct yin_subelement subelems[1] = {
+                                            {YANG_CUSTOM, NULL, 0},
+                                        };
+
+    *flags |= LYS_SET_MAX;
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_MAX_ELEMENTS));
+    if (!temp_val || temp_val[0] == '\0' || temp_val[0] == '0' || (temp_val[0] != 'u' && !isdigit(temp_val[0]))) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", "max-elements");
+        FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+        return LY_EVALID;
+    }
+
+    if (strcmp(temp_val, "unbounded")) {
+        errno = 0;
+        num = strtoul(temp_val, &ptr, 10);
+        if (*ptr != '\0') {
+            LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", "max-elements");
+            FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+            return LY_EVALID;
+        }
+        if ((errno == ERANGE) || (num > UINT32_MAX)) {
+            LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_OOB_YIN, temp_val, "value", "max-elements");
+            FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+            return LY_EVALID;
+        }
+        *max = num;
+    }
+    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+    return yin_parse_content(ctx, subelems, 1, data, YANG_MAX_ELEMENTS, NULL, exts);
+}
+
+/**
+ * @brief Parse min-elements element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] min Value to write to.
+ * @param[in] flags Flags to write to.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_minelements(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, uint32_t *min,
+                      uint16_t *flags, struct lysp_ext_instance **exts)
+{
+    const char *temp_val = NULL;
+    char *ptr;
+    unsigned long int num;
+    struct yin_subelement subelems[1] = {
+                                            {YANG_CUSTOM, NULL, 0},
+                                        };
+
+    *flags |= LYS_SET_MIN;
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_MIN_ELEMENTS));
+
+    if (!temp_val || temp_val[0] == '\0' || (temp_val[0] == '0' && temp_val[1] != '\0')) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", "min-elements");
+        FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+        return LY_EVALID;
+    }
+
+    errno = 0;
+    num = strtoul(temp_val, &ptr, 10);
+    if (ptr[0] != 0) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", "min-elements");
+        FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+        return LY_EVALID;
+    }
+    if (errno == ERANGE || num > UINT32_MAX) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_OOB_YIN, temp_val, "value", "min-elements");
+        FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+        return LY_EVALID;
+    }
+    *min = num;
+    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+    return yin_parse_content(ctx, subelems, 1, data, YANG_MIN_ELEMENTS, NULL, exts);
+}
+
+/**
+ * @brief Parse min-elements or max-elements element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] parent Identification of parent element.
+ * @param[in] current Identification of current element.
+ * @param[in] dest Where the parsed value and flags should be stored.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_minmax(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                 enum yang_keyword parent, enum yang_keyword current, void *dest)
+{
+    assert(current == YANG_MAX_ELEMENTS || current == YANG_MIN_ELEMENTS);
+    assert(parent == YANG_LEAF_LIST || parent == YANG_REFINE || parent == YANG_LIST || parent == YANG_DEVIATE);
+    uint32_t *lim;
+    uint16_t *flags;
+    struct lysp_ext_instance **exts;
+
+    if (parent == YANG_LEAF_LIST) {
+        lim = (current == YANG_MAX_ELEMENTS) ? &((struct lysp_node_leaflist *)dest)->max : &((struct lysp_node_leaflist *)dest)->min;
+        flags = &((struct lysp_node_leaflist *)dest)->flags;
+        exts = &((struct lysp_node_leaflist *)dest)->exts;
+    } else if (parent == YANG_REFINE) {
+        lim = (current == YANG_MAX_ELEMENTS) ? &((struct lysp_refine *)dest)->max : &((struct lysp_refine *)dest)->min;
+        flags = &((struct lysp_refine *)dest)->flags;
+        exts = &((struct lysp_refine *)dest)->exts;
+    } else if (parent == YANG_LIST) {
+        lim = (current == YANG_MAX_ELEMENTS) ? &((struct lysp_node_list *)dest)->max : &((struct lysp_node_list *)dest)->min;
+        flags = &((struct lysp_node_list *)dest)->flags;
+        exts = &((struct lysp_node_list *)dest)->exts;
+    } else {
+        lim = ((struct minmax_dev_meta *)dest)->lim;
+        flags = ((struct minmax_dev_meta *)dest)->flags;
+        exts = ((struct minmax_dev_meta *)dest)->exts;
+    }
+
+    if (current == YANG_MAX_ELEMENTS) {
+        LY_CHECK_RET(yin_parse_maxelements(ctx, attrs, data, lim, flags, exts));
+    } else {
+        LY_CHECK_RET(yin_parse_minelements(ctx, attrs, data, lim, flags, exts));
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse ordered-by element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[out] flags Flags to write to.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_orderedby(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                    uint16_t *flags, struct lysp_ext_instance **exts)
+{
+    const char *temp_val;
+    struct yin_subelement subelems[1] = {
+                                            {YANG_CUSTOM, NULL, 0},
+                                        };
+
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_ORDERED_BY));
+    if (strcmp(temp_val, "system") == 0) {
+        *flags |= LYS_ORDBY_SYSTEM;
+    } else if (strcmp(temp_val, "user") == 0) {
+        *flags |= LYS_ORDBY_USER;
+    } else {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS2, temp_val, "value",
+                       "ordered-by", "system", "user");
+        FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+        return LY_EVALID;
+    }
+    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+
+    return yin_parse_content(ctx, subelems, 1, data, YANG_ORDERED_BY, NULL, exts);
+}
+
+/**
+ * @brief Parse any-data or any-xml element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] any_kw Identification of current element, can be set to YANG_ANY_DATA or YANG_ANY_XML
+ * @param[in] node_meta Meta information about parent node and siblings to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_any(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+              enum yang_keyword any_kw, struct tree_node_meta *node_meta)
+{
+    struct lysp_node_anydata *any;
+
+    /* create new sibling */
+    LY_LIST_NEW_RET(ctx->xml_ctx.ctx, node_meta->nodes, any, next);
+    any->nodetype = (any_kw == YANG_ANYDATA) ? LYS_ANYDATA : LYS_ANYXML;
+    any->parent = node_meta->parent;
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &any->name, Y_IDENTIF_ARG, any_kw));
+
+    struct yin_subelement subelems[9] = {
+                                            {YANG_CONFIG, &any->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_DESCRIPTION, &any->dsc, YIN_SUBELEM_UNIQUE},
+                                            {YANG_IF_FEATURE, &any->iffeatures, 0},
+                                            {YANG_MANDATORY, &any->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_MUST, &any->musts, 0},
+                                            {YANG_REFERENCE, &any->ref, YIN_SUBELEM_UNIQUE},
+                                            {YANG_STATUS, &any->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_WHEN, &any->when, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0},
+                                        };
+    return yin_parse_content(ctx, subelems, 9, data, any_kw, NULL, &any->exts);
+}
+
+/**
+ * @brief parse leaf element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] node_meta Meta information about parent node and siblings to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_leaf(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+               struct tree_node_meta *node_meta)
+{
+    struct lysp_node_leaf *leaf;
+
+    /* create structure new leaf */
+    LY_LIST_NEW_RET(ctx->xml_ctx.ctx, node_meta->nodes, leaf, next);
+    leaf->nodetype = LYS_LEAF;
+    leaf->parent = node_meta->parent;
+
+    /* parser argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &leaf->name, Y_IDENTIF_ARG, YANG_LEAF));
+
+    /* parse content */
+    struct yin_subelement subelems[12] = {
+                                            {YANG_CONFIG, &leaf->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_DEFAULT, &leaf->dflt, YIN_SUBELEM_UNIQUE},
+                                            {YANG_DESCRIPTION, &leaf->dsc, YIN_SUBELEM_UNIQUE},
+                                            {YANG_IF_FEATURE, &leaf->iffeatures, 0},
+                                            {YANG_MANDATORY, &leaf->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_MUST, &leaf->musts, 0},
+                                            {YANG_REFERENCE, &leaf->ref, YIN_SUBELEM_UNIQUE},
+                                            {YANG_STATUS, &leaf->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_TYPE, &leaf->type, YIN_SUBELEM_UNIQUE | YIN_SUBELEM_MANDATORY},
+                                            {YANG_UNITS, &leaf->units, YIN_SUBELEM_UNIQUE},
+                                            {YANG_WHEN, &leaf->when, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0},
+                                         };
+    return yin_parse_content(ctx, subelems, 12, data, YANG_LEAF, NULL, &leaf->exts);
+}
+
+/**
+ * @brief Parse leaf-list element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] node_meta Meta information about parent node and siblings to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_leaflist(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                   struct tree_node_meta *node_meta)
+{
+    struct lysp_node_leaflist *llist;
+
+    LY_LIST_NEW_RET(ctx->xml_ctx.ctx, node_meta->nodes, llist, next);
+
+    llist->nodetype = LYS_LEAFLIST;
+    llist->parent = node_meta->parent;
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &llist->name, Y_IDENTIF_ARG, YANG_LEAF_LIST));
+
+    /* parse content */
+    struct yin_subelement subelems[14] = {
+                                            {YANG_CONFIG, &llist->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_DEFAULT, &llist->dflts, 0},
+                                            {YANG_DESCRIPTION, &llist->dsc, YIN_SUBELEM_UNIQUE},
+                                            {YANG_IF_FEATURE, &llist->iffeatures, 0},
+                                            {YANG_MAX_ELEMENTS, llist, YIN_SUBELEM_UNIQUE},
+                                            {YANG_MIN_ELEMENTS, llist, YIN_SUBELEM_UNIQUE},
+                                            {YANG_MUST, &llist->musts, 0},
+                                            {YANG_ORDERED_BY, &llist->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_REFERENCE, &llist->ref, YIN_SUBELEM_UNIQUE},
+                                            {YANG_STATUS, &llist->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_TYPE, &llist->type, YIN_SUBELEM_UNIQUE | YIN_SUBELEM_MANDATORY},
+                                            {YANG_UNITS, &llist->units, YIN_SUBELEM_UNIQUE},
+                                            {YANG_WHEN, &llist->when, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0},
+                                        };
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, 14, data, YANG_LEAF_LIST, NULL, &llist->exts));
+
+    /* check invalid combination of subelements */
+    if ((llist->min) && (llist->dflts)) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INCHILDSTMSCOMB_YIN, "min-elements", "default", "leaf-list");
+        return LY_EVALID;
+    }
+    if (llist->max && llist->min > llist->max) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_MINMAX, llist->min, llist->max);
+        return LY_EVALID;
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse typedef element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] typedef_meta Meta information about parent node and typedefs to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_typedef(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                  struct tree_node_meta *typedef_meta)
+{
+    struct lysp_tpdf *tpdf;
+    struct lysp_tpdf **tpdfs = (struct lysp_tpdf **)typedef_meta->nodes;
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *tpdfs, tpdf, LY_EMEM);
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &tpdf->name, Y_IDENTIF_ARG, YANG_TYPEDEF));
+
+    /* parse content */
+    struct yin_subelement subelems[7] = {
+                                            {YANG_DEFAULT, &tpdf->dflt, YIN_SUBELEM_UNIQUE},
+                                            {YANG_DESCRIPTION, &tpdf->dsc, YIN_SUBELEM_UNIQUE},
+                                            {YANG_REFERENCE, &tpdf->ref, YIN_SUBELEM_UNIQUE},
+                                            {YANG_STATUS, &tpdf->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_TYPE, &tpdf->type, YIN_SUBELEM_UNIQUE | YIN_SUBELEM_MANDATORY},
+                                            {YANG_UNITS, &tpdf->units, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0},
+                                        };
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, 7, data, YANG_TYPEDEF, NULL, &tpdf->exts));
+
+    /* store data for collision check */
+    if (typedef_meta->parent && !(typedef_meta->parent->nodetype & (LYS_GROUPING | LYS_ACTION | LYS_INOUT | LYS_NOTIF))) {
+        LY_CHECK_RET(ly_set_add(&ctx->tpdfs_nodes, typedef_meta->parent, 0) == -1, LY_EMEM);
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse refine element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] refines Refines to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_refine(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                 struct lysp_refine **refines)
+{
+    struct lysp_refine *rf;
+
+    /* allocate new refine */
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *refines, rf, LY_EMEM);
+
+    /* parse attribute */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_TARGET_NODE, &rf->nodeid, Y_STR_ARG, YANG_REFINE));
+    YANG_CHECK_NONEMPTY((struct lys_parser_ctx *)ctx, strlen(rf->nodeid), "refine");
+
+    /* parse content */
+    struct yin_subelement subelems[11] = {
+                                            {YANG_CONFIG, &rf->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_DEFAULT, &rf->dflts, 0},
+                                            {YANG_DESCRIPTION, &rf->dsc, YIN_SUBELEM_UNIQUE},
+                                            {YANG_IF_FEATURE, &rf->iffeatures, 0},
+                                            {YANG_MANDATORY, &rf->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_MAX_ELEMENTS, rf, YIN_SUBELEM_UNIQUE},
+                                            {YANG_MIN_ELEMENTS, rf, YIN_SUBELEM_UNIQUE},
+                                            {YANG_MUST, &rf->musts, 0},
+                                            {YANG_PRESENCE, &rf->presence, YIN_SUBELEM_UNIQUE},
+                                            {YANG_REFERENCE, &rf->ref, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0},
+                                        };
+    return yin_parse_content(ctx, subelems, 11, data, YANG_REFINE, NULL, &rf->exts);
+}
+
+/**
+ * @brief Parse uses element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] node_meta Meta information about parent node and siblings to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_uses(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+               struct tree_node_meta *node_meta)
+{
+    struct lysp_node_uses *uses;
+
+    /* create new uses */
+    LY_LIST_NEW_RET(ctx->xml_ctx.ctx, node_meta->nodes, uses, next);
+    uses->nodetype = LYS_USES;
+    uses->parent = node_meta->parent;
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &uses->name, Y_PREF_IDENTIF_ARG, YANG_USES));
+
+    /* parse content */
+    struct tree_node_meta augments = {(struct lysp_node *)uses, (struct lysp_node **)&uses->augments};
+    struct yin_subelement subelems[8] = {
+                                            {YANG_AUGMENT, &augments, 0},
+                                            {YANG_DESCRIPTION, &uses->dsc, YIN_SUBELEM_UNIQUE},
+                                            {YANG_IF_FEATURE, &uses->iffeatures, 0},
+                                            {YANG_REFERENCE, &uses->ref, YIN_SUBELEM_UNIQUE},
+                                            {YANG_REFINE, &uses->refines, 0},
+                                            {YANG_STATUS, &uses->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_WHEN, &uses->when, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0},
+                                        };
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, 8, data, YANG_USES, NULL, &uses->exts));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, NULL, uses->augments, NULL, NULL));
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse revision element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] revs Parsed revisions to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_revision(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                   struct lysp_revision **revs)
+{
+    struct lysp_revision *rev;
+    const char *temp_date = NULL;
+
+    /* allocate new reivison */
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *revs, rev, LY_EMEM);
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_DATE, &temp_date, Y_STR_ARG, YANG_REVISION));
+    /* check value */
+    if (lysp_check_date((struct lys_parser_ctx *)ctx, temp_date, strlen(temp_date), "revision")) {
+        FREE_STRING(ctx->xml_ctx.ctx, temp_date);
+        return LY_EVALID;
+    }
+    strcpy(rev->date, temp_date);
+    FREE_STRING(ctx->xml_ctx.ctx, temp_date);
+
+    /* parse content */
+    struct yin_subelement subelems[3] = {
+                                            {YANG_DESCRIPTION, &rev->dsc, YIN_SUBELEM_UNIQUE},
+                                            {YANG_REFERENCE, &rev->ref, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0},
+                                        };
+    return yin_parse_content(ctx, subelems, 3, data, YANG_REVISION, NULL, &rev->exts);
+}
+
+/**
+ * @brief Parse include element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] inc_meta Meta informatinou about module/submodule name and includes to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_include(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                  struct include_meta *inc_meta)
+{
+    struct lysp_include *inc;
+
+    /* allocate new include */
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *inc_meta->includes, inc, LY_EMEM);
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_MODULE, &inc->name, Y_IDENTIF_ARG, YANG_INCLUDE));
+
+    /* submodules share the namespace with the module names, so there must not be
+     * a module of the same name in the context, no need for revision matching */
+    if (!strcmp(inc_meta->name, inc->name) || ly_ctx_get_module_latest(ctx->xml_ctx.ctx, inc->name)) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_NAME_COL, inc->name);
+        return LY_EVALID;
+    }
+
+    /* parse content */
+    struct yin_subelement subelems[4] = {
+                                            {YANG_DESCRIPTION, &inc->dsc, YIN_SUBELEM_UNIQUE | YIN_SUBELEM_VER2},
+                                            {YANG_REFERENCE, &inc->ref, YIN_SUBELEM_UNIQUE | YIN_SUBELEM_VER2},
+                                            {YANG_REVISION_DATE, &inc->rev, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0},
+                                        };
+    return yin_parse_content(ctx, subelems, 4, data, YANG_INCLUDE, NULL, &inc->exts);
+}
+
+/**
+ * @brief Parse revision-date element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of revision-date element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] rev Array to store the parsed value in.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_revision_date(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, char *rev,
+                        struct lysp_ext_instance **exts)
+{
+    const char *temp_rev;
+    struct yin_subelement subelems[1] = {
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_DATE, &temp_rev, Y_STR_ARG, YANG_REVISION_DATE));
+    LY_CHECK_ERR_RET(lysp_check_date((struct lys_parser_ctx *)ctx, temp_rev, strlen(temp_rev), "revision-date") != LY_SUCCESS,
+                     FREE_STRING(ctx->xml_ctx.ctx, temp_rev), LY_EVALID);
+
+    strcpy(rev, temp_rev);
+    FREE_STRING(ctx->xml_ctx.ctx, temp_rev);
+
+    return yin_parse_content(ctx, subelems, 1, data, YANG_REVISION_DATE, NULL, exts);
+}
+
+/**
+ * @brief Parse config element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of import element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] flags Flags to add to.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_config(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, uint16_t *flags,
+                 struct lysp_ext_instance **exts)
+{
+    const char *temp_val = NULL;
+    struct yin_subelement subelems[1] = {
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_CONFIG));
+    if (strcmp(temp_val, "true") == 0) {
+        *flags |= LYS_CONFIG_W;
+    } else if (strcmp(temp_val, "false") == 0) {
+        *flags |= LYS_CONFIG_R;
+    } else {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS2, temp_val, "value", "config",
+                       "true", "false");
+        FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+        return LY_EVALID;
+    }
+    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+
+    return yin_parse_content(ctx, subelems, 1, data, YANG_CONFIG, NULL, exts);
+}
+
+/**
+ * @brief Parse yang-version element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of yang-version element.
+ * @param[in] data Data to read from, always moved to currently handled character.
+ * @param[out] version Storage for the parsed information.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_yangversion(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, uint8_t *version,
+                      struct lysp_ext_instance **exts)
+{
+    const char *temp_version = NULL;
+    struct yin_subelement subelems[1] = {
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_version, Y_STR_ARG, YANG_YANG_VERSION));
+    if (strcmp(temp_version, "1.0") == 0) {
+        *version = LYS_VERSION_1_0;
+    } else if (strcmp(temp_version, "1.1") == 0) {
+        *version = LYS_VERSION_1_1;
+    } else {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS2, temp_version, "value",
+                       "yang-version", "1.0", "1.1");
+        FREE_STRING(ctx->xml_ctx.ctx, temp_version);
+        return LY_EVALID;
+    }
+    FREE_STRING(ctx->xml_ctx.ctx, temp_version);
+    ctx->mod_version = *version;
+
+    return yin_parse_content(ctx, subelems, 1, data, YANG_YANG_VERSION, NULL, exts);
+}
+
+/**
+ * @brief Parse import element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of import element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] imp_meta Meta information about prefix and imports to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_import(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, struct import_meta *imp_meta)
+{
+    struct lysp_import *imp;
+    /* allocate new element in sized array for import */
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *imp_meta->imports, imp, LY_EMEM);
+
+    struct yin_subelement subelems[5] = {
+                                            {YANG_DESCRIPTION, &imp->dsc, YIN_SUBELEM_UNIQUE},
+                                            {YANG_PREFIX, &imp->prefix, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE},
+                                            {YANG_REFERENCE, &imp->ref, YIN_SUBELEM_UNIQUE},
+                                            {YANG_REVISION_DATE, imp->rev, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+
+    /* parse import attributes */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_MODULE, &imp->name, Y_IDENTIF_ARG, YANG_IMPORT));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, 5, data, YANG_IMPORT, NULL, &imp->exts));
+    /* check prefix validity */
+    LY_CHECK_RET(lysp_check_prefix((struct lys_parser_ctx *)ctx, *imp_meta->imports, imp_meta->prefix, &imp->prefix), LY_EVALID);
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse mandatory element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of status element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] flags Flags to add to.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_mandatory(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, uint16_t *flags,
+                    struct lysp_ext_instance **exts)
+{
+    const char *temp_val = NULL;
+    struct yin_subelement subelems[1] = {
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_MANDATORY));
+    if (strcmp(temp_val, "true") == 0) {
+        *flags |= LYS_MAND_TRUE;
+    } else if (strcmp(temp_val, "false") == 0) {
+        *flags |= LYS_MAND_FALSE;
+    } else {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS2, temp_val, "value",
+                       "mandatory", "true", "false");
+        FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+        return LY_EVALID;
+    }
+    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+
+    return yin_parse_content(ctx, subelems, 1, data, YANG_MANDATORY, NULL, exts);
+}
+
+/**
+ * @brief Parse status element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of status element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] flags Flags to add to.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_status(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, uint16_t *flags,
+                 struct lysp_ext_instance **exts)
+{
+    const char *value = NULL;
+    struct yin_subelement subelems[1] = {
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &value, Y_STR_ARG, YANG_STATUS));
+    if (strcmp(value, "current") == 0) {
+        *flags |= LYS_STATUS_CURR;
+    } else if (strcmp(value, "deprecated") == 0) {
+        *flags |= LYS_STATUS_DEPRC;
+    } else if (strcmp(value, "obsolete") == 0) {
+        *flags |= LYS_STATUS_OBSLT;
+    } else {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS3, value, "value",
+                       "status", "current", "deprecated", "obsolete");
+        FREE_STRING(ctx->xml_ctx.ctx, value);
+        return LY_EVALID;
+    }
+    FREE_STRING(ctx->xml_ctx.ctx, value);
+
+    return yin_parse_content(ctx, subelems, 1, data, YANG_STATUS, NULL, exts);
+}
+
+/**
+ * @brief Parse when element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of when element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[out] when_p When pointer to parse to.
+ */
+static LY_ERR
+yin_parse_when(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, struct lysp_when **when_p)
+{
+    struct lysp_when *when;
+    LY_ERR ret = LY_SUCCESS;
+
+    when = calloc(1, sizeof *when);
+    LY_CHECK_ERR_RET(!when, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+    ret = yin_parse_attribute(ctx, attrs, YIN_ARG_CONDITION, &when->cond, Y_STR_ARG, YANG_WHEN);
+    LY_CHECK_ERR_RET(ret, free(when), ret);
+
+    *when_p = when;
+    struct yin_subelement subelems[3] = {
+                                            {YANG_DESCRIPTION, &when->dsc, YIN_SUBELEM_UNIQUE},
+                                            {YANG_REFERENCE, &when->ref, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+
+    return yin_parse_content(ctx, subelems, 3, data, YANG_WHEN, NULL, &when->exts);
+}
+
+/**
+ * @brief Parse yin-elemenet element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of yin-element element.
+ * @param[in,out] data Data to read from, always moved to currently handled position.
+ * @param[in,out] flags Flags to add to.
+ * @prama[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_yin_element(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                              uint16_t *flags, struct lysp_ext_instance **exts)
+{
+    const char *temp_val = NULL;
+    struct yin_subelement subelems[1] = {
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_YIN_ELEMENT));
+    if (strcmp(temp_val, "true") == 0) {
+        *flags |= LYS_YINELEM_TRUE;
+    } else if (strcmp(temp_val, "false") == 0) {
+        *flags |= LYS_YINELEM_FALSE;
+    } else {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS2, temp_val, "value",
+                       "yin-element", "true", "false");
+        FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+        return LY_EVALID;
+    }
+    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+
+    return yin_parse_content(ctx, subelems, 1, data, YANG_YIN_ELEMENT, NULL, exts);
+}
+
+/**
+ * @brief Parse argument element.
+ *
+ * @param[in,out] xml_ctx Xml context.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of argument element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] arg_meta Meta information about destionation of parsed data.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_argument(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                           struct yin_argument_meta *arg_meta, struct lysp_ext_instance **exts)
+{
+    struct yin_subelement subelems[2] = {
+                                            {YANG_YIN_ELEMENT, arg_meta->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, arg_meta->argument, Y_IDENTIF_ARG, YANG_ARGUMENT));
+
+    return yin_parse_content(ctx, subelems, 2, data, YANG_ARGUMENT, NULL, exts);
+}
+
+/**
+ * @brief Parse the extension statement.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of extension element.
+ * @param[in,out] data Data to read from.
+ * @param[in,out] extensions Extensions to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_extension(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, struct lysp_ext **extensions)
+{
+    struct lysp_ext *ex;
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *extensions, ex, LY_EMEM);
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &ex->name, Y_IDENTIF_ARG, YANG_EXTENSION));
+
+    struct yin_argument_meta arg_info = {&ex->flags, &ex->argument};
+    struct yin_subelement subelems[5] = {
+                                            {YANG_ARGUMENT, &arg_info, YIN_SUBELEM_UNIQUE},
+                                            {YANG_DESCRIPTION, &ex->dsc, YIN_SUBELEM_UNIQUE},
+                                            {YANG_REFERENCE, &ex->ref, YIN_SUBELEM_UNIQUE},
+                                            {YANG_STATUS, &ex->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0}
+                                        };
+
+    return yin_parse_content(ctx, subelems, 5, data, YANG_EXTENSION, NULL, &ex->exts);
+}
+
+/**
+ * @brief Parse feature element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] features Features to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_feature(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                  struct lysp_feature **features)
+{
+    struct lysp_feature *feat;
+
+    /* allocate new feature */
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *features, feat, LY_EMEM);
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &feat->name, Y_IDENTIF_ARG, YANG_FEATURE));
+
+    /* parse content */
+    struct yin_subelement subelems[5] = {
+                                            {YANG_DESCRIPTION, &feat->dsc, YIN_SUBELEM_UNIQUE},
+                                            {YANG_IF_FEATURE, &feat->iffeatures, 0},
+                                            {YANG_REFERENCE, &feat->ref, YIN_SUBELEM_UNIQUE},
+                                            {YANG_STATUS, &feat->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0},
+                                        };
+    return yin_parse_content(ctx, subelems, 5, data, YANG_FEATURE, NULL, &feat->exts);
+}
+
+/**
+ * @brief Parse identity element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] identities Identities to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_identity(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                   struct lysp_ident **identities)
+{
+    struct lysp_ident *ident;
+
+    /* allocate new identity */
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *identities, ident, LY_EMEM);
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &ident->name, Y_IDENTIF_ARG, YANG_IDENTITY));
+
+    /* parse content */
+    struct yin_subelement subelems[6] = {
+                                            {YANG_BASE, &ident->bases, 0},
+                                            {YANG_DESCRIPTION, &ident->dsc, YIN_SUBELEM_UNIQUE},
+                                            {YANG_IF_FEATURE, &ident->iffeatures, YIN_SUBELEM_VER2},
+                                            {YANG_REFERENCE, &ident->ref, YIN_SUBELEM_UNIQUE},
+                                            {YANG_STATUS, &ident->flags, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0},
+                                        };
+    return yin_parse_content(ctx, subelems, 6, data, YANG_IDENTITY, NULL, &ident->exts);
+}
+
+/**
+ * @brief Parse list element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] node_meta Meta information about parent node and siblings to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_list(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+               struct tree_node_meta *node_meta)
+{
+    struct lysp_node_list *list;
+    LY_ERR ret = LY_SUCCESS;
+    struct yin_subelement *subelems = NULL;
+
+    LY_LIST_NEW_RET(ctx->xml_ctx.ctx, node_meta->nodes, list, next);
+    list->nodetype = LYS_LIST;
+    list->parent = node_meta->parent;
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &list->name, Y_IDENTIF_ARG, YANG_LIST));
+
+    /* parse list content */
+    LY_CHECK_RET(subelems_allocator(ctx, 25, (struct lysp_node *)list, &subelems,
+                                        YANG_ACTION, &list->actions, 0,
+                                        YANG_ANYDATA, &list->child, 0,
+                                        YANG_ANYXML, &list->child, 0,
+                                        YANG_CHOICE, &list->child, 0,
+                                        YANG_CONFIG, &list->flags, YIN_SUBELEM_UNIQUE,
+                                        YANG_CONTAINER, &list->child, 0,
+                                        YANG_DESCRIPTION, &list->dsc, YIN_SUBELEM_UNIQUE,
+                                        YANG_GROUPING, &list->groupings, 0,
+                                        YANG_IF_FEATURE, &list->iffeatures, 0,
+                                        YANG_KEY, &list->key, YIN_SUBELEM_UNIQUE,
+                                        YANG_LEAF, &list->child, 0,
+                                        YANG_LEAF_LIST, &list->child, 0,
+                                        YANG_LIST, &list->child, 0,
+                                        YANG_MAX_ELEMENTS, list, YIN_SUBELEM_UNIQUE,
+                                        YANG_MIN_ELEMENTS, list, YIN_SUBELEM_UNIQUE,
+                                        YANG_MUST, &list->musts, 0,
+                                        YANG_NOTIFICATION, &list->notifs, 0,
+                                        YANG_ORDERED_BY, &list->flags, YIN_SUBELEM_UNIQUE,
+                                        YANG_REFERENCE, &list->ref, YIN_SUBELEM_UNIQUE,
+                                        YANG_STATUS, &list->flags, YIN_SUBELEM_UNIQUE,
+                                        YANG_TYPEDEF, &list->typedefs, 0,
+                                        YANG_UNIQUE, &list->uniques, 0,
+                                        YANG_USES, &list->child, 0,
+                                        YANG_WHEN, &list->when, YIN_SUBELEM_UNIQUE,
+                                        YANG_CUSTOM, NULL, 0
+                                   ));
+    ret = yin_parse_content(ctx, subelems, 25, data, YANG_LIST, NULL, &list->exts);
+    subelems_deallocator(25, subelems);
+    LY_CHECK_RET(ret);
+
+    /* finalize parent pointers to the reallocated items */
+    LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, list->groupings, NULL, list->actions, list->notifs));
+
+    if (list->max && list->min > list->max) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_MINMAX, list->min, list->max);
+        return LY_EVALID;
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse notification element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] notif_meta Meta information about parent node and notifications to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_notification(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                       struct tree_node_meta *notif_meta)
+{
+    struct lysp_notif *notif;
+    struct lysp_notif **notifs = (struct lysp_notif **)notif_meta->nodes;
+    LY_ERR ret = LY_SUCCESS;
+    struct yin_subelement *subelems = NULL;
+
+    /* allocate new notification */
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *notifs, notif, LY_EMEM);
+    notif->nodetype = LYS_NOTIF;
+    notif->parent = notif_meta->parent;
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &notif->name, Y_IDENTIF_ARG, YANG_NOTIFICATION));
+
+    /* parse notification content */
+    LY_CHECK_RET(subelems_allocator(ctx, 16, (struct lysp_node *)notif, &subelems,
+                                        YANG_ANYDATA, &notif->data, 0,
+                                        YANG_ANYXML, &notif->data, 0,
+                                        YANG_CHOICE, &notif->data, 0,
+                                        YANG_CONTAINER, &notif->data, 0,
+                                        YANG_DESCRIPTION, &notif->dsc, YIN_SUBELEM_UNIQUE,
+                                        YANG_GROUPING, &notif->groupings, 0,
+                                        YANG_IF_FEATURE, &notif->iffeatures, 0,
+                                        YANG_LEAF, &notif->data, 0,
+                                        YANG_LEAF_LIST, &notif->data, 0,
+                                        YANG_LIST, &notif->data, 0,
+                                        YANG_MUST, &notif->musts, YIN_SUBELEM_VER2,
+                                        YANG_REFERENCE, &notif->ref, YIN_SUBELEM_UNIQUE,
+                                        YANG_STATUS, &notif->flags, YIN_SUBELEM_UNIQUE,
+                                        YANG_TYPEDEF, &notif->typedefs, 0,
+                                        YANG_USES, &notif->data, 0,
+                                        YANG_CUSTOM, NULL, 0
+                                   ));
+
+    ret = yin_parse_content(ctx, subelems, 16, data, YANG_NOTIFICATION, NULL, &notif->exts);
+    subelems_deallocator(16, subelems);
+    LY_CHECK_RET(ret);
+
+    /* finalize parent pointers to the reallocated items */
+    LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, notif->groupings, NULL, NULL, NULL));
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse grouping element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] gr_meta Meta information about parent node and groupings to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_grouping(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                   struct tree_node_meta *gr_meta)
+{
+    struct lysp_grp *grp;
+    struct lysp_grp **grps = (struct lysp_grp **)gr_meta->nodes;
+    LY_ERR ret = LY_SUCCESS;
+    struct yin_subelement *subelems = NULL;
+
+    /* create new grouping */
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *grps, grp, LY_EMEM);
+    grp->nodetype = LYS_GROUPING;
+    grp->parent = gr_meta->parent;
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &grp->name, Y_IDENTIF_ARG, YANG_GROUPING));
+
+    /* parse grouping content */
+    LY_CHECK_RET(subelems_allocator(ctx, 16, (struct lysp_node *)grp, &subelems,
+                                        YANG_ACTION, &grp->actions, 0,
+                                        YANG_ANYDATA, &grp->data, 0,
+                                        YANG_ANYXML, &grp->data, 0,
+                                        YANG_CHOICE, &grp->data, 0,
+                                        YANG_CONTAINER, &grp->data, 0,
+                                        YANG_DESCRIPTION, &grp->dsc, YIN_SUBELEM_UNIQUE,
+                                        YANG_GROUPING, &grp->groupings, 0,
+                                        YANG_LEAF, &grp->data, 0,
+                                        YANG_LEAF_LIST, &grp->data, 0,
+                                        YANG_LIST, &grp->data, 0,
+                                        YANG_NOTIFICATION, &grp->notifs, 0,
+                                        YANG_REFERENCE, &grp->ref, YIN_SUBELEM_UNIQUE,
+                                        YANG_STATUS, &grp->flags, YIN_SUBELEM_UNIQUE,
+                                        YANG_TYPEDEF, &grp->typedefs, 0,
+                                        YANG_USES, &grp->data, 0,
+                                        YANG_CUSTOM, NULL, 0
+                                   ));
+    ret = yin_parse_content(ctx, subelems, 16, data, YANG_GROUPING, NULL, &grp->exts);
+    subelems_deallocator(16, subelems);
+    LY_CHECK_RET(ret);
+
+    /* finalize parent pointers to the reallocated items */
+    LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, grp->groupings, NULL, grp->actions, grp->notifs));
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse container element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] node_meta Meta information about parent node and siblings to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_container(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                    struct tree_node_meta *node_meta)
+{
+    struct lysp_node_container *cont;
+    LY_ERR ret = LY_SUCCESS;
+    struct yin_subelement *subelems = NULL;
+
+    /* create new container */
+    LY_LIST_NEW_RET(ctx->xml_ctx.ctx, node_meta->nodes, cont, next);
+    cont->nodetype = LYS_CONTAINER;
+    cont->parent = node_meta->parent;
+
+    /* parse aegument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME,  &cont->name, Y_IDENTIF_ARG, YANG_CONTAINER));
+
+    /* parse container content */
+    LY_CHECK_RET(subelems_allocator(ctx, 21, (struct lysp_node *)cont, &subelems,
+                                        YANG_ACTION, &cont->actions, YIN_SUBELEM_VER2,
+                                        YANG_ANYDATA, &cont->child, YIN_SUBELEM_VER2,
+                                        YANG_ANYXML, &cont->child, 0,
+                                        YANG_CHOICE, &cont->child, 0,
+                                        YANG_CONFIG, &cont->flags, YIN_SUBELEM_UNIQUE,
+                                        YANG_CONTAINER, &cont->child, 0,
+                                        YANG_DESCRIPTION, &cont->dsc, YIN_SUBELEM_UNIQUE,
+                                        YANG_GROUPING, &cont->groupings, 0,
+                                        YANG_IF_FEATURE, &cont->iffeatures, 0,
+                                        YANG_LEAF, &cont->child, 0,
+                                        YANG_LEAF_LIST, &cont->child, 0,
+                                        YANG_LIST, &cont->child, 0,
+                                        YANG_MUST, &cont->musts, 0,
+                                        YANG_NOTIFICATION, &cont->notifs, YIN_SUBELEM_VER2,
+                                        YANG_PRESENCE, &cont->presence, YIN_SUBELEM_UNIQUE,
+                                        YANG_REFERENCE, &cont->ref, YIN_SUBELEM_UNIQUE,
+                                        YANG_STATUS, &cont->flags, YIN_SUBELEM_UNIQUE,
+                                        YANG_TYPEDEF, &cont->typedefs, 0,
+                                        YANG_USES, &cont->child, 0,
+                                        YANG_WHEN, &cont->when, YIN_SUBELEM_UNIQUE,
+                                        YANG_CUSTOM, NULL, 0
+                                   ));
+    ret = yin_parse_content(ctx, subelems, 21, data, YANG_CONTAINER, NULL, &cont->exts);
+    subelems_deallocator(21, subelems);
+    LY_CHECK_RET(ret);
+
+    LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, cont->groupings, NULL, cont->actions, cont->notifs));
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse case element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] node_meta Meta information about parent node and siblings to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_case(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+               struct tree_node_meta *node_meta)
+{
+    struct lysp_node_case *cas;
+    LY_ERR ret = LY_SUCCESS;
+    struct yin_subelement *subelems = NULL;;
+
+    /* create new case */
+    LY_LIST_NEW_RET(ctx->xml_ctx.ctx, node_meta->nodes, cas, next);
+    cas->nodetype = LYS_CASE;
+    cas->parent = node_meta->parent;
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &cas->name, Y_IDENTIF_ARG, YANG_CASE));
+
+    /* parse case content */
+    LY_CHECK_RET(subelems_allocator(ctx, 14, (struct lysp_node *)cas, &subelems,
+                                        YANG_ANYDATA, &cas->child, YIN_SUBELEM_VER2,
+                                        YANG_ANYXML, &cas->child, 0,
+                                        YANG_CHOICE, &cas->child, 0,
+                                        YANG_CONTAINER, &cas->child, 0,
+                                        YANG_DESCRIPTION, &cas->dsc, YIN_SUBELEM_UNIQUE,
+                                        YANG_IF_FEATURE, &cas->iffeatures, 0,
+                                        YANG_LEAF, &cas->child, 0,
+                                        YANG_LEAF_LIST, &cas->child, 0,
+                                        YANG_LIST, &cas->child, 0,
+                                        YANG_REFERENCE, &cas->ref, YIN_SUBELEM_UNIQUE,
+                                        YANG_STATUS, &cas->flags, YIN_SUBELEM_UNIQUE,
+                                        YANG_USES, &cas->child, 0,
+                                        YANG_WHEN, &cas->when, YIN_SUBELEM_UNIQUE,
+                                        YANG_CUSTOM, NULL, 0
+                                   ));
+    ret = yin_parse_content(ctx, subelems, 14, data, YANG_CASE, NULL, &cas->exts);
+    subelems_deallocator(14, subelems);
+
+    return ret;
+}
+
+/**
+ * @brief Parse choice element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] node_meta Meta information about parent node and siblings to add to.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR
+yin_parse_choice(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                 struct tree_node_meta *node_meta)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct yin_subelement *subelems = NULL;
+    struct lysp_node_choice *choice;
+
+    /* create new choice */
+    LY_LIST_NEW_RET(ctx->xml_ctx.ctx, node_meta->nodes, choice, next);
+
+    choice->nodetype = LYS_CHOICE;
+    choice->parent = node_meta->parent;
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &choice->name, Y_IDENTIF_ARG, YANG_CHOICE));
+
+    /* parse choice content */
+    LY_CHECK_RET(subelems_allocator(ctx, 17, (struct lysp_node *)choice, &subelems,
+                                        YANG_ANYDATA, &choice->child, YIN_SUBELEM_VER2,
+                                        YANG_ANYXML, &choice->child, 0,
+                                        YANG_CASE, &choice->child, 0,
+                                        YANG_CHOICE, &choice->child, YIN_SUBELEM_VER2,
+                                        YANG_CONFIG, &choice->flags, YIN_SUBELEM_UNIQUE,
+                                        YANG_CONTAINER, &choice->child, 0,
+                                        YANG_DEFAULT, &choice->dflt, YIN_SUBELEM_UNIQUE,
+                                        YANG_DESCRIPTION, &choice->dsc, YIN_SUBELEM_UNIQUE,
+                                        YANG_IF_FEATURE, &choice->iffeatures, 0,
+                                        YANG_LEAF, &choice->child, 0,
+                                        YANG_LEAF_LIST, &choice->child, 0,
+                                        YANG_LIST, &choice->child, 0,
+                                        YANG_MANDATORY, &choice->flags, YIN_SUBELEM_UNIQUE,
+                                        YANG_REFERENCE, &choice->ref, YIN_SUBELEM_UNIQUE,
+                                        YANG_STATUS, &choice->flags, YIN_SUBELEM_UNIQUE,
+                                        YANG_WHEN, &choice->when, YIN_SUBELEM_UNIQUE,
+                                        YANG_CUSTOM, NULL, 0
+                                   ));
+    ret = yin_parse_content(ctx, subelems, 17, data, YANG_CHOICE, NULL, &choice->exts);
+    subelems_deallocator(17, subelems);
+    return ret;
+}
+
+/**
+ * @brief Parse input or output element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] inout_kw Identification of input/output element.
+ * @param[in] inout_meta Meta information about parent node and siblings and input/output pointer to write to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_inout(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, enum yang_keyword inout_kw,
+                struct inout_meta *inout_meta)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct yin_subelement *subelems = NULL;
+
+    /* initiate structure */
+    inout_meta->inout_p->nodetype = (inout_kw == YANG_INPUT) ? LYS_INPUT : LYS_OUTPUT;
+    inout_meta->inout_p->parent = inout_meta->parent;
+
+    /* check attributes */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NONE, NULL, Y_MAYBE_STR_ARG, inout_kw));
+
+    /* parser input/output content */
+    LY_CHECK_RET(subelems_allocator(ctx, 12, (struct lysp_node *)inout_meta->inout_p, &subelems,
+                                        YANG_ANYDATA, &inout_meta->inout_p->data, YIN_SUBELEM_VER2,
+                                        YANG_ANYXML, &inout_meta->inout_p->data, 0,
+                                        YANG_CHOICE, &inout_meta->inout_p->data, 0,
+                                        YANG_CONTAINER, &inout_meta->inout_p->data, 0,
+                                        YANG_GROUPING, &inout_meta->inout_p->groupings, 0,
+                                        YANG_LEAF, &inout_meta->inout_p->data, 0,
+                                        YANG_LEAF_LIST, &inout_meta->inout_p->data, 0,
+                                        YANG_LIST, &inout_meta->inout_p->data, 0,
+                                        YANG_MUST, &inout_meta->inout_p->musts, YIN_SUBELEM_VER2,
+                                        YANG_TYPEDEF, &inout_meta->inout_p->typedefs, 0,
+                                        YANG_USES, &inout_meta->inout_p->data, 0,
+                                        YANG_CUSTOM, NULL, 0
+                                   ));
+    ret = yin_parse_content(ctx, subelems, 12, data, inout_kw, NULL, &inout_meta->inout_p->exts);
+    subelems_deallocator(12, subelems);
+    LY_CHECK_RET(ret);
+
+    /* finalize parent pointers to the reallocated items */
+    LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, inout_meta->inout_p->groupings, NULL, NULL, NULL));
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse action element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] act_meta Meta information about parent node and actions to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_action(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                 struct tree_node_meta *act_meta)
+{
+    struct lysp_action *act, **acts = (struct lysp_action **)act_meta->nodes;
+    LY_ERR ret = LY_SUCCESS;
+    struct yin_subelement *subelems = NULL;
+
+    /* create new action */
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *acts, act, LY_EMEM);
+    act->nodetype = LYS_ACTION;
+    act->parent = act_meta->parent;
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &act->name, Y_IDENTIF_ARG, YANG_ACTION));
+
+    /* parse content */
+    LY_CHECK_RET(subelems_allocator(ctx, 9, (struct lysp_node *)act, &subelems,
+                                        YANG_DESCRIPTION, &act->dsc, YIN_SUBELEM_UNIQUE,
+                                        YANG_GROUPING, &act->groupings, 0,
+                                        YANG_IF_FEATURE, &act->iffeatures, 0,
+                                        YANG_INPUT, &act->input, YIN_SUBELEM_UNIQUE,
+                                        YANG_OUTPUT, &act->output, YIN_SUBELEM_UNIQUE,
+                                        YANG_REFERENCE, &act->ref, YIN_SUBELEM_UNIQUE,
+                                        YANG_STATUS, &act->flags, YIN_SUBELEM_UNIQUE,
+                                        YANG_TYPEDEF, &act->typedefs, 0,
+                                        YANG_CUSTOM, NULL, 0
+                                   ));
+    ret = (yin_parse_content(ctx, subelems, 9, data, YANG_ACTION, NULL, &act->exts));
+    subelems_deallocator(9, subelems);
+    LY_CHECK_RET(ret);
+
+    LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, act->groupings, NULL, NULL, NULL));
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse augment element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] aug_meta Meta information about parent node and augments to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_augment(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                  struct tree_node_meta *aug_meta)
+{
+    struct lysp_augment *aug;
+    struct lysp_augment **augs = (struct lysp_augment **)aug_meta->nodes;
+    LY_ERR ret = LY_SUCCESS;
+    struct yin_subelement *subelems = NULL;
+
+    /* create new augment */
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *augs, aug, LY_EMEM);
+    aug->nodetype = LYS_AUGMENT;
+    aug->parent = aug_meta->parent;
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_TARGET_NODE, &aug->nodeid, Y_STR_ARG, YANG_AUGMENT));
+    YANG_CHECK_NONEMPTY((struct lys_parser_ctx *)ctx, strlen(aug->nodeid), "augment");
+
+    /* parser augment content */
+    LY_CHECK_RET(subelems_allocator(ctx, 17, (struct lysp_node *)aug, &subelems,
+                                        YANG_ACTION, &aug->actions, YIN_SUBELEM_VER2,
+                                        YANG_ANYDATA, &aug->child, YIN_SUBELEM_VER2,
+                                        YANG_ANYXML, &aug->child, 0,
+                                        YANG_CASE, &aug->child, 0,
+                                        YANG_CHOICE, &aug->child, 0,
+                                        YANG_CONTAINER, &aug->child, 0,
+                                        YANG_DESCRIPTION, &aug->dsc, YIN_SUBELEM_UNIQUE,
+                                        YANG_IF_FEATURE, &aug->iffeatures, 0,
+                                        YANG_LEAF, &aug->child, 0,
+                                        YANG_LEAF_LIST, &aug->child, 0,
+                                        YANG_LIST, &aug->child, 0,
+                                        YANG_NOTIFICATION, &aug->notifs, YIN_SUBELEM_VER2,
+                                        YANG_REFERENCE, &aug->ref, YIN_SUBELEM_UNIQUE,
+                                        YANG_STATUS, &aug->flags, YIN_SUBELEM_UNIQUE,
+                                        YANG_USES, &aug->child, 0,
+                                        YANG_WHEN, &aug->when, YIN_SUBELEM_UNIQUE,
+                                        YANG_CUSTOM, NULL, 0
+                                   ));
+    ret = yin_parse_content(ctx, subelems, 17, data, YANG_AUGMENT, NULL, &aug->exts);
+    subelems_deallocator(17, subelems);
+    LY_CHECK_RET(ret);
+
+    LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, NULL, NULL, aug->actions, aug->notifs));
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse deviate element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] deviates Deviates to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_deviate(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                  struct lysp_deviate **deviates)
+{
+    LY_ERR ret = LY_SUCCESS;
+    uint8_t dev_mod;
+    const char *temp_val;
+    struct lysp_deviate *d;
+    struct lysp_deviate_add *d_add = NULL;
+    struct lysp_deviate_rpl *d_rpl = NULL;
+    struct lysp_deviate_del *d_del = NULL;
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_DEVIATE));
+
+    if (strcmp(temp_val, "not-supported") == 0) {
+        dev_mod = LYS_DEV_NOT_SUPPORTED;
+    } else if (strcmp(temp_val, "add") == 0) {
+        dev_mod = LYS_DEV_ADD;
+    } else if (strcmp(temp_val, "replace") == 0) {
+        dev_mod = LYS_DEV_REPLACE;
+    } else if (strcmp(temp_val, "delete") == 0) {
+        dev_mod = LYS_DEV_DELETE;
+    } else {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS4, temp_val, "value", "deviate",
+                       "not-supported", "add", "replace", "delete");
+        FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+        return LY_EVALID;
+    }
+    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+
+    if (dev_mod == LYS_DEV_NOT_SUPPORTED) {
+        d = calloc(1, sizeof *d);
+        LY_CHECK_ERR_RET(!d, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+        struct yin_subelement subelems[1] = {
+                                                {YANG_CUSTOM, NULL, 0}
+                                            };
+        ret = yin_parse_content(ctx, subelems, 1, data, YANG_DEVIATE, NULL, &d->exts);
+
+    } else if (dev_mod == LYS_DEV_ADD) {
+        d_add = calloc(1, sizeof *d_add);
+        LY_CHECK_ERR_RET(!d_add, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+        d = (struct lysp_deviate *)d_add;
+        struct minmax_dev_meta min = {&d_add->min, &d_add->flags, &d_add->exts};
+        struct minmax_dev_meta max = {&d_add->max, &d_add->flags, &d_add->exts};
+        struct yin_subelement subelems[9] = {
+                                                {YANG_CONFIG, &d_add->flags, YIN_SUBELEM_UNIQUE},
+                                                {YANG_DEFAULT, &d_add->dflts, 0},
+                                                {YANG_MANDATORY, &d_add->flags, YIN_SUBELEM_UNIQUE},
+                                                {YANG_MAX_ELEMENTS, &max, YIN_SUBELEM_UNIQUE},
+                                                {YANG_MIN_ELEMENTS, &min, YIN_SUBELEM_UNIQUE},
+                                                {YANG_MUST, &d_add->musts, 0},
+                                                {YANG_UNIQUE, &d_add->uniques, 0},
+                                                {YANG_UNITS, &d_add->units, YIN_SUBELEM_UNIQUE},
+                                                {YANG_CUSTOM, NULL, 0},
+                                            };
+        ret = yin_parse_content(ctx, subelems, 9, data, YANG_DEVIATE, NULL, &d_add->exts);
+
+    } else if (dev_mod == LYS_DEV_REPLACE) {
+        d_rpl = calloc(1, sizeof *d_rpl);
+        LY_CHECK_ERR_RET(!d_rpl, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+        d = (struct lysp_deviate *)d_rpl;
+        struct minmax_dev_meta min = {&d_rpl->min, &d_rpl->flags, &d_rpl->exts};
+        struct minmax_dev_meta max = {&d_rpl->max, &d_rpl->flags, &d_rpl->exts};
+        struct yin_subelement subelems[8] = {
+                                                {YANG_CONFIG, &d_rpl->flags, YIN_SUBELEM_UNIQUE},
+                                                {YANG_DEFAULT, &d_rpl->dflt, YIN_SUBELEM_UNIQUE},
+                                                {YANG_MANDATORY, &d_rpl->flags, YIN_SUBELEM_UNIQUE},
+                                                {YANG_MAX_ELEMENTS, &max, YIN_SUBELEM_UNIQUE},
+                                                {YANG_MIN_ELEMENTS, &min, YIN_SUBELEM_UNIQUE},
+                                                {YANG_TYPE, &d_rpl->type, YIN_SUBELEM_UNIQUE},
+                                                {YANG_UNITS, &d_rpl->units, YIN_SUBELEM_UNIQUE},
+                                                {YANG_CUSTOM, NULL, 0},
+                                            };
+        ret = yin_parse_content(ctx, subelems, 8, data, YANG_DEVIATE, NULL, &d_rpl->exts);
+
+    } else {
+        d_del = calloc(1, sizeof *d_del);
+        LY_CHECK_ERR_RET(!d_del, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+        d = (struct lysp_deviate *)d_del;
+        struct yin_subelement subelems[5] = {
+                                                {YANG_DEFAULT, &d_del->dflts, 0},
+                                                {YANG_MUST, &d_del->musts, 0},
+                                                {YANG_UNIQUE, &d_del->uniques, 0},
+                                                {YANG_UNITS, &d_del->units, YIN_SUBELEM_UNIQUE},
+                                                {YANG_CUSTOM, NULL, 0},
+                                            };
+        ret = yin_parse_content(ctx, subelems, 5, data, YANG_DEVIATE, NULL, &d_del->exts);
+    }
+    LY_CHECK_GOTO(ret, cleanup);
+
+    d->mod = dev_mod;
+    /* insert into siblings */
+    LY_LIST_INSERT(deviates, d, next);
+
+    return ret;
+
+cleanup:
+    free(d);
+    return ret;
+}
+
+/**
+ * @brief Parse deviation element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] deviations Deviations to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_deviation(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                    struct lysp_deviation **deviations)
+{
+    struct lysp_deviation *dev;
+
+    /* create new deviation */
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *deviations, dev, LY_EMEM);
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_TARGET_NODE, &dev->nodeid, Y_STR_ARG, YANG_DEVIATION));
+    YANG_CHECK_NONEMPTY((struct lys_parser_ctx *)ctx, strlen(dev->nodeid), "deviation");
+    struct yin_subelement subelems[4] = {
+                                            {YANG_DESCRIPTION, &dev->dsc, YIN_SUBELEM_UNIQUE},
+                                            {YANG_DEVIATE, &dev->deviates, YIN_SUBELEM_MANDATORY},
+                                            {YANG_REFERENCE, &dev->ref, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0},
+                                        };
+    return yin_parse_content(ctx, subelems, 4, data, YANG_DEVIATION, NULL, &dev->exts);
+}
+
+/**
+ * @brief Map keyword type to substatement info.
+ *
+ * @param[in] kw Keyword type.
+ *
+ * @return correct LYEXT_SUBSTMT information.
+ */
+static LYEXT_SUBSTMT
+kw2lyext_substmt(enum yang_keyword kw)
+{
+    switch (kw) {
+    case YANG_ARGUMENT:
+        return LYEXT_SUBSTMT_ARGUMENT;
+    case YANG_BASE:
+        return LYEXT_SUBSTMT_BASE;
+    case YANG_BELONGS_TO:
+        return LYEXT_SUBSTMT_BELONGSTO;
+    case YANG_CONTACT:
+        return LYEXT_SUBSTMT_CONTACT;
+    case YANG_DEFAULT:
+        return LYEXT_SUBSTMT_DEFAULT;
+    case YANG_DESCRIPTION:
+        return LYEXT_SUBSTMT_DESCRIPTION;
+    case YANG_ERROR_APP_TAG:
+        return LYEXT_SUBSTMT_ERRTAG;
+    case YANG_ERROR_MESSAGE:
+        return LYEXT_SUBSTMT_ERRMSG;
+    case YANG_KEY:
+        return LYEXT_SUBSTMT_KEY;
+    case YANG_NAMESPACE:
+        return LYEXT_SUBSTMT_NAMESPACE;
+    case YANG_ORGANIZATION:
+        return LYEXT_SUBSTMT_ORGANIZATION;
+    case YANG_PATH:
+        return LYEXT_SUBSTMT_PATH;
+    case YANG_PREFIX:
+        return LYEXT_SUBSTMT_PREFIX;
+    case YANG_PRESENCE:
+        return LYEXT_SUBSTMT_PRESENCE;
+    case YANG_REFERENCE:
+        return LYEXT_SUBSTMT_REFERENCE;
+    case YANG_REVISION_DATE:
+        return LYEXT_SUBSTMT_REVISIONDATE;
+    case YANG_UNITS:
+        return LYEXT_SUBSTMT_UNITS;
+    case YANG_VALUE:
+        return LYEXT_SUBSTMT_VALUE;
+    case YANG_YANG_VERSION:
+        return LYEXT_SUBSTMT_VERSION;
+    case YANG_MODIFIER:
+        return LYEXT_SUBSTMT_MODIFIER;
+    case YANG_REQUIRE_INSTANCE:
+        return LYEXT_SUBSTMT_REQINSTANCE;
+    case YANG_YIN_ELEMENT:
+        return LYEXT_SUBSTMT_YINELEM;
+    case YANG_CONFIG:
+        return LYEXT_SUBSTMT_CONFIG;
+    case YANG_MANDATORY:
+        return LYEXT_SUBSTMT_MANDATORY;
+    case YANG_ORDERED_BY:
+        return LYEXT_SUBSTMT_ORDEREDBY;
+    case YANG_STATUS:
+        return LYEXT_SUBSTMT_STATUS;
+    case YANG_FRACTION_DIGITS:
+        return LYEXT_SUBSTMT_FRACDIGITS;
+    case YANG_MAX_ELEMENTS:
+        return LYEXT_SUBSTMT_MAX;
+    case YANG_MIN_ELEMENTS:
+        return LYEXT_SUBSTMT_MIN;
+    case YANG_POSITION:
+        return LYEXT_SUBSTMT_POSITION;
+    case YANG_UNIQUE:
+        return LYEXT_SUBSTMT_UNIQUE;
+    case YANG_IF_FEATURE:
+        return LYEXT_SUBSTMT_IFFEATURE;
+    default:
+        return LYEXT_SUBSTMT_SELF;
+    }
+}
+
+/**
+ * @brief map keyword to keyword-group.
+ *
+ * @param[in] ctx YIN parser context used for logging.
+ * @param[in] kw Keyword that is child of module or submodule.
+ * @param[out] group Group of keyword.
+ *
+ * @return LY_SUCCESS on success LY_EINT if kw can't be mapped to kw_group, should not happen if called correctly.
+ */
+static LY_ERR
+kw2kw_group(struct yin_parser_ctx *ctx, enum yang_keyword kw, enum yang_module_stmt *group)
+{
+    switch (kw) {
+        /* module header */
+        case YANG_NONE:
+        case YANG_NAMESPACE:
+        case YANG_PREFIX:
+        case YANG_BELONGS_TO:
+        case YANG_YANG_VERSION:
+            *group = Y_MOD_MODULE_HEADER;
+            break;
+        /* linkage */
+        case YANG_INCLUDE:
+        case YANG_IMPORT:
+            *group = Y_MOD_LINKAGE;
+            break;
+        /* meta */
+        case YANG_ORGANIZATION:
+        case YANG_CONTACT:
+        case YANG_DESCRIPTION:
+        case YANG_REFERENCE:
+            *group = Y_MOD_META;
+            break;
+        /* revision */
+        case YANG_REVISION:
+            *group = Y_MOD_REVISION;
+            break;
+        /* body */
+        case YANG_ANYDATA:
+        case YANG_ANYXML:
+        case YANG_AUGMENT:
+        case YANG_CHOICE:
+        case YANG_CONTAINER:
+        case YANG_DEVIATION:
+        case YANG_EXTENSION:
+        case YANG_FEATURE:
+        case YANG_GROUPING:
+        case YANG_IDENTITY:
+        case YANG_LEAF:
+        case YANG_LEAF_LIST:
+        case YANG_LIST:
+        case YANG_NOTIFICATION:
+        case YANG_RPC:
+        case YANG_TYPEDEF:
+        case YANG_USES:
+        case YANG_CUSTOM:
+            *group = Y_MOD_BODY;
+            break;
+        default:
+            LOGINT(ctx->xml_ctx.ctx);
+            return LY_EINT;
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Check if relative order of two keywords is valid.
+ *
+ * @param[in] ctx YIN parser context used for logging.
+ * @param[in] kw Current keyword.
+ * @param[in] next_kw Next keyword.
+ * @param[in] parrent Identification of parrent element, can be se to to YANG_MODULE of YANG_SUBMODULE,
+ *            because relative order is required only in module and submodule sub-elements, used for logging.
+ *
+ * @return LY_SUCCESS on success and LY_EVALID if relative order is invalid.
+ */
+static LY_ERR
+yin_check_relative_order(struct yin_parser_ctx *ctx, enum yang_keyword kw, enum yang_keyword next_kw, enum yang_keyword parrent)
+{
+    assert(parrent == YANG_MODULE || parrent == YANG_SUBMODULE);
+    enum yang_module_stmt gr, next_gr;
+
+    LY_CHECK_RET(kw2kw_group(ctx, kw, &gr));
+    LY_CHECK_RET(kw2kw_group(ctx, next_kw, &next_gr));
+
+    if (gr > next_gr) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INORDER_YIN, ly_stmt2str(parrent), ly_stmt2str(next_kw), ly_stmt2str(kw));
+        return LY_EVALID;
+    }
+
+    return LY_SUCCESS;
+}
+
+LY_ERR
+yin_parse_content(struct yin_parser_ctx *ctx, struct yin_subelement *subelem_info, signed char subelem_info_size,
+                  const char **data, enum yang_keyword current_element, const char **text_content, struct lysp_ext_instance **exts)
+{
+    LY_ERR ret = LY_SUCCESS;
+    char *out = NULL;
+    const char *prefix, *name;
+    size_t out_len = 0, prefix_len, name_len;
+    int dynamic = 0;
+    struct yin_arg_record *attrs = NULL;
+    enum yang_keyword kw = YANG_NONE, last_kw = YANG_NONE;
+    struct yin_subelement *subelem = NULL;
+
+    assert(is_ordered(subelem_info, subelem_info_size));
+
+    if (ctx->xml_ctx.status == LYXML_ELEM_CONTENT) {
+        ret = lyxml_get_string(&ctx->xml_ctx, data, &out, &out_len, &out, &out_len, &dynamic);
+        /* current element has subelements as content */
+        if (ret == LY_EINVAL) {
+            while (ctx->xml_ctx.status == LYXML_ELEMENT) {
+                ret = lyxml_get_element(&ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
+                LY_CHECK_GOTO(ret, cleanup);
+                if (!name) {
+                    /* end of current element reached */
+                    break;
+                }
+                ret = yin_load_attributes(ctx, data, &attrs);
+                LY_CHECK_GOTO(ret, cleanup);
+                last_kw = kw;
+                kw = yin_match_keyword(ctx, name, name_len, prefix, prefix_len, current_element);
+
+                /* check if this element can be child of current element */
+                subelem = get_record(kw, subelem_info_size, subelem_info);
+                if (!subelem) {
+                    if (current_element == YANG_DEVIATE && isdevsub(kw)) {
+                        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INDEV_YIN, ly_stmt2str(kw));
+                    } else {
+                        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_UNEXP_SUBELEM, name_len, name, ly_stmt2str(current_element));
+                    }
+                    ret = LY_EVALID;
+                    goto cleanup;
+                }
+
+                /* relative order is required only in module and submodule sub-elements */
+                if (current_element == YANG_MODULE || current_element == YANG_SUBMODULE) {
+                    ret = yin_check_relative_order(ctx, last_kw, kw, current_element);
+                    LY_CHECK_GOTO(ret, cleanup);
+                }
+
+                /* flag check */
+                if ((subelem->flags & YIN_SUBELEM_UNIQUE) && (subelem->flags & YIN_SUBELEM_PARSED)) {
+                    /* subelement uniquenes */
+                    LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_SUBELEM_REDEF, ly_stmt2str(kw), ly_stmt2str(current_element));
+                    return LY_EVALID;
+                }
+                if (subelem->flags & YIN_SUBELEM_FIRST) {
+                    /* subelement is supposed to be defined as first subelement */
+                    ret = yin_check_subelem_first_constraint(ctx, subelem_info, subelem_info_size, current_element, subelem);
+                    LY_CHECK_GOTO(ret, cleanup);
+                }
+                if (subelem->flags & YIN_SUBELEM_VER2) {
+                    /* subelement is supported only in version 1.1 or higher */
+                    if (ctx->mod_version < 2) {
+                        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INSUBELEM2, ly_stmt2str(kw), ly_stmt2str(current_element));
+                        ret = LY_EVALID;
+                        goto cleanup;
+                    }
+                }
+                /* note that element was parsed for easy uniqueness check in next iterations */
+                subelem->flags |= YIN_SUBELEM_PARSED;
+
+                switch (kw) {
+                /* call responsible function */
+                case YANG_CUSTOM:
+                    ret = yin_parse_extension_instance(ctx, attrs, data, name2fname(name, prefix_len),
+                                                      len2flen(name_len, prefix_len),
+                                                      kw2lyext_substmt(current_element),
+                                                      (subelem->dest) ? *((uint32_t*)subelem->dest) : 0, exts);
+                    break;
+                case YANG_ACTION:
+                case YANG_RPC:
+                    ret = yin_parse_action(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+                    break;
+                case YANG_ANYDATA:
+                case YANG_ANYXML:
+                    ret = yin_parse_any(ctx, attrs, data, kw, (struct tree_node_meta *)subelem->dest);
+                    break;
+                case YANG_ARGUMENT:
+                    ret = yin_parse_argument(ctx, attrs, data, (struct yin_argument_meta *)subelem->dest, exts);
+                    break;
+                case YANG_AUGMENT:
+                    ret = yin_parse_augment(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+                    break;
+                case YANG_BASE:
+                    ret = yin_parse_base(ctx, attrs, data, current_element, subelem->dest, exts);
+                    break;
+                case YANG_BELONGS_TO:
+                    ret = yin_parse_belongs_to(ctx, attrs, data, (struct lysp_submodule *)subelem->dest, exts);
+                    break;
+                case YANG_BIT:
+                    ret = yin_parse_bit(ctx, attrs, data, (struct lysp_type *)subelem->dest);
+                    break;
+                case YANG_CASE:
+                    ret = yin_parse_case(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+                    break;
+                case YANG_CHOICE:
+                    ret = yin_parse_choice(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+                    break;
+                case YANG_CONFIG:
+                    ret = yin_parse_config(ctx, attrs, data, (uint16_t *)subelem->dest, exts);
+                    break;
+                case YANG_CONTACT:
+                case YANG_DESCRIPTION:
+                case YANG_ORGANIZATION:
+                case YANG_REFERENCE:
+                    ret = yin_parse_meta(ctx, attrs, data, kw, (const char **)subelem->dest, exts);
+                    break;
+                case YANG_CONTAINER:
+                    ret = yin_parse_container(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+                    break;
+                case YANG_DEFAULT:
+                case YANG_ERROR_APP_TAG:
+                case YANG_KEY:
+                case YANG_PRESENCE:
+                    ret = yin_parse_simple_elem(ctx, attrs, data, kw, subelem, YIN_ARG_VALUE, Y_STR_ARG, exts);
+                    break;
+                case YANG_DEVIATE:
+                    ret = yin_parse_deviate(ctx, attrs, data, (struct lysp_deviate **)subelem->dest);
+                    break;
+                case YANG_DEVIATION:
+                    ret = yin_parse_deviation(ctx, attrs, data, (struct lysp_deviation **)subelem->dest);
+                    break;
+                case YANG_ENUM:
+                    ret = yin_parse_enum(ctx, attrs, data, (struct lysp_type *)subelem->dest);
+                    break;
+                case YANG_ERROR_MESSAGE:
+                    ret = yin_parse_err_msg(ctx, attrs, data, (const char **)subelem->dest, exts);
+                    break;
+                case YANG_EXTENSION:
+                    ret = yin_parse_extension(ctx, attrs, data, (struct lysp_ext **)subelem->dest);
+                    break;
+                case YANG_FEATURE:
+                    ret = yin_parse_feature(ctx, attrs, data, (struct lysp_feature **)subelem->dest);
+                    break;
+                case YANG_FRACTION_DIGITS:
+                    ret = yin_parse_fracdigits(ctx, attrs, data, (struct lysp_type *)subelem->dest);
+                    break;
+                case YANG_GROUPING:
+                    ret = yin_parse_grouping(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+                    break;
+                case YANG_IDENTITY:
+                    ret = yin_parse_identity(ctx, attrs, data, (struct lysp_ident **)subelem->dest);
+                    break;
+                case YANG_IF_FEATURE:
+                case YANG_UNITS:
+                    ret = yin_parse_simple_elem(ctx, attrs, data, kw, subelem, YIN_ARG_NAME, Y_STR_ARG, exts);
+                    break;
+                case YANG_IMPORT:
+                    ret = yin_parse_import(ctx, attrs, data, (struct import_meta *)subelem->dest);
+                    break;
+                case YANG_INCLUDE:
+                    ret = yin_parse_include(ctx, attrs, data, (struct include_meta *)subelem->dest);
+                    break;
+                case YANG_INPUT:
+                case YANG_OUTPUT:
+                    ret = yin_parse_inout(ctx, attrs, data, kw, (struct inout_meta *)subelem->dest);
+                    break;
+                case YANG_LEAF:
+                    ret = yin_parse_leaf(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+                    break;
+                case YANG_LEAF_LIST:
+                    ret = yin_parse_leaflist(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+                    break;
+                case YANG_LENGTH:
+                    ret = yin_parse_length(ctx, attrs, data, (struct lysp_type *)subelem->dest);
+                    break;
+                case YANG_LIST:
+                    ret = yin_parse_list(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+                    break;
+                case YANG_MANDATORY:
+                    ret = yin_parse_mandatory(ctx, attrs, data, (uint16_t *)subelem->dest, exts);
+                    break;
+                case YANG_MAX_ELEMENTS:
+                case YANG_MIN_ELEMENTS:
+                    ret = yin_parse_minmax(ctx, attrs, data, current_element, kw, subelem->dest);
+                    break;
+                case YANG_MODIFIER:
+                    ret = yin_parse_modifier(ctx, attrs, data, (const char **)subelem->dest, exts);
+                    break;
+                case YANG_MUST:
+                    ret = yin_parse_must(ctx, attrs, data, (struct lysp_restr **)subelem->dest);
+                    break;
+                case YANG_NAMESPACE:
+                    ret = yin_parse_simple_elem(ctx, attrs, data, kw, subelem, YIN_ARG_URI, Y_STR_ARG, exts);
+                    break;
+                case YANG_NOTIFICATION:
+                    ret = yin_parse_notification(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+                    break;
+                case YANG_ORDERED_BY:
+                    ret = yin_parse_orderedby(ctx, attrs, data, (uint16_t *)subelem->dest, exts);
+                    break;
+                case YANG_PATH:
+                    ret = yin_parse_path(ctx, attrs, data, kw, (struct lysp_type *)subelem->dest);
+                    break;
+                case YANG_PATTERN:
+                    ret = yin_parse_pattern(ctx, attrs, data, (struct lysp_type *)subelem->dest);
+                    break;
+                case YANG_VALUE:
+                case YANG_POSITION:
+                    ret = yin_parse_value_pos(ctx, attrs, data, kw, (struct lysp_type_enum *)subelem->dest);
+                    break;
+                case YANG_PREFIX:
+                    ret = yin_parse_simple_elem(ctx, attrs, data, kw, subelem, YIN_ARG_VALUE, Y_IDENTIF_ARG, exts);
+                    break;
+                case YANG_RANGE:
+                    ret = yin_parse_range(ctx, attrs, data, (struct lysp_type *)subelem->dest);
+                    break;
+                case YANG_REFINE:
+                    ret = yin_parse_refine(ctx, attrs, data, (struct lysp_refine **)subelem->dest);
+                    break;
+                case YANG_REQUIRE_INSTANCE:
+                    ret = yin_pasrse_reqinstance(ctx, attrs, data, (struct lysp_type *)subelem->dest);
+                    break;
+                case YANG_REVISION:
+                    ret = yin_parse_revision(ctx, attrs, data, (struct lysp_revision **)subelem->dest);
+                    break;
+                case YANG_REVISION_DATE:
+                    ret = yin_parse_revision_date(ctx, attrs, data, (char *)subelem->dest, exts);
+                    break;
+                case YANG_STATUS:
+                    ret = yin_parse_status(ctx, attrs, data, (uint16_t *)subelem->dest, exts);
+                    break;
+                case YANG_TYPE:
+                    ret = yin_parse_type(ctx, attrs, data, current_element, subelem);
+                    break;
+                case YANG_TYPEDEF:
+                    ret = yin_parse_typedef(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+                    break;
+                case YANG_UNIQUE:
+                    ret = yin_parse_simple_elem(ctx, attrs, data, kw, subelem, YIN_ARG_TAG, Y_STR_ARG, exts);
+                    break;
+                case YANG_USES:
+                    ret = yin_parse_uses(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+                    break;
+                case YANG_WHEN:
+                    ret = yin_parse_when(ctx, attrs, data, (struct lysp_when **)subelem->dest);
+                    break;
+                case YANG_YANG_VERSION:
+                    ret = yin_parse_yangversion(ctx, attrs, data, (uint8_t *)subelem->dest, exts);
+                    break;
+                case YANG_YIN_ELEMENT:
+                    ret = yin_parse_yin_element(ctx, attrs, data, (uint16_t *)subelem->dest, exts);
+                    break;
+                case YIN_TEXT:
+                case YIN_VALUE:
+                    ret = yin_parse_content(ctx, NULL, 0, data, kw, (const char **)subelem->dest, NULL);
+                    break;
+                default:
+                    LOGINT(ctx->xml_ctx.ctx);
+                    ret = LY_EINT;
+                }
+                LY_CHECK_GOTO(ret, cleanup);
+                FREE_ARRAY(ctx, attrs, free_arg_rec);
+                attrs = NULL;
+                subelem = NULL;
+            }
+        } else {
+            LY_CHECK_RET(ret);
+            /* elements with text or none content */
+            /* save text content, if text_content isn't set, it's just ignored */
+            /* no resources are allocated in this branch, no need to use cleanup label */
+            LY_CHECK_RET(yin_validate_value(ctx, Y_STR_ARG, out, out_len));
+            if (text_content) {
+                INSERT_STRING(ctx->xml_ctx.ctx, *text_content, dynamic, out, out_len);
+                LY_CHECK_RET(!*text_content, LY_EMEM);
+            }
+            /* load closing element */
+            LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len));
+        }
+    }
+    /* mandatory subelemnts are checked only after whole element was succesfully parsed */
+    LY_CHECK_RET(yin_check_subelem_mandatory_constraint(ctx, subelem_info, subelem_info_size, current_element));
+
+cleanup:
+    FREE_ARRAY(ctx, attrs, free_arg_rec);
+    return ret;
+}
+
+LY_ERR
+yin_parse_extension_instance(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, const char *ext_name,
+                             int ext_name_len, LYEXT_SUBSTMT subelem, uint32_t subelem_index, struct lysp_ext_instance **exts)
+{
+    LY_ERR ret = LY_SUCCESS;
+    char *out;
+    const char *name, *prefix;
+    size_t out_len, prefix_len, name_len;
+    int dynamic;
+    struct lysp_ext_instance *e;
+    struct lysp_stmt *last_subelem = NULL, *new_subelem = NULL;
+    struct yin_arg_record *iter;
+
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *exts, e, LY_EMEM);
+
+    e->yin = 0;
+    /* store name and insubstmt info */
+    e->name = lydict_insert(ctx->xml_ctx.ctx, ext_name, ext_name_len);
+    e->insubstmt = subelem;
+    e->insubstmt_index = subelem_index;
+    e->yin |= LYS_YIN;
+
+    /* store attributes as subelements */
+    LY_ARRAY_FOR_ITER(attrs, struct yin_arg_record, iter) {
+        if (!iter->prefix) {
+            new_subelem = calloc(1, sizeof(*new_subelem));
+            if (!e->child) {
+                e->child = new_subelem;
+            } else {
+                last_subelem->next = new_subelem;
+            }
+            last_subelem = new_subelem;
+
+            last_subelem->flags |= LYS_YIN_ATTR;
+            last_subelem->stmt = lydict_insert(ctx->xml_ctx.ctx, iter->name, iter->name_len);
+            LY_CHECK_RET(!last_subelem->stmt, LY_EMEM);
+
+            INSERT_STRING(ctx->xml_ctx.ctx, last_subelem->arg, iter->dynamic_content, iter->content, iter->content_len);
+            LY_CHECK_RET(!last_subelem->arg, LY_EMEM);
+        }
+    }
+
+    /* parse subelements */
+    if (ctx->xml_ctx.status == LYXML_ELEM_CONTENT) {
+        ret = lyxml_get_string(&ctx->xml_ctx, data, &out, &out_len, &out, &out_len, &dynamic);
+        if (ret == LY_EINVAL) {
+            while (ctx->xml_ctx.status == LYXML_ELEMENT) {
+                LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len));
+                if (!name) {
+                    /* end of extension instance reached */
+                    break;
+                }
+                LY_CHECK_RET(yin_parse_element_generic(ctx, name2fname(name, prefix_len),
+                                                       len2flen(name_len, prefix_len), data, &new_subelem));
+                if (!e->child) {
+                    e->child = new_subelem;
+                } else {
+                    last_subelem->next = new_subelem;
+                }
+                last_subelem = new_subelem;
+            }
+        } else {
+            if (out_len != 0) {
+                /* save text content */
+                LY_CHECK_RET(ret);
+
+                INSERT_STRING(ctx->xml_ctx.ctx, e->argument, dynamic, out, out_len);
+                LY_CHECK_RET(!e->argument, LY_EMEM);
+
+                /* load closing element */
+                LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len));
+                LY_CHECK_RET(name, LY_EINT);
+            }
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+LY_ERR
+yin_parse_element_generic(struct yin_parser_ctx *ctx, const char *name, size_t name_len, const char **data,
+                          struct lysp_stmt **element)
+{
+    LY_ERR ret = LY_SUCCESS;
+    const char *temp_prefix, *temp_name;
+    char *out = NULL;
+    size_t out_len, temp_name_len, temp_prefix_len, prefix_len;
+    int dynamic;
+    struct lysp_stmt *last = NULL, *new = NULL;
+
+    /* allocate new structure for element */
+    *element = calloc(1, sizeof(**element));
+    LY_CHECK_ERR_RET(!(*element), LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+    (*element)->stmt = lydict_insert(ctx->xml_ctx.ctx, name, name_len);
+    LY_CHECK_RET(!(*element)->stmt, LY_EMEM);
+
+    last = (*element)->child;
+    /* load attributes */
+    while(ctx->xml_ctx.status == LYXML_ATTRIBUTE) {
+        /* add new element to linked-list */
+        new = calloc(1, sizeof(*last));
+        LY_CHECK_ERR_RET(!new, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+        if (!(*element)->child) {
+            /* save first */
+            (*element)->child = new;
+        } else {
+            last->next = new;
+        }
+        last = new;
+
+        last->flags |= LYS_YIN_ATTR;
+        LY_CHECK_RET(lyxml_get_attribute(&ctx->xml_ctx, data, &temp_prefix, &prefix_len, &temp_name, &temp_name_len));
+        last->stmt = lydict_insert(ctx->xml_ctx.ctx, temp_name, temp_name_len);
+        LY_CHECK_RET(!last->stmt, LY_EMEM);
+
+        LY_CHECK_RET(lyxml_get_string(&ctx->xml_ctx, data, &out, &out_len, &out, &out_len, &dynamic));
+        /* attributes with prefix are ignored */
+        if (!temp_prefix) {
+            INSERT_STRING(ctx->xml_ctx.ctx, last->arg, dynamic, out, out_len);
+            LY_CHECK_RET(!last->arg, LY_EMEM);
+        } else {
+            if (dynamic) {
+                free(out);
+            }
+        }
+    }
+
+    /* parse content of element if any */
+    if (ctx->xml_ctx.status == LYXML_ELEM_CONTENT) {
+        ret = lyxml_get_string(&ctx->xml_ctx, data, &out, &out_len, &out, &out_len, &dynamic);
+        if (ret == LY_EINVAL) {
+            while (ctx->xml_ctx.status == LYXML_ELEMENT) {
+                /* parse subelements */
+                LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &temp_prefix, &temp_prefix_len, &temp_name, &temp_name_len));
+                if (!temp_name) {
+                    /* end of element reached */
+                    break;
+                }
+                LY_CHECK_RET(yin_parse_element_generic(ctx, name2fname(temp_name, temp_prefix_len),
+                                                       len2flen(temp_name_len, temp_prefix_len), data, &new));
+                if (!(*element)->child) {
+                    /* save first */
+                    (*element)->child = new;
+                } else {
+                    last->next = new;
+                }
+                last = new;
+            }
+        } else {
+            LY_CHECK_RET(ret);
+            /* save element content */
+            if (out_len != 0) {
+                INSERT_STRING(ctx->xml_ctx.ctx, (*element)->arg, dynamic, out, out_len);
+                LY_CHECK_RET(!(*element)->arg, LY_EMEM);
+            }
+
+            /* read closing tag */
+            LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &temp_prefix, &prefix_len, &temp_name, &temp_name_len));
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+LY_ERR
+yin_parse_mod(struct yin_parser_ctx *ctx, struct yin_arg_record *mod_attrs, const char **data, struct lysp_module *mod)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct yin_subelement *subelems = NULL;
+
+    LY_CHECK_RET(yin_parse_attribute(ctx, mod_attrs, YIN_ARG_NAME, &mod->mod->name, Y_IDENTIF_ARG, YANG_MODULE));
+    LY_CHECK_RET(subelems_allocator(ctx, 28, NULL, &subelems,
+                                            YANG_ANYDATA, &mod->data, YIN_SUBELEM_VER2,
+                                            YANG_ANYXML, &mod->data, 0,
+                                            YANG_AUGMENT, &mod->augments, 0,
+                                            YANG_CHOICE, &mod->data, 0,
+                                            YANG_CONTACT, &mod->mod->contact, YIN_SUBELEM_UNIQUE,
+                                            YANG_CONTAINER, &mod->data, 0,
+                                            YANG_DESCRIPTION, &mod->mod->dsc, YIN_SUBELEM_UNIQUE,
+                                            YANG_DEVIATION, &mod->deviations, 0,
+                                            YANG_EXTENSION, &mod->extensions, 0,
+                                            YANG_FEATURE, &mod->features, 0,
+                                            YANG_GROUPING, &mod->groupings, 0,
+                                            YANG_IDENTITY, &mod->identities, 0,
+                                            YANG_IMPORT, mod->mod->prefix, &mod->imports, 0,
+                                            YANG_INCLUDE, mod->mod->name, &mod->includes, 0,
+                                            YANG_LEAF, &mod->data, 0,
+                                            YANG_LEAF_LIST, &mod->data, 0,
+                                            YANG_LIST, &mod->data, 0,
+                                            YANG_NAMESPACE, &mod->mod->ns, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE,
+                                            YANG_NOTIFICATION, &mod->notifs, 0,
+                                            YANG_ORGANIZATION, &mod->mod->org, YIN_SUBELEM_UNIQUE,
+                                            YANG_PREFIX, &mod->mod->prefix, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE,
+                                            YANG_REFERENCE, &mod->mod->ref, YIN_SUBELEM_UNIQUE,
+                                            YANG_REVISION, &mod->revs, 0,
+                                            YANG_RPC, &mod->rpcs, 0,
+                                            YANG_TYPEDEF, &mod->typedefs, 0,
+                                            YANG_USES, &mod->data, 0,
+                                            YANG_YANG_VERSION, &mod->mod->version, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE,
+                                            YANG_CUSTOM, NULL, 0
+                                   ));
+
+    ret = yin_parse_content(ctx, subelems, 28, data, YANG_MODULE, NULL, &mod->exts);
+    subelems_deallocator(28, subelems);
+
+    return ret;
+}
+
+LY_ERR
+yin_parse_submod(struct yin_parser_ctx *ctx, struct yin_arg_record *mod_attrs, const char **data, struct lysp_submodule *submod)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct yin_subelement *subelems = NULL;
+
+    LY_CHECK_RET(yin_parse_attribute(ctx, mod_attrs, YIN_ARG_NAME, &submod->name, Y_IDENTIF_ARG, YANG_SUBMODULE));
+    LY_CHECK_RET(subelems_allocator(ctx, 27, NULL, &subelems,
+                                        YANG_ANYDATA, &submod->data, YIN_SUBELEM_VER2,
+                                        YANG_ANYXML, &submod->data, 0,
+                                        YANG_AUGMENT, &submod->augments, 0,
+                                        YANG_BELONGS_TO, submod, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE,
+                                        YANG_CHOICE, &submod->data, 0,
+                                        YANG_CONTACT, &submod->contact, YIN_SUBELEM_UNIQUE,
+                                        YANG_CONTAINER, &submod->data, 0,
+                                        YANG_DESCRIPTION, &submod->dsc, YIN_SUBELEM_UNIQUE,
+                                        YANG_DEVIATION, &submod->deviations, 0,
+                                        YANG_EXTENSION, &submod->extensions, 0,
+                                        YANG_FEATURE, &submod->features, 0,
+                                        YANG_GROUPING, &submod->groupings, 0,
+                                        YANG_IDENTITY, &submod->identities, 0,
+                                        YANG_IMPORT, submod->prefix, &submod->imports, 0,
+                                        YANG_INCLUDE, submod->name, &submod->includes, 0,
+                                        YANG_LEAF, &submod->data, 0,
+                                        YANG_LEAF_LIST, &submod->data, 0,
+                                        YANG_LIST, &submod->data, 0,
+                                        YANG_NOTIFICATION, &submod->notifs, 0,
+                                        YANG_ORGANIZATION, &submod->org, YIN_SUBELEM_UNIQUE,
+                                        YANG_REFERENCE, &submod->ref, YIN_SUBELEM_UNIQUE,
+                                        YANG_REVISION, &submod->revs, 0,
+                                        YANG_RPC, &submod->rpcs, 0,
+                                        YANG_TYPEDEF, &submod->typedefs, 0,
+                                        YANG_USES, &submod->data, 0,
+                                        YANG_YANG_VERSION, &submod->version, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE,
+                                        YANG_CUSTOM, NULL, 0
+                                   ));
+
+    ret = yin_parse_content(ctx, subelems, 27, data, YANG_SUBMODULE, NULL, &submod->exts);
+    subelems_deallocator(27, subelems);
+
+    return ret;
+}
+
+LY_ERR
+yin_parse_submodule(struct yin_parser_ctx **yin_ctx, struct ly_ctx *ctx, struct lys_parser_ctx *main_ctx, const char *data, struct lysp_submodule **submod)
+{
+    enum yang_keyword kw = YANG_NONE;
+    LY_ERR ret = LY_SUCCESS;
+    const char *prefix, *name;
+    size_t prefix_len, name_len;
+    struct yin_arg_record *attrs = NULL;
+    struct lysp_submodule *mod_p = NULL;
+
+    /* create context */
+    *yin_ctx = calloc(1, sizeof **yin_ctx);
+    LY_CHECK_ERR_RET(!(*yin_ctx), LOGMEM(ctx), LY_EMEM);
+    (*yin_ctx)->xml_ctx.ctx = ctx;
+    (*yin_ctx)->xml_ctx.line = 1;
+
+    /* map the typedefs and groupings list from main context to the submodule's context */
+    memcpy(&(*yin_ctx)->tpdfs_nodes, &main_ctx->tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
+    memcpy(&(*yin_ctx)->grps_nodes, &main_ctx->grps_nodes, sizeof main_ctx->grps_nodes);
+
+    /* check submodule */
+    ret = lyxml_get_element(&(*yin_ctx)->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+    LY_CHECK_GOTO(ret, cleanup);
+    ret = yin_load_attributes(*yin_ctx, &data, &attrs);
+    LY_CHECK_GOTO(ret, cleanup);
+    kw = yin_match_keyword(*yin_ctx, name, name_len, prefix, prefix_len, YANG_NONE);
+
+    if (kw == YANG_MODULE) {
+        LOGERR(ctx, LY_EDENIED, "Input data contains module in situation when a submodule is expected.");
+        ret = LY_EINVAL;
+        goto cleanup;
+    } else if (kw != YANG_SUBMODULE) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)*yin_ctx, LY_VCODE_MOD_SUBOMD, ly_stmt2str(kw));
+        ret = LY_EVALID;
+        goto cleanup;
+    }
+
+    mod_p = calloc(1, sizeof *mod_p);
+    LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(ctx), cleanup);
+    mod_p->parsing = 1;
+
+    ret = yin_parse_submod(*yin_ctx, attrs, &data, mod_p);
+    LY_CHECK_GOTO(ret, cleanup);
+
+    name = NULL;
+    /* skip possible trailing whitespaces at end of the input */
+    while(*data && isspace(*data)) {
+        data++;
+    }
+    if (*data) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)*yin_ctx, LY_VCODE_TRAILING_SUBMOD, 15, data, strlen(data) > 15 ? "..." : "");
+        ret = LY_EVALID;
+        goto cleanup;
+    }
+
+    mod_p->parsing = 0;
+    *submod = mod_p;
+
+cleanup:
+    if (ret) {
+        lysp_submodule_free(ctx, mod_p);
+        yin_parser_ctx_free(*yin_ctx);
+        *yin_ctx = NULL;
+    }
+
+    FREE_ARRAY(*yin_ctx, attrs, free_arg_rec);
+    return ret;
+}
+
+LY_ERR
+yin_parse_module(struct yin_parser_ctx **yin_ctx, const char *data, struct lys_module *mod)
+{
+    LY_ERR ret = LY_SUCCESS;
+    enum yang_keyword kw = YANG_NONE;
+    struct lysp_module *mod_p = NULL;
+    const char *prefix, *name;
+    size_t prefix_len, name_len;
+    struct yin_arg_record *attrs = NULL;
+
+    /* create context */
+    *yin_ctx = calloc(1, sizeof **yin_ctx);
+    LY_CHECK_ERR_RET(!(*yin_ctx), LOGMEM(mod->ctx), LY_EMEM);
+    (*yin_ctx)->xml_ctx.ctx = mod->ctx;
+    (*yin_ctx)->xml_ctx.line = 1;
+
+    /* check module */
+    ret = lyxml_get_element(&(*yin_ctx)->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+    LY_CHECK_GOTO(ret, cleanup);
+    ret = yin_load_attributes(*yin_ctx, &data, &attrs);
+    LY_CHECK_GOTO(ret, cleanup);
+    kw = yin_match_keyword(*yin_ctx, name, name_len, prefix, prefix_len, YANG_NONE);
+    if (kw == YANG_SUBMODULE) {
+        LOGERR(mod->ctx, LY_EDENIED, "Input data contains submodule which cannot be parsed directly without its main module.");
+        ret = LY_EINVAL;
+        goto cleanup;
+    } else if (kw != YANG_MODULE) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)*yin_ctx, LY_VCODE_MOD_SUBOMD, ly_stmt2str(kw));
+        ret = LY_EVALID;
+        goto cleanup;
+    }
+
+    /* allocate module */
+    mod_p = calloc(1, sizeof *mod_p);
+    LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(mod->ctx), cleanup);
+    mod_p->mod = mod;
+    mod_p->parsing = 1;
+
+    /* parse module substatements */
+    ret = yin_parse_mod(*yin_ctx, attrs, &data, mod_p);
+    LY_CHECK_GOTO(ret, cleanup);
+
+    name = NULL;
+    /* skip possible trailing whitespaces at end of the input */
+    while(*data && isspace(*data)) {
+        data++;
+    }
+    if (*data) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)*yin_ctx, LY_VCODE_TRAILING_MOD, 15, data, strlen(data) > 15 ? "..." : "");
+        ret = LY_EVALID;
+        goto cleanup;
+    }
+
+    mod_p->parsing = 0;
+    mod->parsed = mod_p;
+
+cleanup:
+    if (ret != LY_SUCCESS) {
+        lysp_module_free(mod_p);
+        yin_parser_ctx_free(*yin_ctx);
+        *yin_ctx = NULL;
+    }
+    FREE_ARRAY(*yin_ctx, attrs, free_arg_rec);
+    return ret;
+}
diff --git a/src/parser_yin.h b/src/parser_yin.h
new file mode 100644
index 0000000..7bf278a
--- /dev/null
+++ b/src/parser_yin.h
@@ -0,0 +1,300 @@
+/**
+ * @file parser_yin.h
+ * @author David Sedlák <xsedla1d@stud.fit.vutbr.cz>
+ * @brief YIN parser header file.
+ *
+ * Copyright (c) 2015 - 2019 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.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef LY_PARSER_YIN_H_
+#define LY_PARSER_YIN_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "log.h"
+#include "xml.h"
+
+/* list of yin attribute strings */
+extern const char *const yin_attr_list[];
+#define yin_attr2str(STMT) yin_attr_list[STMT]
+
+#define YIN_NS_URI "urn:ietf:params:xml:ns:yang:yin:1"
+
+/**
+ * @brief Get start of full name including possible prefix.
+ *
+ * @param[in] name Start of name in input data.
+ * @param[in] prefix_len Lenght of prefix.
+ *
+ * @return Pointer to begining of full element name including prefix.
+ */
+#define name2fname(name, prefix_len) (prefix_len != 0 ? name - (prefix_len + 1) : name)
+
+/**
+ * @brief Get length of full name including possible prefix.
+ *
+ * @param[in] name_len Lenght of name without prefix.
+ * @param[in] prefix_len Lenght of prefix.
+ *
+ * @return Lenght of full name including possible prefix and ':' delimiter.
+ */
+#define len2flen(name_len, prefix_len) (prefix_len != 0 ? name_len + prefix_len + 1 : name_len)
+
+#define VALID_VALS1 " Only valid value is \"%s\"."
+#define VALID_VALS2 " Valid values are \"%s\" and \"%s\"."
+#define VALID_VALS3 " Valid values are \"%s\", \"%s\" and \"%s\"."
+#define VALID_VALS4 " Valid values are \"%s\", \"%s\", \"%s\" and \"%s\"."
+
+/* shortcut to determin if keyword can in general be subelement of deviation regardles of it's type */
+#define isdevsub(kw) (kw == YANG_CONFIG || kw == YANG_DEFAULT || kw == YANG_MANDATORY || \
+                      kw == YANG_MAX_ELEMENTS || kw == YANG_MIN_ELEMENTS ||              \
+                      kw == YANG_MUST || kw == YANG_TYPE || kw == YANG_UNIQUE ||         \
+                      kw == YANG_UNITS || kw == YANG_CUSTOM)
+
+/**
+ * @brief insert string into dictionary and store as target.
+ *
+ * @param[in] CTX libyang context.
+ * @param[out] TARGET variable where to store the pointer to the inserted value.
+ * @param[in] DYNAMIC Set to 1 if STR is dynamically allocated, 0 otherwise. If set to 1, zerocopy version of lydict_insert is used.
+ * @param[in] STR string to store.
+ * @param[in] LEN length of the string in WORD to store.
+ */
+#define INSERT_STRING(CTX, TARGET, DYNAMIC, STR, LEN) \
+    if (DYNAMIC) {(TARGET) = lydict_insert_zc(CTX, STR);} \
+    else {(TARGET) = lydict_insert(CTX, LEN ? STR : "", LEN);}
+
+enum yin_argument {
+    YIN_ARG_UNKNOWN = 0,   /**< parsed argument can not be matched with any supported yin argument keyword */
+    YIN_ARG_NAME,          /**< argument name */
+    YIN_ARG_TARGET_NODE,   /**< argument target-node */
+    YIN_ARG_MODULE,        /**< argument module */
+    YIN_ARG_VALUE,         /**< argument value */
+    YIN_ARG_TEXT,          /**< argument text */
+    YIN_ARG_CONDITION,     /**< argument condition */
+    YIN_ARG_URI,           /**< argument uri */
+    YIN_ARG_DATE,          /**< argument data */
+    YIN_ARG_TAG,           /**< argument tag */
+    YIN_ARG_NONE,          /**< empty (special value) */
+};
+
+/**
+ * @brief structure to store instance of xml attribute
+ */
+struct yin_arg_record {
+    const char *prefix;   /**< start of prefix */
+    size_t prefix_len;    /**< length of prefix */
+    const char *name;     /**< start of name */
+    size_t name_len;      /**< length of name */
+    char *content;        /**< start of content */
+    size_t content_len;   /**< length of content */
+    int dynamic_content;  /**< is set to 1 iff content is dynamically allocated 0 otherwise */
+};
+
+/* flags to set constraints of subelements */
+#define YIN_SUBELEM_MANDATORY   0x01    /**< is set when subelement is mandatory */
+#define YIN_SUBELEM_UNIQUE      0x02    /**< is set when subelement is unique */
+#define YIN_SUBELEM_FIRST       0x04    /**< is set when subelement is actually yang argument mapped to yin element */
+#define YIN_SUBELEM_VER2        0x08    /**< subelemnt is allowed only in modules with version at least 2 (YANG 1.1) */
+
+#define YIN_SUBELEM_PARSED      0x80    /**< is set during parsing when given subelement is encountered for the first
+                                             time to simply check validity of given constraints */
+
+struct yin_subelement {
+    enum yang_keyword type; /**< type of keyword */
+    void *dest;             /**< meta infromation passed to responsible function (mostly information about where parsed subelement should be stored) */
+    uint8_t flags;          /**< describes constraints of subelement can be set to YIN_SUBELEM_MANDATORY, YIN_SUBELEM_UNIQUE, YIN_SUBELEM_FIRST and YIN_SUBELEM_VER2 */
+};
+
+/* Meta information passed to yin_parse_argument function,
+   holds information about where content of argument element will be stored. */
+struct yin_argument_meta {
+    uint16_t *flags;        /**< Argument flags */
+    const char **argument;  /**< Argument value */
+};
+
+/**
+ * @brief Meta information passed to functions working with tree_schema,
+ *        that require additional information about parent node.
+ */
+struct tree_node_meta {
+    struct lysp_node *parent;       /**< parent node */
+    struct lysp_node **nodes;    /**< linked list of siblings */
+};
+
+/**
+ * @brief Meta information passed to yin_parse_import function.
+ */
+struct import_meta {
+    const char *prefix;             /**< module prefix. */
+    struct lysp_import **imports;   /**< imports to add to. */
+};
+
+/**
+ * @brief Meta information passed to yin_parse_include function.
+ */
+struct include_meta {
+    const char *name;               /**< Module/submodule name. */
+    struct lysp_include **includes; /**< [Sized array](@ref sizedarrays) of parsed includes to add to. */
+};
+
+/**
+ * @brief Meta information passed to yin_parse_inout function.
+ */
+struct inout_meta {
+    struct lysp_node *parent;          /**< Parent node. */
+    struct lysp_action_inout *inout_p; /**< inout_p Input/output pointer to write to. */
+};
+
+/**
+ * @brief Meta information passed to yin_parse_minmax function.
+ */
+struct minmax_dev_meta {
+    uint32_t *lim;                      /**< min/max value to write to. */
+    uint16_t *flags;                    /**< min/max flags to write to. */
+    struct lysp_ext_instance **exts;    /**< extension instances to add to. */
+};
+
+/**
+ * @brief Match argument name.
+ *
+ * @param[in] name String representing name.
+ * @param[in] len Lenght of the name.
+ *
+ * @return yin_argument values.
+ */
+enum yin_argument yin_match_argument_name(const char *name, size_t len);
+
+/**
+ * @brief Generic function for content parsing
+ *
+ * @param[in,out] ctx Yin parser context for logging and to store current state.
+ * @param[in] subelem_info array of valid subelement types and meta information,
+ *            array must be ordered by subelem_info->type in ascending order.
+ * @param[in] subelem_info_size Size of subelem_info array.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] current_element Type of current element.
+ * @param[out] text_content Where the text content of element should be stored if any. Text content is ignored if set to NULL.
+ * @param[in,out] exts Extension instance to add to. Can be set to null if element cannot have extension as subelements.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_parse_content(struct yin_parser_ctx *ctx, struct yin_subelement *subelem_info, signed char subelem_info_size,
+                         const char **data, enum yang_keyword current_element, const char **text_content,
+                         struct lysp_ext_instance **exts);
+
+/**
+ * @brief Check that val is valid UTF8 character sequence of val_type.
+ *        Doesn't check empty string, only character validity.
+ *
+ * @param[in] ctx Yin parser context for logging.
+ * @param[in] val_type Type of the input string to select method of checking character validity.
+ * @param[in] val Input to validate.
+ * @param[in] len Length of input.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_validate_value(struct yin_parser_ctx *ctx, enum yang_arg val_type, char *val, size_t len);
+
+/**
+ * @brief Match yang keyword from yin data.
+ *
+ * @param[in,out] ctx Yin parser context for logging and to store current state.
+ * @param[in] name Start of keyword name
+ * @param[in] name_len Lenght of keyword name.
+ * @param[in] prefix Start of keyword prefix.
+ * @param[in] prefix_len Lenght of prefix.
+ * @param[in] parrent Identification of parrent element, use YANG_NONE for elements without parrent.
+ *
+ * @return yang_keyword values.
+ */
+enum yang_keyword yin_match_keyword(struct yin_parser_ctx *ctx, const char *name, size_t name_len,
+                                    const char *prefix, size_t prefix_len, enum yang_keyword parrent);
+
+/**
+ * @brief Load all attributes of element into ([sized array](@ref sizedarrays)). Caller is suposed to free the array.
+ *
+ * @param[in,out] ctx Yin parser context for logging and to store current state.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[out] attrs ([Sized array](@ref sizedarrays)) of attributes.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_load_attributes(struct yin_parser_ctx *ctx, const char **data, struct yin_arg_record **attrs);
+
+/**
+ * @brief Parse instance of extension.
+ *
+ * @param[in,out] ctx Yin parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of extension instance.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] ext_name Name of the extension element.
+ * @param[in] ext_name_len Length of extension name.
+ * @param[in] subelem Type of the keyword this extension instance is a subelement of.
+ * @param[in] subelem_index Index of the keyword instance this extension instance is a subelement of
+ * @param[in,out] exts Extension instance to add to.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_parse_extension_instance(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                                    const char *ext_name, int ext_name_len, LYEXT_SUBSTMT subelem,
+                                    uint32_t subelem_index, struct lysp_ext_instance **exts);
+
+/**
+ * @brief Parse yin element into generic structure.
+ *
+ * @param[in,out] ctx Yin parser context for logging and to store current state.
+ * @param[in] name Name of element.
+ * @param[in] name_len Length of elements Name.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[out] element Where the element structure should be stored.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_parse_element_generic(struct yin_parser_ctx *ctx, const char *name, size_t name_len, const char **data,
+                                 struct lysp_stmt **element);
+
+/**
+ * @brief Parse module element.
+ *
+ * @param[in,out] ctx Yin parser context for logging and to store current state.
+ * @param[in] mod_attrs Attributes of module element.
+ * @param[in,out] data Data to read from.
+ * @param[out] mod Parsed module structure.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_parse_mod(struct yin_parser_ctx *ctx, struct yin_arg_record *mod_attrs,
+                     const char **data, struct lysp_module *mod);
+
+
+/**
+ * @brief Parse submodule element.
+ *
+ * @param[in,out] ctx Yin parser context for logging and to store current state.
+ * @param[in] mod_attrs Attributes of submodule element.
+ * @param[in,out] data Data to read from.
+ * @param[out] submod Parsed submodule structure.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_parse_submod(struct yin_parser_ctx *ctx, struct yin_arg_record *mod_attrs,
+                        const char **data, struct lysp_submodule *submod);
+
+/**
+ * @brief free argument record, content loaded from lyxml_get_string() can be
+ * dynamically allocated in some cases so it must be also freed.
+ *
+ * @param ctx unused just to fulfill signature of callback for FREE_ARRAY.
+ * @param[in] record Record to free.
+ */
+void free_arg_rec(struct yin_parser_ctx *ctx, struct yin_arg_record *record);
+
+#endif /* LY_PARSER_YIN_H_*/
diff --git a/src/printer_yang.c b/src/printer_yang.c
index a3242a6..65ce5b5 100755
--- a/src/printer_yang.c
+++ b/src/printer_yang.c
@@ -229,7 +229,9 @@
         if (!count) {
             break;
         }
-        if (ext->insubstmt == substmt && ext->insubstmt_index == substmt_index) {
+        if (ext->yin) {
+            ly_print(ctx->out, "%*s%s Model comes from different input format, extensions must be resolved first.", INDENT, ext[u].name);
+        } else if (ext->insubstmt == substmt && ext->insubstmt_index == substmt_index) {
             ypr_open(ctx->out, flag);
             if (ext[u].argument) {
                 ly_print(ctx->out, "%*s%s %s%s", INDENT, ext[u].name, ext[u].argument, ext[u].child ? " {\n" : ";\n");
diff --git a/src/tree_schema.c b/src/tree_schema.c
index ad8e695..3fc8b08 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -595,28 +595,21 @@
 {
     LY_ERR ret = LY_EINVAL;
     struct lysp_submodule *submod = NULL, *latest_sp;
-    struct lys_parser_ctx context = {0};
+    struct lys_parser_ctx *context = NULL;
+    struct yin_parser_ctx *yin_context = NULL;
 
     LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
 
-    context.ctx = ctx;
-    context.line = 1;
-
-    /* map the typedefs and groupings list from main context to the submodule's context */
-    memcpy(&context.tpdfs_nodes, &main_ctx->tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
-    memcpy(&context.grps_nodes, &main_ctx->grps_nodes, sizeof main_ctx->grps_nodes);
-
     switch (format) {
-    /* TODO not yet supported
     case LYS_IN_YIN:
-        mod = yin_read_module();
+        ret = yin_parse_submodule(&yin_context, ctx, main_ctx, data, &submod);
+        context = (struct lys_parser_ctx *)yin_context;
         break;
-    */
     case LYS_IN_YANG:
-        ret = yang_parse_submodule(&context, data, &submod);
+        ret = yang_parse_submodule(&context, ctx, main_ctx, data, &submod);
         break;
     default:
-        LOGERR(context.ctx, LY_EINVAL, "Invalid schema input format.");
+        LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
         break;
     }
     LY_CHECK_RET(ret, NULL);
@@ -625,11 +618,11 @@
     lysp_sort_revisions(submod->revs);
 
     if (custom_check) {
-        LY_CHECK_GOTO(custom_check(context.ctx, NULL, submod, check_data), error);
+        LY_CHECK_GOTO(custom_check((*context).ctx, NULL, submod, check_data), error);
     }
 
     /* decide the latest revision */
-    latest_sp = ly_ctx_get_submodule(context.ctx, submod->belongsto, submod->name, NULL);
+    latest_sp = ly_ctx_get_submodule((*context).ctx, submod->belongsto, submod->name, NULL);
     if (latest_sp) {
         if (submod->revs) {
             if (!latest_sp->revs) {
@@ -648,12 +641,23 @@
     }
 
     /* remap possibly changed and reallocated typedefs and groupings list back to the main context */
-    memcpy(&main_ctx->tpdfs_nodes, &context.tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
-    memcpy(&main_ctx->grps_nodes, &context.grps_nodes, sizeof main_ctx->grps_nodes);
+    memcpy(&main_ctx->tpdfs_nodes, &(*context).tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
+    memcpy(&main_ctx->grps_nodes, &(*context).grps_nodes, sizeof main_ctx->grps_nodes);
 
+    if (format == LYS_IN_YANG) {
+        lys_parser_ctx_free(context);
+    } else {
+        yin_parser_ctx_free(yin_context);
+    }
     return submod;
+
 error:
     lysp_submodule_free(ctx, submod);
+    if (format == LYS_IN_YANG) {
+        lys_parser_ctx_free(context);
+    } else {
+        yin_parser_ctx_free(yin_context);
+    }
     return NULL;
 }
 
@@ -667,23 +671,20 @@
     struct lysp_include *inc;
     LY_ERR ret = LY_EINVAL;
     unsigned int u, i;
-    struct lys_parser_ctx context = {0};
+    struct lys_parser_ctx *context = NULL;
+    struct yin_parser_ctx *yin_context = NULL;
 
     LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
 
-    context.ctx = ctx;
-    context.line = 1;
-
     mod = calloc(1, sizeof *mod);
     LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), NULL);
     mod->ctx = ctx;
 
     switch (format) {
-    /* TODO not yet supported
     case LYS_IN_YIN:
-        mod = yin_read_module();
+        ret = yin_parse_module(&yin_context, data, mod);
+        context = (struct lys_parser_ctx *)yin_context;
         break;
-    */
     case LYS_IN_YANG:
         ret = yang_parse_module(&context, data, mod);
         break;
@@ -794,7 +795,7 @@
     }
     LY_ARRAY_FOR(mod->parsed->includes, u) {
         inc = &mod->parsed->includes[u];
-        if (!inc->submodule && lysp_load_submodule(&context, mod->parsed, inc)) {
+        if (!inc->submodule && lysp_load_submodule(context, mod->parsed, inc)) {
             goto error_ctx;
         }
         if (!mod->implemented) {
@@ -806,15 +807,26 @@
     mod->parsed->parsing = 0;
 
     /* check name collisions - typedefs and TODO groupings */
-    LY_CHECK_GOTO(lysp_check_typedefs(&context, mod->parsed), error_ctx);
+    LY_CHECK_GOTO(lysp_check_typedefs(context, mod->parsed), error_ctx);
 
+    if (format == LYS_IN_YANG) {
+        lys_parser_ctx_free(context);
+    } else {
+        yin_parser_ctx_free(yin_context);
+    }
     return mod;
 
 error_ctx:
     ly_set_rm(&ctx->list, mod, NULL);
 error:
     lys_module_free(mod, NULL);
-    ly_set_erase(&context.tpdfs_nodes, NULL);
+    ly_set_erase(&context->tpdfs_nodes, NULL);
+    if (format == LYS_IN_YANG) {
+        lys_parser_ctx_free(context);
+    } else {
+        yin_parser_ctx_free(yin_context);
+    }
+
     return NULL;
 }
 
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 050c7be..4a3dbec 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -294,19 +294,22 @@
     const char *arg;                 /**< statement's argument */
     struct lysp_stmt *next;          /**< link to the next statement */
     struct lysp_stmt *child;         /**< list of the statement's substatements (linked list) */
-    uint16_t flags;
+    uint16_t flags;                  /**< statement flags, can be set to LYS_YIN_ATTR */
 };
 
+#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 */
-    struct lysp_stmt *child;         /**< list of the extension's substatements (linked list) */
-    LYEXT_SUBSTMT insubstmt;         /**< value identifying placement of the extension instance */
-    uint32_t insubstmt_index;        /**< in case the instance is in a substatement, this identifies
-                                          the index of that substatement */
+    const char *name;                       /**< extension identifier, including possible prefix */
+    const char *argument;                   /**< optional value of the extension's argument */
+    struct lysp_stmt *child;                /**< list of the extension's substatements (linked list) */
+    LYEXT_SUBSTMT insubstmt;                /**< value identifying placement of the extension instance */
+    uint32_t insubstmt_index;               /**< in case the instance is in a substatement, this identifies
+                                                 the index of that substatement */
+    uint8_t yin;                            /** flag for YIN source format, can be set to LYS_YIN */
 };
 
 /**
@@ -513,7 +516,6 @@
     struct lysp_restr *musts;        /**< list of must restrictions ([sized array](@ref sizedarrays)) */
     const char **uniques;            /**< list of uniques specifications ([sized array](@ref sizedarrays)) */
     const char **dflts;              /**< list of default values ([sized array](@ref sizedarrays)) */
-    uint16_t flags;                  /**< [schema node flags](@ref snodeflags) */
 };
 
 struct lysp_deviate_rpl {
@@ -588,6 +590,7 @@
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *      11 LYS_SET_MAX      | | | |x|x| | | | | | | | | | | | |x| |x| | | |
  *         LYS_USED_GRP     | | | | | | | | | | | | | | | |x| | | | | | | |
+ *         LYS_YIN_ATTR     | | | | | | | | | | | | | | | | | | | | | | |x|
  *     ---------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *
  */
@@ -701,6 +704,8 @@
 #define LYS_SINGLEQUOTED 0x100       /**< flag for single-quoted argument of an extension instance's substatement */
 #define LYS_DOUBLEQUOTED 0x200       /**< flag for double-quoted argument of an extension instance's substatement */
 
+#define LYS_YIN_ATTR     0x400       /**< flag to identify YIN attribute */
+
 #define LYS_ISENUM       0x200       /**< flag to simply distinguish type in struct lysc_type_bitenum_item */
 
 #define LYS_FLAGS_COMPILED_MASK 0xff /**< mask for flags that maps to the compiled structures */
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index 64728f2..68c8252 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -54,7 +54,7 @@
     }
 }
 
-static void
+void
 lysp_import_free(struct ly_ctx *ctx, struct lysp_import *import)
 {
     /* imported module is freed directly from the context's list */
@@ -65,7 +65,7 @@
     FREE_ARRAY(ctx, import->exts, lysp_ext_instance_free);
 }
 
-static void
+void
 lysp_include_free(struct ly_ctx *ctx, struct lysp_include *include)
 {
     if (include->submodule) {
@@ -77,7 +77,7 @@
     FREE_ARRAY(ctx, include->exts, lysp_ext_instance_free);
 }
 
-static void
+void
 lysp_revision_free(struct ly_ctx *ctx, struct lysp_revision *rev)
 {
     FREE_STRING(ctx, rev->dsc);
@@ -85,7 +85,7 @@
     FREE_ARRAY(ctx, rev->exts, lysp_ext_instance_free);
 }
 
-static void
+void
 lysp_ext_free(struct ly_ctx *ctx, struct lysp_ext *ext)
 {
     FREE_STRING(ctx, ext->name);
@@ -138,7 +138,7 @@
 }
 
 void lysc_type_free(struct ly_ctx *ctx, struct lysc_type *type);
-static void
+void
 lysp_type_free(struct ly_ctx *ctx, struct lysp_type *type)
 {
     FREE_STRING(ctx, type->name);
@@ -156,7 +156,7 @@
     }
 }
 
-static void
+void
 lysp_tpdf_free(struct ly_ctx *ctx, struct lysp_tpdf *tpdf)
 {
     FREE_STRING(ctx, tpdf->name);
@@ -306,7 +306,7 @@
     FREE_ARRAY(ctx, dev->exts, lysp_ext_instance_free);
 }
 
-static void
+void
 lysp_refine_free(struct ly_ctx *ctx, struct lysp_refine *ref)
 {
     FREE_STRING(ctx, ref->nodeid);
@@ -871,3 +871,20 @@
 
     free(module);
 }
+
+void
+lys_parser_ctx_free(struct lys_parser_ctx *ctx)
+{
+    if (ctx) {
+        free(ctx);
+    }
+}
+
+void
+yin_parser_ctx_free(struct yin_parser_ctx *ctx)
+{
+    if (ctx) {
+        lyxml_context_clear(&ctx->xml_ctx);
+        free(ctx);
+    }
+}
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 2f8a2b8..46d7801 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -424,6 +424,29 @@
     return LY_ENOTFOUND;
 }
 
+LY_ERR
+lysp_check_enum_name(struct lys_parser_ctx *ctx, const char *name, size_t name_len)
+{
+    if (!name_len) {
+        LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Enum name must not be zero-length.");
+        return LY_EVALID;
+    } else if (isspace(name[0]) || isspace(name[name_len - 1])) {
+        LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Enum name must not have any leading or trailing whitespaces (\"%.*s\").",
+                    name_len, name);
+        return LY_EVALID;
+    } else {
+        for (size_t u = 0; u < name_len; ++u) {
+            if (iscntrl(name[u])) {
+                LOGWRN(ctx->ctx, "Control characters in enum name should be avoided (\"%.*s\", character number %d).",
+                    name_len, name, u + 1);
+                break;
+            }
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
 /*
  * @brief Check name of a new type to avoid name collisions.
  *
@@ -512,6 +535,97 @@
 }
 
 LY_ERR
+lysp_parse_finalize_reallocated(struct lys_parser_ctx *ctx, struct lysp_grp *groupings, struct lysp_augment *augments,
+                                struct lysp_action *actions, struct lysp_notif *notifs)
+{
+    unsigned int u, v;
+    struct lysp_node *child;
+
+    /* finalize parent pointers to the reallocated items */
+
+    /* gropings */
+    LY_ARRAY_FOR(groupings, u) {
+        LY_LIST_FOR(groupings[u].data, child) {
+            child->parent = (struct lysp_node*)&groupings[u];
+        }
+        LY_ARRAY_FOR(groupings[u].actions, v) {
+            groupings[u].actions[v].parent = (struct lysp_node*)&groupings[u];
+        }
+        LY_ARRAY_FOR(groupings[u].notifs, v) {
+            groupings[u].notifs[v].parent = (struct lysp_node*)&groupings[u];
+        }
+        LY_ARRAY_FOR(groupings[u].groupings, v) {
+            groupings[u].groupings[v].parent = (struct lysp_node*)&groupings[u];
+        }
+        if (groupings[u].typedefs) {
+            ly_set_add(&ctx->tpdfs_nodes, &groupings[u], 0);
+        }
+    }
+
+    /* augments */
+    LY_ARRAY_FOR(augments, u) {
+        LY_LIST_FOR(augments[u].child, child) {
+            child->parent = (struct lysp_node*)&augments[u];
+        }
+        LY_ARRAY_FOR(augments[u].actions, v) {
+            augments[u].actions[v].parent = (struct lysp_node*)&augments[u];
+        }
+        LY_ARRAY_FOR(augments[u].notifs, v) {
+            augments[u].notifs[v].parent = (struct lysp_node*)&augments[u];
+        }
+    }
+
+    /* actions */
+    LY_ARRAY_FOR(actions, u) {
+        if (actions[u].input.parent) {
+            actions[u].input.parent = (struct lysp_node*)&actions[u];
+            LY_LIST_FOR(actions[u].input.data, child) {
+                child->parent = (struct lysp_node*)&actions[u].input;
+            }
+            LY_ARRAY_FOR(actions[u].input.groupings, v) {
+                actions[u].input.groupings[v].parent = (struct lysp_node*)&actions[u].input;
+            }
+            if (actions[u].input.typedefs) {
+                ly_set_add(&ctx->tpdfs_nodes, &actions[u].input, 0);
+            }
+        }
+        if (actions[u].output.parent) {
+            actions[u].output.parent = (struct lysp_node*)&actions[u];
+            LY_LIST_FOR(actions[u].output.data, child) {
+                child->parent = (struct lysp_node*)&actions[u].output;
+            }
+            LY_ARRAY_FOR(actions[u].output.groupings, v) {
+                actions[u].output.groupings[v].parent = (struct lysp_node*)&actions[u].output;
+            }
+            if (actions[u].output.typedefs) {
+                ly_set_add(&ctx->tpdfs_nodes, &actions[u].output, 0);
+            }
+        }
+        LY_ARRAY_FOR(actions[u].groupings, v) {
+            actions[u].groupings[v].parent = (struct lysp_node*)&actions[u];
+        }
+        if (actions[u].typedefs) {
+            ly_set_add(&ctx->tpdfs_nodes, &actions[u], 0);
+        }
+    }
+
+    /* notifications */
+    LY_ARRAY_FOR(notifs, u) {
+        LY_LIST_FOR(notifs[u].data, child) {
+            child->parent = (struct lysp_node*)&notifs[u];
+        }
+        LY_ARRAY_FOR(notifs[u].groupings, v) {
+            notifs[u].groupings[v].parent = (struct lysp_node*)&notifs[u];
+        }
+        if (notifs[u].typedefs) {
+            ly_set_add(&ctx->tpdfs_nodes, &notifs[u], 0);
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+LY_ERR
 lysp_check_typedefs(struct lys_parser_ctx *ctx, struct lysp_module *mod)
 {
     struct hash_table *ids_global;
@@ -796,6 +910,41 @@
 }
 
 LY_ERR
+lysp_check_stringchar(struct lys_parser_ctx *ctx, unsigned int c)
+{
+    if (!is_yangutf8char(c)) {
+        LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, c);
+        return LY_EVALID;
+    }
+    return LY_SUCCESS;
+}
+
+LY_ERR
+lysp_check_identifierchar(struct lys_parser_ctx *ctx, unsigned int c, int first, int *prefix)
+{
+    if (first || (prefix && (*prefix) == 1)) {
+        if (!is_yangidentstartchar(c)) {
+            LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Invalid identifier first character '%c'.", c);
+            return LY_EVALID;
+        }
+        if (prefix) {
+            if (first) {
+                (*prefix) = 0;
+            } else {
+                (*prefix) = 2;
+            }
+        }
+    } else if (c == ':' && prefix && (*prefix) == 0) {
+        (*prefix) = 1;
+    } else if (!is_yangidentchar(c)) {
+        LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Invalid identifier character '%c'.", c);
+        return LY_EVALID;
+    }
+
+    return LY_SUCCESS;
+}
+
+LY_ERR
 lysp_load_submodule(struct lys_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
 {
     struct lysp_submodule *submod = NULL;
@@ -1261,6 +1410,210 @@
     return NULL;
 }
 
+enum yang_keyword
+lysp_match_kw(struct lys_parser_ctx *ctx, const char **data)
+{
+/**
+ * @brief Move the DATA pointer by COUNT items. Also updates the indent value in yang parser context
+ * @param[in] CTX yang parser context to update its indent value.
+ * @param[in,out] DATA pointer to move
+ * @param[in] COUNT number of items for which the DATA pointer is supposed to move on.
+ */
+#define MOVE_IN(CTX, DATA, COUNT) (*(DATA))+=COUNT;if(CTX){(CTX)->indent+=COUNT;}
+#define IF_KW(STR, LEN, STMT) if (!strncmp(*(data), STR, LEN)) {MOVE_IN(ctx, data, LEN);*kw=STMT;}
+#define IF_KW_PREFIX(STR, LEN) if (!strncmp(*(data), STR, LEN)) {MOVE_IN(ctx, data, LEN);
+#define IF_KW_PREFIX_END }
+
+    enum yang_keyword result = YANG_NONE;
+    enum yang_keyword *kw = &result;
+    /* read the keyword itself */
+    switch (**data) {
+    case 'a':
+        MOVE_IN(ctx, data, 1);
+        IF_KW("rgument", 7, YANG_ARGUMENT)
+        else IF_KW("ugment", 6, YANG_AUGMENT)
+        else IF_KW("ction", 5, YANG_ACTION)
+        else IF_KW_PREFIX("ny", 2)
+            IF_KW("data", 4, YANG_ANYDATA)
+            else IF_KW("xml", 3, YANG_ANYXML)
+        IF_KW_PREFIX_END
+        break;
+    case 'b':
+        MOVE_IN(ctx, data, 1);
+        IF_KW("ase", 3, YANG_BASE)
+        else IF_KW("elongs-to", 9, YANG_BELONGS_TO)
+        else IF_KW("it", 2, YANG_BIT)
+        break;
+    case 'c':
+        MOVE_IN(ctx, data, 1);
+        IF_KW("ase", 3, YANG_CASE)
+        else IF_KW("hoice", 5, YANG_CHOICE)
+        else IF_KW_PREFIX("on", 2)
+            IF_KW("fig", 3, YANG_CONFIG)
+            else IF_KW_PREFIX("ta", 2)
+                IF_KW("ct", 2, YANG_CONTACT)
+                else IF_KW("iner", 4, YANG_CONTAINER)
+            IF_KW_PREFIX_END
+        IF_KW_PREFIX_END
+        break;
+    case 'd':
+        MOVE_IN(ctx, data, 1);
+        IF_KW_PREFIX("e", 1)
+            IF_KW("fault", 5, YANG_DEFAULT)
+            else IF_KW("scription", 9, YANG_DESCRIPTION)
+            else IF_KW_PREFIX("viat", 4)
+                IF_KW("e", 1, YANG_DEVIATE)
+                else IF_KW("ion", 3, YANG_DEVIATION)
+            IF_KW_PREFIX_END
+        IF_KW_PREFIX_END
+        break;
+    case 'e':
+        MOVE_IN(ctx, data, 1);
+        IF_KW("num", 3, YANG_ENUM)
+        else IF_KW_PREFIX("rror-", 5)
+            IF_KW("app-tag", 7, YANG_ERROR_APP_TAG)
+            else IF_KW("message", 7, YANG_ERROR_MESSAGE)
+        IF_KW_PREFIX_END
+        else IF_KW("xtension", 8, YANG_EXTENSION)
+        break;
+    case 'f':
+        MOVE_IN(ctx, data, 1);
+        IF_KW("eature", 6, YANG_FEATURE)
+        else IF_KW("raction-digits", 14, YANG_FRACTION_DIGITS)
+        break;
+    case 'g':
+        MOVE_IN(ctx, data, 1);
+        IF_KW("rouping", 7, YANG_GROUPING)
+        break;
+    case 'i':
+        MOVE_IN(ctx, data, 1);
+        IF_KW("dentity", 7, YANG_IDENTITY)
+        else IF_KW("f-feature", 9, YANG_IF_FEATURE)
+        else IF_KW("mport", 5, YANG_IMPORT)
+        else IF_KW_PREFIX("n", 1)
+            IF_KW("clude", 5, YANG_INCLUDE)
+            else IF_KW("put", 3, YANG_INPUT)
+        IF_KW_PREFIX_END
+        break;
+    case 'k':
+        MOVE_IN(ctx, data, 1);
+        IF_KW("ey", 2, YANG_KEY)
+        break;
+    case 'l':
+        MOVE_IN(ctx, data, 1);
+        IF_KW_PREFIX("e", 1)
+            IF_KW("af-list", 7, YANG_LEAF_LIST)
+            else IF_KW("af", 2, YANG_LEAF)
+            else IF_KW("ngth", 4, YANG_LENGTH)
+        IF_KW_PREFIX_END
+        else IF_KW("ist", 3, YANG_LIST)
+        break;
+    case 'm':
+        MOVE_IN(ctx, data, 1);
+        IF_KW_PREFIX("a", 1)
+            IF_KW("ndatory", 7, YANG_MANDATORY)
+            else IF_KW("x-elements", 10, YANG_MAX_ELEMENTS)
+        IF_KW_PREFIX_END
+        else IF_KW("in-elements", 11, YANG_MIN_ELEMENTS)
+        else IF_KW("ust", 3, YANG_MUST)
+        else IF_KW_PREFIX("od", 2)
+            IF_KW("ule", 3, YANG_MODULE)
+            else IF_KW("ifier", 5, YANG_MODIFIER)
+        IF_KW_PREFIX_END
+        break;
+    case 'n':
+        MOVE_IN(ctx, data, 1);
+        IF_KW("amespace", 8, YANG_NAMESPACE)
+        else IF_KW("otification", 11, YANG_NOTIFICATION)
+        break;
+    case 'o':
+        MOVE_IN(ctx, data, 1);
+        IF_KW_PREFIX("r", 1)
+            IF_KW("dered-by", 8, YANG_ORDERED_BY)
+            else IF_KW("ganization", 10, YANG_ORGANIZATION)
+        IF_KW_PREFIX_END
+        else IF_KW("utput", 5, YANG_OUTPUT)
+        break;
+    case 'p':
+        MOVE_IN(ctx, data, 1);
+        IF_KW("ath", 3, YANG_PATH)
+        else IF_KW("attern", 6, YANG_PATTERN)
+        else IF_KW("osition", 7, YANG_POSITION)
+        else IF_KW_PREFIX("re", 2)
+            IF_KW("fix", 3, YANG_PREFIX)
+            else IF_KW("sence", 5, YANG_PRESENCE)
+        IF_KW_PREFIX_END
+        break;
+    case 'r':
+        MOVE_IN(ctx, data, 1);
+        IF_KW("ange", 4, YANG_RANGE)
+        else IF_KW_PREFIX("e", 1)
+            IF_KW_PREFIX("f", 1)
+                IF_KW("erence", 6, YANG_REFERENCE)
+                else IF_KW("ine", 3, YANG_REFINE)
+            IF_KW_PREFIX_END
+            else IF_KW("quire-instance", 14, YANG_REQUIRE_INSTANCE)
+            else IF_KW("vision-date", 11, YANG_REVISION_DATE)
+            else IF_KW("vision", 6, YANG_REVISION)
+        IF_KW_PREFIX_END
+        else IF_KW("pc", 2, YANG_RPC)
+        break;
+    case 's':
+        MOVE_IN(ctx, data, 1);
+        IF_KW("tatus", 5, YANG_STATUS)
+        else IF_KW("ubmodule", 8, YANG_SUBMODULE)
+        break;
+    case 't':
+        MOVE_IN(ctx, data, 1);
+        IF_KW("ypedef", 6, YANG_TYPEDEF)
+        else IF_KW("ype", 3, YANG_TYPE)
+        break;
+    case 'u':
+        MOVE_IN(ctx, data, 1);
+        IF_KW_PREFIX("ni", 2)
+            IF_KW("que", 3, YANG_UNIQUE)
+            else IF_KW("ts", 2, YANG_UNITS)
+        IF_KW_PREFIX_END
+        else IF_KW("ses", 3, YANG_USES)
+        break;
+    case 'v':
+        MOVE_IN(ctx, data, 1);
+        IF_KW("alue", 4, YANG_VALUE)
+        break;
+    case 'w':
+        MOVE_IN(ctx, data, 1);
+        IF_KW("hen", 3, YANG_WHEN)
+        break;
+    case 'y':
+        MOVE_IN(ctx, data, 1);
+        IF_KW("ang-version", 11, YANG_YANG_VERSION)
+        else IF_KW("in-element", 10, YANG_YIN_ELEMENT)
+        break;
+    default:
+        /* if context is not NULL we are matching keyword from YANG data*/
+        if (ctx) {
+            if (**data == ';') {
+                MOVE_IN(ctx, data, 1);
+                *kw = YANG_SEMICOLON;
+            } else if (**data == '{') {
+                MOVE_IN(ctx, data, 1);
+                *kw = YANG_LEFT_BRACE;
+            } else if (**data == '}') {
+                MOVE_IN(ctx, data, 1);
+                *kw = YANG_RIGHT_BRACE;
+            }
+        }
+        break;
+    }
+
+#undef IF_KW
+#undef IF_KW_PREFIX
+#undef IF_KW_PREFIX_END
+#undef MOVE_IN
+
+    return result;
+}
+
 unsigned int
 lysp_ext_instance_iter(struct lysp_ext_instance *ext, unsigned int index, LYEXT_SUBSTMT substmt)
 {
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 8e9e029..1ff883d 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -20,13 +20,51 @@
 #include "plugins_exts.h"
 #include "set.h"
 #include "tree_schema.h"
+#include "xml.h"
 
-#define LOGVAL_YANG(CTX, ...) LOGVAL((CTX)->ctx, LY_VLOG_LINE, &(CTX)->line, __VA_ARGS__)
+#define LOGVAL_PARSER(CTX, ...) LOGVAL((CTX)->ctx, LY_VLOG_LINE, &(CTX)->line, __VA_ARGS__)
 
 /* These 2 macros checks YANG's identifier grammar rule */
 #define is_yangidentstartchar(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')
 #define is_yangidentchar(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || \
-        c == '_' || c == '-' || c == '.')
+                              c == '_' || c == '-' || c == '.')
+
+/* Macro to check YANG's yang-char grammar rule */
+#define is_yangutf8char(c) ((c >= 0x20 && c <= 0xd7ff) || c == 0x09 || c == 0x0a || c == 0x0d || \
+                            (c >= 0xe000 && c <= 0xfdcf)   || (c >= 0xfdf0 && c <= 0xfffd)   || \
+                            (c >= 0x10000 && c <= 0x1fffd) || (c >= 0x20000 && c <= 0x2fffd) || \
+                            (c >= 0x30000 && c <= 0x3fffd) || (c >= 0x40000 && c <= 0x2fffd) || \
+                            (c >= 0x50000 && c <= 0x5fffd) || (c >= 0x60000 && c <= 0x6fffd) || \
+                            (c >= 0x70000 && c <= 0x7fffd) || (c >= 0x80000 && c <= 0x8fffd) || \
+                            (c >= 0x90000 && c <= 0x9fffd) || (c >= 0xa0000 && c <= 0xafffd) || \
+                            (c >= 0xb0000 && c <= 0xbfffd) || (c >= 0xc0000 && c <= 0xcfffd) || \
+                            (c >= 0xd0000 && c <= 0xdfffd) || (c >= 0xe0000 && c <= 0xefffd) || \
+                            (c >= 0xf0000 && c <= 0xffffd) || (c >= 0x100000 && c <= 0x10fffd))
+
+/**
+ * @brief Try to find object with MEMBER string matching the IDENT in the given ARRAY.
+ * Macro logs an error message and returns LY_EVALID in case of existence of a matching object.
+ *
+ * @param[in] CTX yang parser context for logging.
+ * @param[in] ARRAY [sized array](@ref sizedarrays) of a generic objects with member named MEMBER to search.
+ * @param[in] MEMBER Name of the member of the objects in the ARRAY to compare.
+ * @param[in] STMT Name of the compared YANG statements for logging.
+ * @param[in] IDENT String trying to find in the ARRAY's objects inside the MEMBER member.
+ */
+#define CHECK_UNIQUENESS(CTX, ARRAY, MEMBER, STMT, IDENT) \
+    if (ARRAY) { \
+        for (unsigned int u = 0; u < LY_ARRAY_SIZE(ARRAY) - 1; ++u) { \
+            if (!strcmp((ARRAY)[u].MEMBER, IDENT)) { \
+                LOGVAL_PARSER(CTX, LY_VCODE_DUPIDENT, IDENT, STMT); \
+                return LY_EVALID; \
+            } \
+        } \
+    }
+
+#define YANG_CHECK_NONEMPTY(CTX, VALUE_LEN, STMT) \
+    if (!VALUE_LEN) { \
+        LOGWRN((CTX)->ctx, "Empty argument of %s statement does not make sense.", STMT); \
+    }
 
 /**
  * @brief List of YANG statement groups - the (sub)module's substatements
@@ -50,17 +88,39 @@
 };
 
 /**
- * @brief internal context for schema parsers
+ * @brief Internal context for yang schema parser.
  */
 struct lys_parser_ctx {
-    struct ly_ctx *ctx;
-    struct ly_set tpdfs_nodes;
-    struct ly_set grps_nodes;
-    uint64_t line;      /**< line number */
-    uint64_t indent;    /**< current position on the line for YANG indentation */
-    uint8_t mod_version; /**< module's version */
+    struct ly_set tpdfs_nodes;  /**< set of typedef nodes */
+    struct ly_set grps_nodes;   /**< set of grouping nodes */
+    uint8_t mod_version;        /**< module's version */
+    struct ly_ctx *ctx;         /**< context of then yang schemas */
+    uint64_t line;              /**< line number */
+    uint64_t indent;            /**< current position on the line for YANG indentation */
 };
 
+/**
+ * @brief free lys parser context.
+ */
+void lys_parser_ctx_free(struct lys_parser_ctx *ctx);
+
+/**
+ * @brief Internal context for yin schema parser.
+ */
+struct yin_parser_ctx {
+    struct ly_set tpdfs_nodes;     /**< set of typedef nodes */
+    struct ly_set grps_nodes;      /**< set of grouping nodes */
+    uint8_t mod_version;           /**< module's version */
+    struct lyxml_context xml_ctx;  /**< context for xml parser */
+};
+
+/**
+ * @brief free yin parser context
+ *
+ * @param[in] ctx Context to free.
+ */
+void yin_parser_ctx_free(struct yin_parser_ctx *ctx);
+
 struct lysc_incomplete_dflt {
     struct lyd_value *dflt;
     struct lys_module *dflt_mod;
@@ -68,6 +128,31 @@
 };
 
 /**
+ * @brief Check that \p c is valid UTF8 code point for YANG string.
+ *
+ * @param[in] ctx yang parser context for logging.
+ * @param[in] c UTF8 code point of a character to check.
+ * @return LY_ERR values.
+ */
+LY_ERR lysp_check_stringchar(struct lys_parser_ctx *ctx, unsigned int c);
+
+/**
+ * @brief Check that \p c is valid UTF8 code point for YANG identifier.
+ *
+ * @param[in] ctx yang parser context for logging.
+ * @param[in] c UTF8 code point of a character to check.
+ * @param[in] first Flag to check the first character of an identifier, which is more restricted.
+ * @param[in,out] prefix Storage for internally used flag in case of possible prefixed identifiers:
+ * 0 - colon not yet found (no prefix)
+ * 1 - \p c is the colon character
+ * 2 - prefix already processed, now processing the identifier
+ *
+ * If the identifier cannot be prefixed, NULL is expected.
+ * @return LY_ERR values.
+ */
+LY_ERR lysp_check_identifierchar(struct lys_parser_ctx *ctx, unsigned int c, int first, int *prefix);
+
+/**
  * @brief Internal structure for lys_get_prefix().
  */
 struct lys_get_prefix_data {
@@ -126,13 +211,26 @@
 LY_ERR lysp_check_typedefs(struct lys_parser_ctx *ctx, struct lysp_module *mod);
 
 /**
+ * @brief Finalize some of the structures in case they are stored in sized array,
+ * which can be possibly reallocated and some other data may point to them.
+ *
+ * Update parent pointers in the nodes inside grouping/augment/RPC/Notification, which could be reallocated.
+ *
+ * @param[in] mod Parsed module to be updated.
+ * @return LY_ERR value (currently only LY_SUCCESS, but it can change in future).
+ */
+LY_ERR
+lysp_parse_finalize_reallocated(struct lys_parser_ctx *ctx, struct lysp_grp *groupings, struct lysp_augment *augments,
+                                struct lysp_action *actions, struct lysp_notif *notifs);
+
+/**
  * @brief Just move the newest revision into the first position, does not sort the rest
  * @param[in] revs Sized-array of the revisions in a printable schema tree.
  */
 void lysp_sort_revisions(struct lysp_revision *revs);
 
 /**
- * @brief Find type specified type definition
+ * @brief Find type specified type definition.
  *
  * @param[in] id Name of the type including possible prefix. Module where the prefix is being searched is start_module.
  * @param[in] start_node Context node where the type is being instantiated to be able to search typedefs in parents.
@@ -146,6 +244,17 @@
                       LY_DATA_TYPE *type, const struct lysp_tpdf **tpdf, struct lysp_node **node, struct lysp_module **module);
 
 /**
+ * @brief Validate enum name.
+ *
+ * @param[in] ctx yang parser context for logging.
+ * @param[in] name String to check.
+ * @param[in] name_len Length of name.
+ *
+ * @return LY_ERR values
+ */
+LY_ERR lysp_check_enum_name(struct lys_parser_ctx *ctx, const char *name, size_t name_len);
+
+/**
  * @brief Find and parse module of the given name.
  *
  * @param[in] ctx libyang context.
@@ -668,12 +777,15 @@
 
 /**
  * @brief Parse submodule from YANG data.
- * @param[in] ctx Parser context.
+ * @param[in,out] ctx Parser context.
+ * @param[in] ly_ctx Context of YANG schemas.
+ * @param[in] main_ctx Parser context of main module.
  * @param[in] data Input data to be parsed.
  * @param[out] submod Pointer to the parsed submodule structure.
  * @return LY_ERR value - LY_SUCCESS, LY_EINVAL or LY_EVALID.
  */
-LY_ERR yang_parse_submodule(struct lys_parser_ctx *ctx, const char *data, struct lysp_submodule **submod);
+LY_ERR yang_parse_submodule(struct lys_parser_ctx **context, struct ly_ctx *ly_ctx, struct lys_parser_ctx *main_ctx,
+                            const char *data, struct lysp_submodule **submod);
 
 /**
  * @brief Parse module from YANG data.
@@ -683,7 +795,34 @@
  * module structure, will be filled in.
  * @return LY_ERR value - LY_SUCCESS, LY_EINVAL or LY_EVALID.
  */
-LY_ERR yang_parse_module(struct lys_parser_ctx *ctx, const char *data, struct lys_module *mod);
+LY_ERR yang_parse_module(struct lys_parser_ctx **context, const char *data, struct lys_module *mod);
+
+/**
+ * @brief Parse module from YIN data.
+ *
+ * @param[in,out] yin_ctx Context created during parsing, is used to finalize lysp_model after it's completly parsed.
+ * @param[in] data Input data to be parsed.
+ * @param[in,out] mod Prepared module structure where the parsed information, including the parsed
+ * module structure, will be filled in.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_parse_module(struct yin_parser_ctx **yin_ctx, const char *data, struct lys_module *mod);
+
+/**
+ * @brief Parse submodule from YIN data.
+ *
+ * @param[in,out] yin_ctx Context created during parsing, is used to finalize lysp_model after it's completly parsed.
+ * @param[in] ctx Libyang context.
+ * @param[in] main_ctx Parser context of main module.
+ * @param[in,out] data Input data to be parsed.
+ * @param[in,out] submod Submodule structure where the parsed information, will be filled in.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_parse_submodule(struct yin_parser_ctx **yin_ctx, struct ly_ctx *ctx, struct lys_parser_ctx *main_ctx,
+                           const char *data, struct lysp_submodule **submod);
+
 
 /**
  * @brief Make the specific module implemented, use the provided value as flag.
@@ -697,4 +836,14 @@
  */
 LY_ERR ly_ctx_module_implement_internal(struct ly_ctx *ctx, struct lys_module *mod, uint8_t implemented);
 
+/**
+ * @brief match yang keyword
+ *
+ * param[in] ctx yang parser context for logging, can be NULL if keyword is from YIN data.
+ * param[in,out] data Data to read from, always moved to currently handled character.
+ *
+ * return yang_keyword values.
+ */
+enum yang_keyword lysp_match_kw(struct lys_parser_ctx *ctx, const char **data);
+
 #endif /* LY_TREE_SCHEMA_INTERNAL_H_ */
diff --git a/src/xml.c b/src/xml.c
index dd556bd..a08417c 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -720,7 +720,7 @@
                     e = (struct lyxml_elem*)context->elements.objs[context->elements.count - 1];
                     LY_CHECK_ERR_GOTO(e->prefix_len != prefix_len || e->name_len != name_len
                                       || (prefix_len && strncmp(prefix, e->prefix, e->prefix_len)) || strncmp(name, e->name, e->name_len),
-                            free(e); LOGVAL(ctx, LY_VLOG_LINE, &fakecontext.line, LYVE_SYNTAX,
+                            free(e); --context->elements.count; LOGVAL(ctx, LY_VLOG_LINE, &fakecontext.line, LYVE_SYNTAX,
                                             "Opening and closing elements tag missmatch (\"%.*s\").", name_len, name),
                             error);
                     /* opening and closing element tags matches */
diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt
new file mode 100644
index 0000000..8ed9c90
--- /dev/null
+++ b/tests/fuzz/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+set(fuzz_targets yangfuzz)
+
+foreach(target_name IN LISTS fuzz_targets)
+    add_executable(${target_name} ${target_name}.c)
+    target_link_libraries(${target_name} yang)
+endforeach(target_name)
diff --git a/tests/fuzz/README.md b/tests/fuzz/README.md
new file mode 100644
index 0000000..e07193f
--- /dev/null
+++ b/tests/fuzz/README.md
@@ -0,0 +1,40 @@
+# FUZZING
+yangfuzz, a simple YANG fuzz harness is available in this directory and
+is designed to be used with the [AFL](http://lcamtuf.coredump.cx/afl/) fuzzer.
+
+To build the fuzz target, the ENABLE_FUZZ_TARGETS option has to be enabled.
+
+To add AFL instrumentation when compiling libyang, the AFL clang-fast compiler
+should be used with the following cmake option:
+
+It is reccomended to set the build type to Release, since otherwise the fuzzer will detect failed asserts as crashes.
+
+```
+$ cmake -DENABLE_FUZZ_TARGETS=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=path_to_afl/afl-clang-fast ..
+```
+
+After that the programs can be built by running make:
+```
+$ make
+```
+
+The yangfuzz executable will then be available in the root of the build directory that was used.
+
+The libyang yang test files available in the `tests/data/files` subdirectory can be used as initial
+test cases for fuzzing the programs with AFL.
+
+The files that will be used as starting test cases should be copied into a single directory. Those files should then be minimized by using afl-cmin and afl-tmin.
+Also, AFL will issue a warning about a decrease of performance when working with large files, so only smaller test cases should be used.
+
+To increase the speed of fuzzing, the test cases and AFL output files should be stored on a temporary RAM disk.
+If a new fuzz target is used, AFL persistent mode should be used. More about persistent mode can be read in the official AFL documentation.
+
+When all of the above is done the fuzzing process can begin. AFL supports running multiple instances of the fuzzer, which can speed up the
+process on multi core CPUs. The first fuzz instance should be started in master mode, and the other instances in slave mode.
+The total number of instances should usually be equal to the number of cores.
+
+Below is an example of running 2 instances. The -i flag specifies the testcase input directory, and the -o file specifies the directory the fuzzer will use for output.
+```
+afl-fuzz -i minimised_testcases/ -o syncdir/ -M fuzzer1 -- libyang/build/fuzz/yangfuzz @@
+afl-fuzz -i minimised_testcases/ -o syncdir/ -S fuzzer2 -- libyang/build/fuzz/yangfuzz @@
+```
diff --git a/tests/fuzz/yangfuzz.c b/tests/fuzz/yangfuzz.c
new file mode 100644
index 0000000..06d6076
--- /dev/null
+++ b/tests/fuzz/yangfuzz.c
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "libyang.h"
+
+int main(int argc, char **argv) {
+	if (argc != 2) {
+		fprintf(stderr, "invalid usage\n");
+		exit(EXIT_FAILURE);
+	}
+
+
+	struct ly_ctx *ctx = NULL;
+	LY_ERR err;
+	while (__AFL_LOOP(100)) {
+		err = ly_ctx_new(NULL, 0, &ctx);
+		if (err != LY_SUCCESS) {
+			fprintf(stderr, "Failed to create context\n");
+			exit(EXIT_FAILURE);
+		}
+
+		lys_parse_path(ctx, argv[1], LYS_IN_YANG);
+		ly_ctx_destroy(ctx, NULL);
+	}
+
+	return 0;
+}
diff --git a/tests/src/CMakeLists.txt b/tests/src/CMakeLists.txt
index c5ded11..fa021c9 100644
--- a/tests/src/CMakeLists.txt
+++ b/tests/src/CMakeLists.txt
@@ -5,6 +5,7 @@
     src_hash_table
     src_xml
     src_parser_yang
+    src_parser_yin
     src_tree_schema
     src_tree_schema_compile
     src_tree_schema_helpers
@@ -25,6 +26,7 @@
     " "
     " "
     " "
+    " "
     " ")
 set(tests ${tests} ${local_tests} PARENT_SCOPE)
 set(tests_wraps ${tests_wraps} ${local_tests_wraps} PARENT_SCOPE)
diff --git a/tests/src/test_context.c b/tests/src/test_context.c
index 78deffe..58f52d4 100644
--- a/tests/src/test_context.c
+++ b/tests/src/test_context.c
@@ -283,7 +283,7 @@
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
     assert_int_equal(ctx->module_set_id, ly_ctx_get_module_set_id(ctx));
 
-    assert_null(lys_parse_mem_module(ctx, "module x {namespace urn:x;prefix x;}", 3, 1, NULL, NULL));
+    assert_null(lys_parse_mem_module(ctx, "module x {namespace urn:x;prefix x;}", 4, 1, NULL, NULL));
     logbuf_assert("Invalid schema input format.");
 
     /* import callback */
diff --git a/tests/src/test_parser_yang.c b/tests/src/test_parser_yang.c
index 0d6263d..e4adfd7 100644
--- a/tests/src/test_parser_yang.c
+++ b/tests/src/test_parser_yang.c
@@ -38,13 +38,12 @@
 void lysp_when_free(struct ly_ctx *ctx, struct lysp_when *when);
 
 LY_ERR buf_add_char(struct ly_ctx *ctx, const char **input, size_t len, char **buf, size_t *buf_len, size_t *buf_used);
-LY_ERR buf_store_char(struct lys_parser_ctx *ctx, const char **input, enum yang_arg arg,
-                      char **word_p, size_t *word_len, char **word_b, size_t *buf_len, int need_buf);
+LY_ERR buf_store_char(struct lys_parser_ctx *ctx, const char **input, enum yang_arg arg, char **word_p,
+                      size_t *word_len, char **word_b, size_t *buf_len, int need_buf, int *prefix);
 LY_ERR get_keyword(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword *kw, char **word_p, size_t *word_len);
 LY_ERR get_argument(struct lys_parser_ctx *ctx, const char **data, enum yang_arg arg,
                     uint16_t *flags, char **word_p, char **word_b, size_t *word_len);
 LY_ERR skip_comment(struct lys_parser_ctx *ctx, const char **data, int comment);
-LY_ERR check_identifierchar(struct lys_parser_ctx *ctx, unsigned int c, int first, int *prefix);
 
 LY_ERR parse_action(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_action **actions);
 LY_ERR parse_any(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword kw, struct lysp_node *parent, struct lysp_node **siblings);
@@ -67,6 +66,7 @@
 LY_ERR parse_submodule(struct lys_parser_ctx *ctx, const char **data, struct lysp_submodule *submod);
 LY_ERR parse_uses(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
 LY_ERR parse_when(struct lys_parser_ctx *ctx, const char **data, struct lysp_when **when_p);
+LY_ERR parse_type_enum_value_pos(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword val_kw, int64_t *value, uint16_t *flags, struct lysp_ext_instance **exts);
 
 #define BUFSIZE 1024
 char logbuf[BUFSIZE] = {0};
@@ -141,10 +141,10 @@
     const char *str;
     char *buf, *p;
     size_t len, size;
-    int prefix;
     struct lys_parser_ctx ctx;
     ctx.ctx = NULL;
     ctx.line = 1;
+    int prefix = 0;
 
     /* storing into buffer */
     str = "abcd";
@@ -161,48 +161,50 @@
     /* invalid first characters */
     len = 0;
     str = "2invalid";
-    assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1));
+    assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
     str = ".invalid";
-    assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1));
+    assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
     str = "-invalid";
-    assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1));
+    assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
     /* invalid following characters */
     len = 3; /* number of characters read before the str content */
     str = "!";
-    assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1));
+    assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
     str = ":";
-    assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1));
+    assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
     /* valid colon for prefixed identifiers */
     len = size = 0;
     p = NULL;
+    prefix = 0;
     str = "x:id";
-    assert_int_equal(LY_SUCCESS, buf_store_char(&ctx, &str, Y_PREF_IDENTIF_ARG, &p, &len, &buf, &size, 0));
+    assert_int_equal(LY_SUCCESS, buf_store_char(&ctx, &str, Y_PREF_IDENTIF_ARG, &p, &len, &buf, &size, 0, &prefix));
     assert_int_equal(1, len);
     assert_null(buf);
     assert_string_equal(":id", str);
     assert_int_equal('x', p[len - 1]);
-    assert_int_equal(LY_SUCCESS, buf_store_char(&ctx, &str, Y_PREF_IDENTIF_ARG, &p, &len, &buf, &size, 1));
+    assert_int_equal(LY_SUCCESS, buf_store_char(&ctx, &str, Y_PREF_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
     assert_int_equal(2, len);
     assert_string_equal("id", str);
     assert_int_equal(':', p[len - 1]);
     free(buf);
+    prefix = 0;
 
     /* checking identifiers */
-    assert_int_equal(LY_EVALID, check_identifierchar(&ctx, ':', 0, NULL));
+    assert_int_equal(LY_EVALID, lysp_check_identifierchar(&ctx, ':', 0, NULL));
     logbuf_assert("Invalid identifier character ':'. Line number 1.");
-    assert_int_equal(LY_EVALID, check_identifierchar(&ctx, '#', 1, NULL));
+    assert_int_equal(LY_EVALID, lysp_check_identifierchar(&ctx, '#', 1, NULL));
     logbuf_assert("Invalid identifier first character '#'. Line number 1.");
 
-    assert_int_equal(LY_SUCCESS, check_identifierchar(&ctx, 'a', 1, &prefix));
+    assert_int_equal(LY_SUCCESS, lysp_check_identifierchar(&ctx, 'a', 1, &prefix));
     assert_int_equal(0, prefix);
-    assert_int_equal(LY_SUCCESS, check_identifierchar(&ctx, ':', 0, &prefix));
+    assert_int_equal(LY_SUCCESS, lysp_check_identifierchar(&ctx, ':', 0, &prefix));
     assert_int_equal(1, prefix);
-    assert_int_equal(LY_EVALID, check_identifierchar(&ctx, ':', 0, &prefix));
+    assert_int_equal(LY_EVALID, lysp_check_identifierchar(&ctx, ':', 0, &prefix));
     assert_int_equal(1, prefix);
-    assert_int_equal(LY_SUCCESS, check_identifierchar(&ctx, 'b', 0, &prefix));
+    assert_int_equal(LY_SUCCESS, lysp_check_identifierchar(&ctx, 'b', 0, &prefix));
     assert_int_equal(2, prefix);
     /* second colon is invalid */
-    assert_int_equal(LY_EVALID, check_identifierchar(&ctx, ':', 0, &prefix));
+    assert_int_equal(LY_EVALID, lysp_check_identifierchar(&ctx, ':', 0, &prefix));
     logbuf_assert("Invalid identifier character ':'. Line number 1.");
 }
 
@@ -282,6 +284,10 @@
     assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
     logbuf_assert("Invalid character sequence \"}\", expected unquoted string character, optsep, semicolon or opening brace. Line number 1.");
 
+    /* invalid identifier-ref-arg-str */
+    str = "pre:pre:value";
+    assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_PREF_IDENTIF_ARG, NULL, &word, &buf, &len));
+
     str = "\"\";"; /* empty identifier is not allowed */
     assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_IDENTIF_ARG, NULL, &word, &buf, &len));
     logbuf_assert("Statement argument is required. Line number 1.");
@@ -1041,20 +1047,33 @@
     assert_int_equal(2, mod->mod->version);
     mod = mod_renew(&ctx);
 
+    struct lys_parser_ctx *ctx_p = NULL;
     str = "module " SCHEMA_BEGINNING "} module q {namespace urn:q;prefixq;}";
     m = mod->mod;
     free(mod);
     m->parsed = NULL;
-    assert_int_equal(LY_EVALID, yang_parse_module(&ctx, str, m));
-    logbuf_assert("Trailing garbage \"module q {names...\" after module, expected end-of-input. Line number 3.");
+    assert_int_equal(LY_EVALID, yang_parse_module(&ctx_p, str, m));
+    logbuf_assert("Trailing garbage \"module q {names...\" after module, expected end-of-input. Line number 1.");
+    lys_parser_ctx_free(ctx_p);
     mod = mod_renew(&ctx);
 
     str = "prefix " SCHEMA_BEGINNING "}";
     m = mod->mod;
     free(mod);
     m->parsed = NULL;
-    assert_int_equal(LY_EVALID, yang_parse_module(&ctx, str, m));
-    logbuf_assert("Invalid keyword \"prefix\", expected \"module\" or \"submodule\". Line number 3.");
+    assert_int_equal(LY_EVALID, yang_parse_module(&ctx_p, str, m));
+    lys_parser_ctx_free(ctx_p);
+    logbuf_assert("Invalid keyword \"prefix\", expected \"module\" or \"submodule\". Line number 1.");
+    mod = mod_renew(&ctx);
+
+    str = "module " SCHEMA_BEGINNING "}";
+    str = "module " SCHEMA_BEGINNING "leaf enum {type enumeration {enum seven { position 7;}}}}";
+    m = mod->mod;
+    free(mod);
+    m->parsed = NULL;
+    assert_int_equal(LY_EVALID, yang_parse_module(&ctx_p, str, m));
+    lys_parser_ctx_free(ctx_p);
+    logbuf_assert("Invalid keyword \"position\" as a child of \"enum\". Line number 1.");
     mod = mod_renew(&ctx);
 
     /* extensions */
@@ -1108,12 +1127,14 @@
     str = "submodule " SCHEMA_BEGINNING "} module q {namespace urn:q;prefixq;}";
     lysp_submodule_free(ctx.ctx, submod);
     submod = NULL;
-    assert_int_equal(LY_EVALID, yang_parse_submodule(&ctx, str, &submod));
-    logbuf_assert("Trailing garbage \"module q {names...\" after submodule, expected end-of-input. Line number 3.");
+    assert_int_equal(LY_EVALID, yang_parse_submodule(&ctx_p, ctx.ctx, &ctx, str, &submod));
+    lys_parser_ctx_free(ctx_p);
+    logbuf_assert("Trailing garbage \"module q {names...\" after submodule, expected end-of-input. Line number 1.");
 
     str = "prefix " SCHEMA_BEGINNING "}";
-    assert_int_equal(LY_EVALID, yang_parse_submodule(&ctx, str, &submod));
-    logbuf_assert("Invalid keyword \"prefix\", expected \"module\" or \"submodule\". Line number 3.");
+    assert_int_equal(LY_EVALID, yang_parse_submodule(&ctx_p, ctx.ctx, &ctx, str, &submod));
+    lys_parser_ctx_free(ctx_p);
+    logbuf_assert("Invalid keyword \"prefix\", expected \"module\" or \"submodule\". Line number 1.");
     submod = submod_renew(&ctx, submod);
 
 #undef TEST_GENERIC
@@ -2193,6 +2214,32 @@
     ly_ctx_destroy(ctx.ctx, NULL);
 }
 
+static void
+test_value(void **state)
+{
+    *state = test_value;
+    struct lys_parser_ctx ctx;
+
+    assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
+    assert_non_null(ctx.ctx);
+    ctx.line = 1;
+    ctx.indent = 0;
+    int64_t val = 0;
+    uint16_t flags = 0;
+
+    const char *data = "-0;";
+    assert_int_equal(parse_type_enum_value_pos(&ctx, &data, YANG_VALUE, &val, &flags, NULL), LY_SUCCESS);
+    assert_int_equal(val, 0);
+
+    data = "-0;";
+    flags = 0;
+    assert_int_equal(parse_type_enum_value_pos(&ctx, &data, YANG_POSITION, &val, &flags, NULL), LY_EVALID);
+    logbuf_assert("Invalid value \"-0\" of \"position\". Line number 1.");
+
+    *state = NULL;
+    ly_ctx_destroy(ctx.ctx, NULL);
+}
+
 int main(void)
 {
     const struct CMUnitTest tests[] = {
@@ -2220,6 +2267,7 @@
         cmocka_unit_test_setup_teardown(test_uses, logger_setup, logger_teardown),
         cmocka_unit_test_setup_teardown(test_augment, logger_setup, logger_teardown),
         cmocka_unit_test_setup_teardown(test_when, logger_setup, logger_teardown),
+        cmocka_unit_test_setup_teardown(test_value, logger_setup, logger_teardown),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);
diff --git a/tests/src/test_parser_yin.c b/tests/src/test_parser_yin.c
new file mode 100644
index 0000000..5ddba08
--- /dev/null
+++ b/tests/src/test_parser_yin.c
@@ -0,0 +1,4437 @@
+/**
+ * @file test_parser_yin.c
+ * @author David Sedlák <xsedla1d@stud.fit.vutbr.cz>
+ * @brief unit tests for functions from parser_yin.c
+ *
+ * Copyright (c) 2015 - 2019 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.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "../../src/common.h"
+#include "../../src/tree_schema.h"
+#include "../../src/tree_schema_internal.h"
+#include "../../src/parser_yin.h"
+#include "../../src/xml.h"
+
+/* prototypes of static functions */
+void lysp_ext_instance_free(struct ly_ctx *ctx, struct lysp_ext_instance *ext);
+void lysp_ext_free(struct ly_ctx *ctx, struct lysp_ext *ext);
+void lysp_when_free(struct ly_ctx *ctx, struct lysp_when *when);
+void lysp_type_free(struct ly_ctx *ctx, struct lysp_type *type);
+void lysp_node_free(struct ly_ctx *ctx, struct lysp_node *node);
+void lysp_tpdf_free(struct ly_ctx *ctx, struct lysp_tpdf *tpdf);
+void lysp_refine_free(struct ly_ctx *ctx, struct lysp_refine *ref);
+void lysp_revision_free(struct ly_ctx *ctx, struct lysp_revision *rev);
+void lysp_include_free(struct ly_ctx *ctx, struct lysp_include *include);
+void lysp_feature_free(struct ly_ctx *ctx, struct lysp_feature *feat);
+void lysp_ident_free(struct ly_ctx *ctx, struct lysp_ident *ident);
+void lysp_notif_free(struct ly_ctx *ctx, struct lysp_notif *notif);
+void lysp_grp_free(struct ly_ctx *ctx, struct lysp_grp *grp);
+void lysp_action_inout_free(struct ly_ctx *ctx, struct lysp_action_inout *inout);
+void lysp_action_free(struct ly_ctx *ctx, struct lysp_action *action);
+void lysp_augment_free(struct ly_ctx *ctx, struct lysp_augment *augment);
+void lysp_deviate_free(struct ly_ctx *ctx, struct lysp_deviate *d);
+void lysp_deviation_free(struct ly_ctx *ctx, struct lysp_deviation *dev);
+void lysp_submodule_free(struct ly_ctx *ctx, struct lysp_submodule *submod);
+void lysp_import_free(struct ly_ctx *ctx, struct lysp_import *import);
+
+/* wrapping element used for mocking has nothing to do with real module structure */
+#define ELEMENT_WRAPPER_START "<status xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+#define ELEMENT_WRAPPER_END "</status>"
+
+struct state {
+    struct ly_ctx *ctx;
+    struct lys_module *mod;
+    struct lysp_module *lysp_mod;
+    struct yin_parser_ctx *yin_ctx;
+    bool finished_correctly;
+};
+
+#define BUFSIZE 1024
+char logbuf[BUFSIZE] = {0};
+int store = -1; /* negative for infinite logging, positive for limited logging */
+
+/* set to 0 to printing error messages to stderr instead of checking them in code */
+#define ENABLE_LOGGER_CHECKING 1
+
+#if ENABLE_LOGGER_CHECKING
+static void
+logger(LY_LOG_LEVEL level, const char *msg, const char *path)
+{
+    (void) level; /* unused */
+    if (store) {
+        if (path && path[0]) {
+            snprintf(logbuf, BUFSIZE - 1, "%s %s", msg, path);
+        } else {
+            strncpy(logbuf, msg, BUFSIZE - 1);
+        }
+        if (store > 0) {
+            --store;
+        }
+    }
+}
+#endif
+
+#if ENABLE_LOGGER_CHECKING
+#   define logbuf_assert(str) assert_string_equal(logbuf, str)
+#else
+#   define logbuf_assert(str)
+#endif
+
+#define TEST_DUP_GENERIC(PREFIX, MEMBER, VALUE1, VALUE2, FUNC, RESULT, LINE, CLEANUP) \
+    str = PREFIX MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
+    assert_int_equal(LY_EVALID, FUNC(&ctx, &str, RESULT)); \
+    logbuf_assert("Duplicate keyword \""MEMBER"\". Line number "LINE"."); \
+    CLEANUP
+
+int
+setup_ly_ctx(void **state)
+{
+    struct state *st = NULL;
+
+    /* allocate state variable */
+    (*state) = st = calloc(1, sizeof(*st));
+    if (!st) {
+        fprintf(stderr, "Memmory allocation failed");
+        return EXIT_FAILURE;
+    }
+
+    /* create new libyang context */
+    ly_ctx_new(NULL, 0, &st->ctx);
+
+    return EXIT_SUCCESS;
+}
+
+int
+destroy_ly_ctx(void **state)
+{
+    struct state *st = *state;
+    ly_ctx_destroy(st->ctx, NULL);
+    free(st);
+
+    return EXIT_SUCCESS;
+}
+
+static int
+setup_f(void **state)
+{
+    struct state *st = *state;
+
+#if ENABLE_LOGGER_CHECKING
+    /* setup logger */
+    ly_set_log_clb(logger, 1);
+#endif
+
+    /* allocate new module */
+    st->mod = calloc(1, sizeof(*st->mod));
+    st->mod->ctx = st->ctx;
+
+    /* allocate new parsed module */
+    st->lysp_mod = calloc(1, sizeof(*st->lysp_mod));
+    st->lysp_mod->mod = calloc(1, sizeof(*st->lysp_mod->mod));
+    st->lysp_mod->mod->ctx = st->ctx;
+
+    /* allocate parser context */
+    st->yin_ctx = calloc(1, sizeof(*st->yin_ctx));
+    st->yin_ctx->xml_ctx.ctx = st->ctx;
+    st->yin_ctx->xml_ctx.line = 1;
+
+    return EXIT_SUCCESS;
+}
+
+static int
+teardown_f(void **state)
+{
+    struct state *st = *(struct state **)state;
+    struct lys_module *temp;
+
+#if ENABLE_LOGGER_CHECKING
+    /* teardown logger */
+    if (!st->finished_correctly && logbuf[0] != '\0') {
+        fprintf(stderr, "%s\n", logbuf);
+    }
+#endif
+
+    temp = st->lysp_mod->mod;
+
+    lyxml_context_clear(&st->yin_ctx->xml_ctx);
+    lys_module_free(st->mod, NULL);
+    lysp_module_free(st->lysp_mod);
+    lys_module_free(temp, NULL);
+    free(st->yin_ctx);
+
+    return EXIT_SUCCESS;
+}
+
+static struct state*
+reset_state(void **state)
+{
+    ((struct state *)*state)->finished_correctly = true;
+    logbuf[0] = '\0';
+    teardown_f(state);
+    setup_f(state);
+
+    return *state;
+}
+
+void
+logbuf_clean(void)
+{
+    logbuf[0] = '\0';
+}
+
+static int
+setup_logger(void **state)
+{
+    (void)state; /* unused */
+#if ENABLE_LOGGER_CHECKING
+    /* setup logger */
+    ly_set_log_clb(logger, 1);
+#endif
+
+    logbuf[0] = '\0';
+
+    return EXIT_SUCCESS;
+}
+
+static int
+teardown_logger(void **state)
+{
+    struct state *st = *state;
+
+#if ENABLE_LOGGER_CHECKING
+    /* teardown logger */
+    if (!st->finished_correctly && logbuf[0] != '\0') {
+        fprintf(stderr, "%s\n", logbuf);
+    }
+#endif
+
+    return EXIT_SUCCESS;
+}
+
+static int
+setup_element_test(void **state)
+{
+    setup_logger(state);
+    struct state *st = *state;
+
+    st->yin_ctx = calloc(1, sizeof(*st->yin_ctx));
+
+    /* allocate parser context */
+    st->yin_ctx->xml_ctx.ctx = st->ctx;
+    st->yin_ctx->xml_ctx.line = 1;
+
+    return EXIT_SUCCESS;
+}
+
+static int
+teardown_element_test(void **state)
+{
+    struct state *st = *(struct state **)state;
+
+    lyxml_context_clear(&st->yin_ctx->xml_ctx);
+    free(st->yin_ctx);
+
+    teardown_logger(state);
+
+    return EXIT_SUCCESS;
+}
+
+static void
+test_yin_match_keyword(void **state)
+{
+    struct state *st = *state;
+
+    const char *prefix, *name;
+    struct yin_arg_record *args = NULL;
+    size_t prefix_len, name_len;
+    /* create mock yin namespace in xml context */
+    const char *data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" />";
+    lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+    yin_load_attributes(st->yin_ctx, &data, &args);
+    LY_ARRAY_FREE(args);
+
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "anydatax", strlen("anydatax"), prefix, prefix_len, YANG_NONE), YANG_NONE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "asdasd", strlen("asdasd"), prefix, prefix_len, YANG_NONE), YANG_NONE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "", 0, prefix, prefix_len, YANG_NONE), YANG_NONE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "anydata", strlen("anydata"), prefix, prefix_len, YANG_NONE), YANG_ANYDATA);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "anyxml", strlen("anyxml"), prefix, prefix_len, YANG_NONE), YANG_ANYXML);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "argument", strlen("argument"), prefix, prefix_len, YANG_NONE), YANG_ARGUMENT);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "augment", strlen("augment"), prefix, prefix_len, YANG_NONE), YANG_AUGMENT);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "base", strlen("base"), prefix, prefix_len, YANG_NONE), YANG_BASE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "belongs-to", strlen("belongs-to"), prefix, prefix_len, YANG_NONE), YANG_BELONGS_TO);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "bit", strlen("bit"), prefix, prefix_len, YANG_NONE), YANG_BIT);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "case", strlen("case"), prefix, prefix_len, YANG_NONE), YANG_CASE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "choice", strlen("choice"), prefix, prefix_len, YANG_NONE), YANG_CHOICE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "config", strlen("config"), prefix, prefix_len, YANG_NONE), YANG_CONFIG);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "contact", strlen("contact"), prefix, prefix_len, YANG_NONE), YANG_CONTACT);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "container", strlen("container"), prefix, prefix_len, YANG_NONE), YANG_CONTAINER);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "default", strlen("default"), prefix, prefix_len, YANG_NONE), YANG_DEFAULT);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "description", strlen("description"), prefix, prefix_len, YANG_NONE), YANG_DESCRIPTION);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "deviate", strlen("deviate"), prefix, prefix_len, YANG_NONE), YANG_DEVIATE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "deviation", strlen("deviation"), prefix, prefix_len, YANG_NONE), YANG_DEVIATION);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "enum", strlen("enum"), prefix, prefix_len, YANG_NONE), YANG_ENUM);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "error-app-tag", strlen("error-app-tag"), prefix, prefix_len, YANG_NONE), YANG_ERROR_APP_TAG);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "error-message", strlen("error-message"), prefix, prefix_len, YANG_NONE), YANG_ERROR_MESSAGE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "extension", strlen("extension"), prefix, prefix_len, YANG_NONE), YANG_EXTENSION);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "feature", strlen("feature"), prefix, prefix_len, YANG_NONE), YANG_FEATURE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "fraction-digits", strlen("fraction-digits"), prefix,  prefix_len, YANG_NONE), YANG_FRACTION_DIGITS);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "grouping", strlen("grouping"), prefix, prefix_len, YANG_NONE), YANG_GROUPING);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "identity", strlen("identity"), prefix, prefix_len, YANG_NONE), YANG_IDENTITY);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "if-feature", strlen("if-feature"), prefix, prefix_len, YANG_NONE), YANG_IF_FEATURE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "import", strlen("import"), prefix, prefix_len, YANG_NONE), YANG_IMPORT);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "include", strlen("include"), prefix, prefix_len, YANG_NONE), YANG_INCLUDE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "input", strlen("input"), prefix, prefix_len, YANG_NONE), YANG_INPUT);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "key", strlen("key"), prefix, prefix_len, YANG_NONE), YANG_KEY);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "leaf", strlen("leaf"), prefix, prefix_len, YANG_NONE), YANG_LEAF);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "leaf-list", strlen("leaf-list"), prefix, prefix_len, YANG_NONE), YANG_LEAF_LIST);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "length", strlen("length"), prefix, prefix_len, YANG_NONE), YANG_LENGTH);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "list", strlen("list"), prefix, prefix_len, YANG_NONE), YANG_LIST);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "mandatory", strlen("mandatory"), prefix, prefix_len, YANG_NONE), YANG_MANDATORY);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "max-elements", strlen("max-elements"), prefix, prefix_len, YANG_NONE), YANG_MAX_ELEMENTS);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "min-elements", strlen("min-elements"), prefix, prefix_len, YANG_NONE), YANG_MIN_ELEMENTS);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "modifier", strlen("modifier"), prefix, prefix_len, YANG_NONE), YANG_MODIFIER);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "module", strlen("module"), prefix, prefix_len, YANG_NONE), YANG_MODULE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "must", strlen("must"), prefix, prefix_len, YANG_NONE), YANG_MUST);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "namespace", strlen("namespace"), prefix, prefix_len, YANG_NONE), YANG_NAMESPACE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "notification", strlen("notification"), prefix, prefix_len, YANG_NONE), YANG_NOTIFICATION);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "ordered-by", strlen("ordered-by"), prefix, prefix_len, YANG_NONE), YANG_ORDERED_BY);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "organization", strlen("organization"), prefix, prefix_len, YANG_NONE), YANG_ORGANIZATION);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "output", strlen("output"), prefix, prefix_len, YANG_NONE), YANG_OUTPUT);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "path", strlen("path"), prefix, prefix_len, YANG_NONE), YANG_PATH);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "pattern", strlen("pattern"), prefix, prefix_len, YANG_NONE), YANG_PATTERN);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "position", strlen("position"), prefix, prefix_len, YANG_NONE), YANG_POSITION);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "prefix", strlen("prefix"), prefix, prefix_len, YANG_NONE), YANG_PREFIX);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "presence", strlen("presence"), prefix, prefix_len, YANG_NONE), YANG_PRESENCE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "range", strlen("range"), prefix, prefix_len, YANG_NONE), YANG_RANGE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "reference", strlen("reference"), prefix, prefix_len, YANG_NONE), YANG_REFERENCE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "refine", strlen("refine"), prefix, prefix_len, YANG_NONE), YANG_REFINE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "require-instance", strlen("require-instance"), prefix, prefix_len, YANG_NONE), YANG_REQUIRE_INSTANCE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "revision", strlen("revision"), prefix, prefix_len, YANG_NONE), YANG_REVISION);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "revision-date", strlen("revision-date"), prefix, prefix_len, YANG_NONE), YANG_REVISION_DATE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "rpc", strlen("rpc"), prefix, prefix_len, YANG_NONE), YANG_RPC);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "status", strlen("status"), prefix, prefix_len, YANG_NONE), YANG_STATUS);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "submodule", strlen("submodule"), prefix, prefix_len, YANG_NONE), YANG_SUBMODULE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "type", strlen("type"), prefix, prefix_len, YANG_NONE), YANG_TYPE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "typedef", strlen("typedef"), prefix, prefix_len, YANG_NONE), YANG_TYPEDEF);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "unique", strlen("unique"), prefix, prefix_len, YANG_NONE), YANG_UNIQUE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "units", strlen("units"), prefix, prefix_len, YANG_NONE), YANG_UNITS);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "uses", strlen("uses"), prefix, prefix_len, YANG_NONE), YANG_USES);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "value", strlen("value"), prefix, prefix_len, YANG_NONE), YANG_VALUE);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "when", strlen("when"), prefix, prefix_len, YANG_NONE), YANG_WHEN);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "yang-version", strlen("yang-version"), prefix, prefix_len, YANG_NONE), YANG_YANG_VERSION);
+    assert_int_equal(yin_match_keyword(st->yin_ctx, "yin-element", strlen("yin-element"), prefix, prefix_len, YANG_NONE), YANG_YIN_ELEMENT);
+
+    st->finished_correctly = true;
+}
+
+static void
+test_yin_match_argument_name(void **state)
+{
+    (void)state; /* unused */
+
+    assert_int_equal(yin_match_argument_name("", 5), YIN_ARG_UNKNOWN);
+    assert_int_equal(yin_match_argument_name("qwertyasd", 5), YIN_ARG_UNKNOWN);
+    assert_int_equal(yin_match_argument_name("conditionasd", 8), YIN_ARG_UNKNOWN);
+    assert_int_equal(yin_match_argument_name("condition", 9), YIN_ARG_CONDITION);
+    assert_int_equal(yin_match_argument_name("date", 4), YIN_ARG_DATE);
+    assert_int_equal(yin_match_argument_name("module", 6), YIN_ARG_MODULE);
+    assert_int_equal(yin_match_argument_name("name", 4), YIN_ARG_NAME);
+    assert_int_equal(yin_match_argument_name("tag", 3), YIN_ARG_TAG);
+    assert_int_equal(yin_match_argument_name("target-node", 11), YIN_ARG_TARGET_NODE);
+    assert_int_equal(yin_match_argument_name("text", 4), YIN_ARG_TEXT);
+    assert_int_equal(yin_match_argument_name("uri", 3), YIN_ARG_URI);
+    assert_int_equal(yin_match_argument_name("value", 5), YIN_ARG_VALUE);
+}
+
+static void
+test_yin_parse_element_generic(void **state)
+{
+    const char *prefix, *name;
+    struct state *st = *state;
+    struct lysp_ext_instance exts;
+    size_t prefix_len, name_len;
+    LY_ERR ret;
+
+    memset(&exts, 0, sizeof(exts));
+
+    const char *data = "<elem attr=\"value\">text_value</elem>";
+    lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+    ret = yin_parse_element_generic(st->yin_ctx, name, name_len, &data, &exts.child);
+    assert_int_equal(ret, LY_SUCCESS);
+    assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+    assert_string_equal(exts.child->stmt, "elem");
+    assert_string_equal(exts.child->arg, "text_value");
+    assert_string_equal(exts.child->child->stmt, "attr");
+    assert_string_equal(exts.child->child->arg, "value");
+    assert_true(exts.child->child->flags & LYS_YIN_ATTR);
+    lysp_ext_instance_free(st->ctx, &exts);
+    st = reset_state(state);
+
+    data = "<elem></elem>";
+    lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+    ret = yin_parse_element_generic(st->yin_ctx, name, name_len, &data, &exts.child);
+    assert_int_equal(ret, LY_SUCCESS);
+    assert_string_equal(exts.child->stmt, "elem");
+    assert_null(exts.child->child);
+    assert_null(exts.child->arg);
+    assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+    lysp_ext_instance_free(st->ctx, &exts);
+
+    st->finished_correctly = true;
+}
+
+static void
+test_yin_parse_extension_instance(void **state)
+{
+    LY_ERR ret;
+    struct state *st = *state;
+    const char *prefix, *name;
+    size_t prefix_len, name_len;
+    struct yin_arg_record *args = NULL;
+    struct lysp_ext_instance *exts = NULL;
+    const char *data = "<ext value1=\"test\" value=\"test2\"><subelem>text</subelem></ext>";
+    lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+    yin_load_attributes(st->yin_ctx, &data, &args);
+    ret = yin_parse_extension_instance(st->yin_ctx, args, &data, name2fname(name, prefix_len),
+                                       len2flen(name_len, prefix_len), LYEXT_SUBSTMT_CONTACT, 0, &exts);
+    assert_int_equal(ret, LY_SUCCESS);
+    assert_string_equal(exts->name, "ext");
+    assert_int_equal(exts->insubstmt_index, 0);
+    assert_true(exts->insubstmt == LYEXT_SUBSTMT_CONTACT);
+    assert_true(exts->yin & LYS_YIN);
+    assert_string_equal(exts->child->stmt, "value1");
+    assert_string_equal(exts->child->arg, "test");
+    assert_null(exts->child->child);
+    assert_true(exts->child->flags & LYS_YIN_ATTR);
+    assert_string_equal(exts->child->next->stmt, "value");
+    assert_string_equal(exts->child->next->arg, "test2");
+    assert_null(exts->child->next->child);
+    assert_true(exts->child->next->flags & LYS_YIN_ATTR);
+
+    assert_string_equal(exts->child->next->next->stmt, "subelem");
+    assert_string_equal(exts->child->next->next->arg, "text");
+    assert_null(exts->child->next->next->child);
+    assert_null(exts->child->next->next->next);
+    assert_false(exts->child->next->next->flags & LYS_YIN_ATTR);
+    assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+    LY_ARRAY_FREE(args);
+    lysp_ext_instance_free(st->ctx, exts);
+    LY_ARRAY_FREE(exts);
+    exts = NULL;
+    args = NULL;
+    st = reset_state(state);
+
+    data = "<extension-elem />";
+    lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+    yin_load_attributes(st->yin_ctx, &data, &args);
+    ret = yin_parse_extension_instance(st->yin_ctx, args, &data, name, name_len, LYEXT_SUBSTMT_CONTACT, 0, &exts);
+    assert_int_equal(ret, LY_SUCCESS);
+    assert_string_equal(exts->name, "extension-elem");
+    assert_null(exts->argument);
+    assert_null(exts->child);
+    assert_int_equal(exts->insubstmt, LYEXT_SUBSTMT_CONTACT);
+    assert_int_equal(exts->insubstmt_index, 0);
+    assert_true(exts->yin & LYS_YIN);
+    assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+    LY_ARRAY_FREE(args);
+    lysp_ext_instance_free(st->ctx, exts);
+    LY_ARRAY_FREE(exts);
+    exts = NULL;
+    args = NULL;
+    st = reset_state(state);
+
+    data = "<ext attr1=\"text1\" attr2=\"text2\">"
+                "<ext-sub1/>"
+                "<ext-sub2 sattr1=\"stext2\">"
+                    "<ext-sub21>"
+                        "<ext-sub211 sattr21=\"text21\"/>"
+                    "</ext-sub21>"
+                "</ext-sub2>"
+                "<ext-sub3 attr3=\"text3\"></ext-sub3>"
+           "</ext>";
+    lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+    yin_load_attributes(st->yin_ctx, &data, &args);
+    ret = yin_parse_extension_instance(st->yin_ctx, args, &data, name, name_len, LYEXT_SUBSTMT_CONTACT, 0, &exts);
+    assert_int_equal(ret, LY_SUCCESS);
+
+    assert_string_equal(exts->name, "ext");
+    assert_null(exts->argument);
+    assert_int_equal(exts->insubstmt, LYEXT_SUBSTMT_CONTACT);
+    assert_int_equal(exts->insubstmt_index, 0);
+    assert_true(exts->yin & LYS_YIN);
+    assert_string_equal(exts->child->stmt, "attr1");
+    assert_string_equal(exts->child->arg, "text1");
+    assert_null(exts->child->child);
+    assert_true(exts->child->flags & LYS_YIN_ATTR);
+
+    assert_string_equal(exts->child->next->stmt, "attr2");
+    assert_string_equal(exts->child->next->arg, "text2");
+    assert_null(exts->child->next->child);
+    assert_true(exts->child->next->flags & LYS_YIN_ATTR);
+
+    assert_string_equal(exts->child->next->next->stmt, "ext-sub1");
+    assert_null(exts->child->next->next->arg);
+    assert_null(exts->child->next->next->child);
+    assert_int_equal(exts->child->next->next->flags, 0);
+
+    assert_string_equal(exts->child->next->next->next->stmt, "ext-sub2");
+    assert_null(exts->child->next->next->next->arg);
+    assert_int_equal(exts->child->next->next->next->flags, 0);
+    assert_string_equal(exts->child->next->next->next->child->stmt, "sattr1");
+    assert_string_equal(exts->child->next->next->next->child->arg, "stext2");
+    assert_null(exts->child->next->next->next->child->child);
+    assert_true(exts->child->next->next->next->child->flags & LYS_YIN_ATTR);
+
+    assert_string_equal(exts->child->next->next->next->child->next->stmt, "ext-sub21");
+    assert_null(exts->child->next->next->next->child->next->arg);
+    assert_null(exts->child->next->next->next->child->next->next);
+    assert_int_equal(exts->child->next->next->next->child->next->flags, 0);
+
+    assert_string_equal(exts->child->next->next->next->child->next->child->stmt, "ext-sub211");
+    assert_null(exts->child->next->next->next->child->next->child->arg);
+    assert_int_equal(exts->child->next->next->next->child->next->child->flags, 0);
+    assert_null(exts->child->next->next->next->child->next->child->next);
+
+    assert_string_equal(exts->child->next->next->next->child->next->child->child->stmt, "sattr21");
+    assert_string_equal(exts->child->next->next->next->child->next->child->child->arg, "text21");
+    assert_null(exts->child->next->next->next->child->next->child->child->next);
+    assert_null(exts->child->next->next->next->child->next->child->child->child);
+    assert_true(exts->child->next->next->next->child->next->child->child->flags & LYS_YIN_ATTR);
+
+    assert_string_equal(exts->child->next->next->next->next->stmt, "ext-sub3");
+    assert_null(exts->child->next->next->next->next->arg);
+    assert_null(exts->child->next->next->next->next->next);
+    assert_int_equal(exts->child->next->next->next->next->flags, 0);
+
+    assert_string_equal(exts->child->next->next->next->next->child->stmt, "attr3");
+    assert_string_equal(exts->child->next->next->next->next->child->arg, "text3");
+    assert_null(exts->child->next->next->next->next->child->next);
+    assert_null(exts->child->next->next->next->next->child->child);
+    assert_true(exts->child->next->next->next->next->child->flags & LYS_YIN_ATTR);
+
+    LY_ARRAY_FREE(args);
+    lysp_ext_instance_free(st->ctx, exts);
+    LY_ARRAY_FREE(exts);
+    exts = NULL;
+    args = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_yin_parse_content(void **state)
+{
+    struct state *st = *state;
+    LY_ERR ret = LY_SUCCESS;
+    const char *name, *prefix;
+    size_t name_len, prefix_len;
+    const char *data = "<prefix value=\"a_mod\" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+                            "<custom xmlns=\"my-ext\">"
+                                "totally amazing extension"
+                            "</custom>"
+                            "<extension name=\"ext\">"
+                                "<argument name=\"argname\"></argument>"
+                                "<description><text>desc</text></description>"
+                                "<reference><text>ref</text></reference>"
+                                "<status value=\"deprecated\"></status>"
+                            "</extension>"
+                            "<text xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">wsefsdf</text>"
+                            "<if-feature name=\"foo\"></if-feature>"
+                            "<when condition=\"condition...\">"
+                                "<reference><text>when_ref</text></reference>"
+                                "<description><text>when_desc</text></description>"
+                            "</when>"
+                            "<config value=\"true\"/>"
+                            "<error-message>"
+                                "<value>error-msg</value>"
+                            "</error-message>"
+                            "<error-app-tag value=\"err-app-tag\"/>"
+                            "<units name=\"radians\"></units>"
+                            "<default value=\"default-value\"/>"
+                            "<position value=\"25\"></position>"
+                            "<value value=\"-5\"/>"
+                            "<require-instance value=\"true\"></require-instance>"
+                            "<range value=\"5..10\" />"
+                            "<length value=\"baf\"/>"
+                            "<pattern value='pattern'>"
+                                "<modifier value='invert-match'/>"
+                            "</pattern>"
+                            "<enum name=\"yay\">"
+                            "</enum>"
+                        "</prefix>";
+    struct lysp_ext_instance *exts = NULL;
+    const char **if_features = NULL;
+    struct yin_arg_record *attrs = NULL;
+    const char *value, *err_msg, *app_tag, *units, *def;
+    struct lysp_ext *ext_def = NULL;
+    struct lysp_when *when_p = NULL;
+    struct lysp_type_enum pos_enum = {}, val_enum = {};
+    struct lysp_type req_type = {}, range_type = {}, len_type = {}, patter_type = {}, enum_type = {};
+    uint8_t config = 0;
+
+    lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+    yin_load_attributes(st->yin_ctx, &data, &attrs);
+
+    struct yin_subelement subelems[17] = {
+                                            {YANG_CONFIG, &config, 0},
+                                            {YANG_DEFAULT, &def, YIN_SUBELEM_UNIQUE},
+                                            {YANG_ENUM, &enum_type, 0},
+                                            {YANG_ERROR_APP_TAG, &app_tag, YIN_SUBELEM_UNIQUE},
+                                            {YANG_ERROR_MESSAGE, &err_msg, 0},
+                                            {YANG_EXTENSION, &ext_def, 0},
+                                            {YANG_IF_FEATURE, &if_features, 0},
+                                            {YANG_LENGTH, &len_type, 0},
+                                            {YANG_PATTERN, &patter_type, 0},
+                                            {YANG_POSITION, &pos_enum, 0},
+                                            {YANG_RANGE, &range_type, 0},
+                                            {YANG_REQUIRE_INSTANCE, &req_type, 0},
+                                            {YANG_UNITS, &units, YIN_SUBELEM_UNIQUE},
+                                            {YANG_VALUE, &val_enum, 0},
+                                            {YANG_WHEN, &when_p, 0},
+                                            {YANG_CUSTOM, NULL, 0},
+                                            {YIN_TEXT, &value, 0}
+                                         };
+    ret = yin_parse_content(st->yin_ctx, subelems, 17, &data, YANG_PREFIX, NULL, &exts);
+    assert_int_equal(ret, LY_SUCCESS);
+    assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+    /* check parsed values */
+    assert_string_equal(def, "default-value");
+    assert_string_equal(exts->name, "custom");
+    assert_string_equal(exts->argument, "totally amazing extension");
+    assert_string_equal(value, "wsefsdf");
+    assert_string_equal(units, "radians");
+    assert_string_equal(when_p->cond, "condition...");
+    assert_string_equal(when_p->dsc, "when_desc");
+    assert_string_equal(when_p->ref, "when_ref");
+    assert_int_equal(config, LYS_CONFIG_W);
+    assert_int_equal(pos_enum.value, 25);
+    assert_true(pos_enum.flags & LYS_SET_VALUE);
+    assert_int_equal(val_enum.value, -5);
+    assert_true(val_enum.flags & LYS_SET_VALUE);
+    assert_int_equal(req_type.require_instance, 1);
+    assert_true(req_type.flags &= LYS_SET_REQINST);
+    assert_string_equal(range_type.range->arg, "5..10");
+    assert_true(range_type.flags & LYS_SET_RANGE);
+    assert_string_equal(err_msg, "error-msg");
+    assert_string_equal(app_tag, "err-app-tag");
+    assert_string_equal(enum_type.enums->name, "yay");
+    assert_string_equal(len_type.length->arg, "baf");
+    assert_true(len_type.flags & LYS_SET_LENGTH);
+    assert_string_equal(patter_type.patterns->arg, "\x015pattern");
+    assert_true(patter_type.flags & LYS_SET_PATTERN);
+    /* cleanup */
+    lysp_ext_instance_free(st->ctx, exts);
+    lysp_when_free(st->ctx, when_p);
+    lysp_ext_free(st->ctx, ext_def);
+    FREE_STRING(st->ctx, *if_features);
+    FREE_STRING(st->ctx, err_msg);
+    FREE_STRING(st->ctx, app_tag);
+    FREE_STRING(st->ctx, units);
+    FREE_STRING(st->ctx, patter_type.patterns->arg);
+    FREE_STRING(st->ctx, def);
+    FREE_STRING(st->ctx, range_type.range->arg);
+    FREE_STRING(st->ctx, len_type.length->arg);
+    FREE_STRING(st->ctx, enum_type.enums->name);
+    FREE_STRING(st->ctx, value);
+    LY_ARRAY_FREE(if_features);
+    LY_ARRAY_FREE(exts);
+    LY_ARRAY_FREE(ext_def);
+    LY_ARRAY_FREE(attrs);
+    LY_ARRAY_FREE(patter_type.patterns);
+    LY_ARRAY_FREE(enum_type.enums);
+    free(when_p);
+    free(range_type.range);
+    free(len_type.length);
+    attrs = NULL;
+    st = reset_state(state);
+
+    /* test unique subelem */
+    const char *prefix_value;
+    struct yin_subelement subelems2[2] = {{YANG_PREFIX, &prefix_value, YIN_SUBELEM_UNIQUE},
+                                         {YIN_TEXT, &value, YIN_SUBELEM_UNIQUE}};
+    data = ELEMENT_WRAPPER_START
+                "<prefix value=\"inv_mod\" />"
+                "<text xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">wsefsdf</text>"
+                "<text xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">wsefsdf</text>"
+           ELEMENT_WRAPPER_END;
+    lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+    yin_load_attributes(st->yin_ctx, &data, &attrs);
+    ret = yin_parse_content(st->yin_ctx, subelems2, 2, &data, YANG_STATUS, NULL, &exts);
+    assert_int_equal(ret, LY_EVALID);
+    logbuf_assert("Redefinition of \"text\" sub-element in \"status\" element. Line number 1.");
+    lydict_remove(st->ctx, prefix_value);
+    lydict_remove(st->ctx, value);
+    st = reset_state(state);
+    LY_ARRAY_FREE(attrs);
+    attrs = NULL;
+
+    /* test first subelem */
+    data = ELEMENT_WRAPPER_START
+                "<prefix value=\"inv_mod\" />"
+                "<text xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">wsefsdf</text>"
+                "<text xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">wsefsdf</text>"
+           ELEMENT_WRAPPER_END;
+    struct yin_subelement subelems3[2] = {{YANG_PREFIX, &prefix_value, YIN_SUBELEM_UNIQUE},
+                                         {YIN_TEXT, &value, YIN_SUBELEM_FIRST}};
+    lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+    yin_load_attributes(st->yin_ctx, &data, &attrs);
+    ret = yin_parse_content(st->yin_ctx, subelems3, 2, &data, YANG_STATUS, NULL, &exts);
+    assert_int_equal(ret, LY_EVALID);
+    logbuf_assert("Sub-element \"text\" of \"status\" element must be defined as it's first sub-element. Line number 1.");
+    lydict_remove(st->ctx, prefix_value);
+    st = reset_state(state);
+    LY_ARRAY_FREE(attrs);
+    attrs = NULL;
+
+    /* test mandatory subelem */
+    data = ELEMENT_WRAPPER_START ELEMENT_WRAPPER_END;
+    struct yin_subelement subelems4[1] = {{YANG_PREFIX, &prefix_value, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE}};
+    lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+    yin_load_attributes(st->yin_ctx, &data, &attrs);
+    ret = yin_parse_content(st->yin_ctx, subelems4, 1, &data, YANG_STATUS, NULL, &exts);
+    assert_int_equal(ret, LY_EVALID);
+    logbuf_assert("Missing mandatory sub-element \"prefix\" of \"status\" element. Line number 1.");
+    LY_ARRAY_FREE(attrs);
+
+    st->finished_correctly = true;
+}
+
+static void
+test_validate_value(void **state)
+{
+    struct state *st = *state;
+    assert_int_equal(yin_validate_value(st->yin_ctx, Y_IDENTIF_ARG, "#invalid", 8), LY_EVALID);
+    logbuf_assert("Invalid identifier character '#'. Line number 1.");
+    assert_int_equal(yin_validate_value(st->yin_ctx, Y_STR_ARG, "", 0), LY_SUCCESS);
+    assert_int_equal(yin_validate_value(st->yin_ctx, Y_IDENTIF_ARG, "pre:b", 5), LY_EVALID);
+    assert_int_equal(yin_validate_value(st->yin_ctx, Y_PREF_IDENTIF_ARG, "pre:b", 5), LY_SUCCESS);
+    assert_int_equal(yin_validate_value(st->yin_ctx, Y_PREF_IDENTIF_ARG, "pre:pre:b", 9), LY_EVALID);
+
+    st->finished_correctly = true;
+}
+
+/* helper function to simplify unit test of each element using parse_content function */
+LY_ERR
+test_element_helper(struct state *st, const char **data, void *dest, const char **text,
+                    struct lysp_ext_instance **exts, bool valid)
+{
+    struct yin_arg_record *attrs = NULL;
+    const char *name, *prefix;
+    size_t name_len, prefix_len;
+    LY_ERR ret = LY_SUCCESS;
+    struct yin_subelement subelems[71] = {
+                                            {YANG_ACTION, dest, 0},
+                                            {YANG_ANYDATA, dest, 0},
+                                            {YANG_ANYXML, dest, 0},
+                                            {YANG_ARGUMENT,dest, 0},
+                                            {YANG_AUGMENT, dest, 0},
+                                            {YANG_BASE, dest, 0},
+                                            {YANG_BELONGS_TO, dest, 0},
+                                            {YANG_BIT, dest, 0},
+                                            {YANG_CASE, dest, 0},
+                                            {YANG_CHOICE, dest, 0},
+                                            {YANG_CONFIG, dest, 0},
+                                            {YANG_CONTACT, dest, 0},
+                                            {YANG_CONTAINER, dest, 0},
+                                            {YANG_DEFAULT, dest, YIN_SUBELEM_UNIQUE},
+                                            {YANG_DESCRIPTION, dest, 0},
+                                            {YANG_DEVIATE, dest, 0},
+                                            {YANG_DEVIATION, dest, 0},
+                                            {YANG_ENUM, dest, 0},
+                                            {YANG_ERROR_APP_TAG, dest, YIN_SUBELEM_UNIQUE},
+                                            {YANG_ERROR_MESSAGE, dest, 0},
+                                            {YANG_EXTENSION, dest, 0},
+                                            {YANG_FEATURE, dest, 0},
+                                            {YANG_FRACTION_DIGITS, dest, 0},
+                                            {YANG_GROUPING, dest, 0},
+                                            {YANG_IDENTITY, dest, 0},
+                                            {YANG_IF_FEATURE, dest, 0},
+                                            {YANG_IMPORT, dest, 0},
+                                            {YANG_INCLUDE, dest, 0},
+                                            {YANG_INPUT, dest, 0},
+                                            {YANG_KEY, dest, YIN_SUBELEM_UNIQUE},
+                                            {YANG_LEAF, dest, 0},
+                                            {YANG_LEAF_LIST, dest, 0},
+                                            {YANG_LENGTH, dest, 0},
+                                            {YANG_LIST, dest, 0},
+                                            {YANG_MANDATORY, dest, 0},
+                                            {YANG_MAX_ELEMENTS, dest, 0},
+                                            {YANG_MIN_ELEMENTS, dest, 0},
+                                            {YANG_MODIFIER, dest, 0},
+                                            {YANG_MODULE, dest, 0},
+                                            {YANG_MUST, dest, 0},
+                                            {YANG_NAMESPACE, dest, YIN_SUBELEM_UNIQUE},
+                                            {YANG_NOTIFICATION, dest, 0},
+                                            {YANG_ORDERED_BY, dest, 0},
+                                            {YANG_ORGANIZATION, dest, 0},
+                                            {YANG_OUTPUT, dest, 0},
+                                            {YANG_PATH, dest, 0},
+                                            {YANG_PATTERN, dest, 0},
+                                            {YANG_POSITION, dest, 0},
+                                            {YANG_PREFIX, dest, YIN_SUBELEM_UNIQUE},
+                                            {YANG_PRESENCE, dest, YIN_SUBELEM_UNIQUE},
+                                            {YANG_RANGE, dest, 0},
+                                            {YANG_REFERENCE, dest, 0},
+                                            {YANG_REFINE, dest, 0},
+                                            {YANG_REQUIRE_INSTANCE, dest, 0},
+                                            {YANG_REVISION, dest, 0},
+                                            {YANG_REVISION_DATE, dest, 0},
+                                            {YANG_RPC, dest, 0},
+                                            {YANG_STATUS, dest, 0},
+                                            {YANG_SUBMODULE, dest, 0},
+                                            {YANG_TYPE, dest, 0},
+                                            {YANG_TYPEDEF, dest, 0},
+                                            {YANG_UNIQUE, dest, 0},
+                                            {YANG_UNITS, dest, YIN_SUBELEM_UNIQUE},
+                                            {YANG_USES, dest, 0},
+                                            {YANG_VALUE, dest, 0},
+                                            {YANG_WHEN, dest, 0},
+                                            {YANG_YANG_VERSION, dest, 0},
+                                            {YANG_YIN_ELEMENT, dest, 0},
+                                            {YANG_CUSTOM, dest, 0},
+                                            {YIN_TEXT, dest, 0},
+                                            {YIN_VALUE, dest, 0}
+                                        };
+    LY_CHECK_RET(lyxml_get_element(&st->yin_ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len));
+    LY_CHECK_RET(yin_load_attributes(st->yin_ctx, data, &attrs));
+    ret = yin_parse_content(st->yin_ctx, subelems, 71, data, yin_match_keyword(st->yin_ctx, name, name_len, prefix, prefix_len, YANG_NONE), text, exts);
+    LY_ARRAY_FREE(attrs);
+    if (valid) {
+        assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+    }
+    /* reset status */
+    st->yin_ctx->xml_ctx.status = LYXML_ELEMENT;
+    return ret;
+}
+
+#define EXT_SUBELEM "<myext:c-define name=\"MY_MTU\" xmlns:myext=\"urn:example:extensions\"/>"
+
+static void
+test_enum_elem(void **state)
+{
+    struct state *st = *state;
+    struct lysp_type type = {};
+    const char *data;
+    data = ELEMENT_WRAPPER_START
+           "<enum name=\"enum-name\">"
+                "<if-feature name=\"feature\" />"
+                "<value value=\"55\" />"
+                "<status value=\"deprecated\" />"
+                "<description><text>desc...</text></description>"
+                "<reference><text>ref...</text></reference>"
+                EXT_SUBELEM
+           "</enum>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(type.enums->name, "enum-name");
+    assert_string_equal(*type.enums->iffeatures, "feature");
+    assert_int_equal(type.enums->value, 55);
+    assert_true((type.enums->flags & LYS_STATUS_DEPRC) && (type.enums->flags & LYS_SET_VALUE));
+    assert_string_equal(type.enums->dsc, "desc...");
+    assert_string_equal(type.enums->ref, "ref...");
+    assert_string_equal(type.enums->exts->name, "myext:c-define");
+    assert_int_equal(type.enums->exts->insubstmt_index, 0);
+    assert_int_equal(type.enums->exts->insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_type_free(st->ctx, &type);
+    memset(&type, 0, sizeof type);
+
+    data = ELEMENT_WRAPPER_START
+           "<enum name=\"enum-name\"></enum>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(type.enums->name, "enum-name");
+    lysp_type_free(st->ctx, &type);
+    memset(&type, 0, sizeof type);
+
+    st->finished_correctly = true;
+}
+
+static void
+test_bit_elem(void **state)
+{
+    struct state *st = *state;
+    struct lysp_type type = {};
+    const char *data;
+    data = ELEMENT_WRAPPER_START
+           "<bit name=\"bit-name\">"
+                "<if-feature name=\"feature\" />"
+                "<position value=\"55\" />"
+                "<status value=\"deprecated\" />"
+                "<description><text>desc...</text></description>"
+                "<reference><text>ref...</text></reference>"
+                EXT_SUBELEM
+           "</bit>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(type.bits->name, "bit-name");
+    assert_string_equal(*type.bits->iffeatures, "feature");
+    assert_int_equal(type.bits->value, 55);
+    assert_true((type.bits->flags & LYS_STATUS_DEPRC) && (type.bits->flags & LYS_SET_VALUE));
+    assert_string_equal(type.bits->dsc, "desc...");
+    assert_string_equal(type.bits->ref, "ref...");
+    assert_string_equal(type.bits->exts->name, "myext:c-define");
+    assert_int_equal(type.bits->exts->insubstmt_index, 0);
+    assert_int_equal(type.bits->exts->insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_type_free(st->ctx, &type);
+    memset(&type, 0, sizeof type);
+
+    data = ELEMENT_WRAPPER_START
+           "<bit name=\"bit-name\"> </bit>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(type.bits->name, "bit-name");
+    lysp_type_free(st->ctx, &type);
+    memset(&type, 0, sizeof type);
+
+    st->finished_correctly = true;
+}
+
+static void
+test_meta_elem(void **state)
+{
+    struct state *st = *state;
+    char *value = NULL;
+    const char *data;
+    struct lysp_ext_instance *exts = NULL;
+
+    /* organization element */
+    data = ELEMENT_WRAPPER_START
+                "<organization><text>organization...</text>" EXT_SUBELEM EXT_SUBELEM "</organization>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &value, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_ORGANIZATION);
+    assert_string_equal(exts[1].name, "myext:c-define");
+    assert_int_equal(exts[1].insubstmt_index, 0);
+    assert_int_equal(exts[1].insubstmt, LYEXT_SUBSTMT_ORGANIZATION);
+    assert_string_equal(value, "organization...");
+    FREE_STRING(st->ctx, value);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    value = NULL;
+    exts = NULL;
+
+    /* contact element */
+    data = ELEMENT_WRAPPER_START
+                "<contact><text>contact...</text>" EXT_SUBELEM "</contact>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &value, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_CONTACT);
+    assert_string_equal(value, "contact...");
+    FREE_STRING(st->ctx, value);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+    value = NULL;
+
+    /* description element */
+    data = ELEMENT_WRAPPER_START
+                "<description><text>description...</text>" EXT_SUBELEM "</description>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &value, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(value, "description...");
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_DESCRIPTION);
+    FREE_STRING(st->ctx, value);
+    value = NULL;
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+
+    /* reference element */
+    data = ELEMENT_WRAPPER_START
+                "<reference><text>reference...</text>" EXT_SUBELEM "</reference>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &value, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(value, "reference...");
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_REFERENCE);
+    FREE_STRING(st->ctx, value);
+    value = NULL;
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+
+    /* reference element */
+    data = ELEMENT_WRAPPER_START
+                "<reference invalid=\"text\"><text>reference...</text>""</reference>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &value, NULL, &exts, false), LY_EVALID);
+    logbuf_assert("Unexpected attribute \"invalid\" of \"reference\" element. Line number 1.");
+    FREE_STRING(st->ctx, value);
+    value = NULL;
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+
+    /* missing text subelement */
+    data = ELEMENT_WRAPPER_START
+                "<reference>reference...</reference>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &value, NULL, &exts, false), LY_EVALID);
+    logbuf_assert("Missing mandatory sub-element \"text\" of \"reference\" element. Line number 1.");
+
+    /* reference element */
+    data = ELEMENT_WRAPPER_START
+                "<reference>" EXT_SUBELEM "<text>reference...</text></reference>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &value, NULL, &exts, false), LY_EVALID);
+    logbuf_assert("Sub-element \"text\" of \"reference\" element must be defined as it's first sub-element. Line number 1.");
+    FREE_STRING(st->ctx, value);
+    value = NULL;
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_import_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_import *imports = NULL;
+    struct import_meta imp_meta = {"prefix", &imports};
+
+    /* max subelems */
+    data = ELEMENT_WRAPPER_START
+                "<import module=\"a\">"
+                    EXT_SUBELEM
+                    "<prefix value=\"a_mod\"/>"
+                    "<revision-date date=\"2015-01-01\"></revision-date>"
+                    "<description><text>import description</text></description>"
+                    "<reference><text>import reference</text></reference>"
+                "</import>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &imp_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(imports->name, "a");
+    assert_string_equal(imports->prefix, "a_mod");
+    assert_string_equal(imports->rev, "2015-01-01");
+    assert_string_equal(imports->dsc, "import description");
+    assert_string_equal(imports->ref, "import reference");
+    assert_string_equal(imports->exts->name, "myext:c-define");
+    assert_int_equal(imports->exts->insubstmt, LYEXT_SUBSTMT_SELF);
+    assert_int_equal(imports->exts->insubstmt_index, 0);
+    FREE_ARRAY(st->ctx, imports, lysp_import_free);
+    imports = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START
+                "<import module=\"a\">"
+                    "<prefix value=\"a_mod\"/>"
+                "</import>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &imp_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(imports->prefix, "a_mod");
+    FREE_ARRAY(st->ctx, imports, lysp_import_free);
+    imports = NULL;
+
+    /* invalid (missing prefix) */
+    data = ELEMENT_WRAPPER_START "<import module=\"a\"></import>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &imp_meta, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Missing mandatory sub-element \"prefix\" of \"import\" element. Line number 1.");
+    FREE_ARRAY(st->ctx, imports, lysp_import_free);
+    imports = NULL;
+
+    /* invalid reused prefix */
+    data = ELEMENT_WRAPPER_START
+                "<import module=\"a\">"
+                    "<prefix value=\"prefix\"/>"
+                "</import>"
+                "<import module=\"a\">"
+                    "<prefix value=\"prefix\"/>"
+                "</import>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &imp_meta, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Prefix \"prefix\" already used as module prefix. Line number 1.");
+    FREE_ARRAY(st->ctx, imports, lysp_import_free);
+    imports = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_status_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    uint16_t flags = 0;
+    struct lysp_ext_instance *exts = NULL;
+
+    /* test valid values */
+    data = ELEMENT_WRAPPER_START "<status value=\"current\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, true), LY_SUCCESS);
+    assert_true(flags & LYS_STATUS_CURR);
+
+    data = ELEMENT_WRAPPER_START "<status value=\"deprecated\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, true), LY_SUCCESS);
+    assert_true(flags & LYS_STATUS_DEPRC);
+
+    data = ELEMENT_WRAPPER_START "<status value=\"obsolete\">"EXT_SUBELEM"</status>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &flags, NULL, &exts, true), LY_SUCCESS);
+    assert_true(flags & LYS_STATUS_OBSLT);
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_STATUS);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+
+    /* test invalid value */
+    data = ELEMENT_WRAPPER_START "<status value=\"invalid\"></status>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"invalid\" of \"value\" attribute in \"status\" element. Valid values are \"current\", \"deprecated\" and \"obsolete\". Line number 1.");
+    st->finished_correctly = true;
+}
+
+static void
+test_ext_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_ext *ext = NULL;
+
+    /* max subelems */
+    data = ELEMENT_WRAPPER_START
+           "<extension name=\"ext_name\">"
+                "<argument name=\"arg\"></argument>"
+                "<status value=\"current\"/>"
+                "<description><text>ext_desc</text></description>"
+                "<reference><text>ext_ref</text></reference>"
+                EXT_SUBELEM
+           "</extension>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &ext, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(ext->name, "ext_name");
+    assert_string_equal(ext->argument, "arg");
+    assert_true(ext->flags & LYS_STATUS_CURR);
+    assert_string_equal(ext->dsc, "ext_desc");
+    assert_string_equal(ext->ref, "ext_ref");
+    assert_string_equal(ext->exts[0].name, "myext:c-define");
+    assert_int_equal(ext->exts[0].insubstmt_index, 0);
+    assert_int_equal(ext->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_ext_free(st->ctx, ext);
+    LY_ARRAY_FREE(ext);
+    ext = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<extension name=\"ext_name\"></extension>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &ext, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(ext->name, "ext_name");
+    lysp_ext_free(st->ctx, ext);
+    LY_ARRAY_FREE(ext);
+    ext = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_yin_element_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    uint16_t flags = 0;
+    struct lysp_ext_instance *exts = NULL;
+
+    data = ELEMENT_WRAPPER_START "<yin-element value=\"true\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, true), LY_SUCCESS);
+    assert_true(flags & LYS_YINELEM_TRUE);
+
+    data = ELEMENT_WRAPPER_START "<yin-element value=\"false\">" EXT_SUBELEM "</yin-element>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &flags, NULL, &exts, true), LY_SUCCESS);
+    assert_true(flags & LYS_YINELEM_TRUE);
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_YINELEM);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+
+    data = ELEMENT_WRAPPER_START "<yin-element value=\"invalid\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, false), LY_EVALID);
+    assert_true(flags & LYS_YINELEM_TRUE);
+    logbuf_assert("Invalid value \"invalid\" of \"value\" attribute in \"yin-element\" element. Valid values are \"true\" and \"false\". Line number 1.");
+    st->finished_correctly = true;
+}
+
+static void
+test_yangversion_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    uint8_t version = 0;
+    struct lysp_ext_instance *exts = NULL;
+
+    /* valid values */
+    data = ELEMENT_WRAPPER_START "<yang-version value=\"1.0\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &version, NULL, NULL, true), LY_SUCCESS);
+    assert_true(version & LYS_VERSION_1_0);
+    assert_int_equal(st->yin_ctx->mod_version, LYS_VERSION_1_0);
+
+    data = ELEMENT_WRAPPER_START "<yang-version value=\"1.1\">" EXT_SUBELEM "</yang-version>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &version, NULL, &exts, true), LY_SUCCESS);
+    assert_true(version & LYS_VERSION_1_1);
+    assert_int_equal(st->yin_ctx->mod_version, LYS_VERSION_1_1);
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_VERSION);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+
+    /* invalid value */
+    data = ELEMENT_WRAPPER_START "<yang-version value=\"version\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &version, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"version\" of \"value\" attribute in \"yang-version\" element. Valid values are \"1.0\" and \"1.1\". Line number 1.");
+
+    st->finished_correctly = true;
+}
+
+static void
+test_mandatory_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    uint16_t man = 0;
+    struct lysp_ext_instance *exts = NULL;
+
+    /* valid values */
+    data = ELEMENT_WRAPPER_START "<mandatory value=\"true\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &man, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(man, LYS_MAND_TRUE);
+    man = 0;
+
+    data = ELEMENT_WRAPPER_START "<mandatory value=\"false\">" EXT_SUBELEM "</mandatory>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &man, NULL, &exts, true), LY_SUCCESS);
+    assert_int_equal(man, LYS_MAND_FALSE);
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_MANDATORY);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+
+    data = ELEMENT_WRAPPER_START "<mandatory value=\"invalid\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &man, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"invalid\" of \"value\" attribute in \"mandatory\" element. Valid values are \"true\" and \"false\". Line number 1.");
+
+    st->finished_correctly = true;
+}
+
+static void
+test_argument_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    uint16_t flags = 0;
+    const char *arg;
+    struct yin_argument_meta arg_meta = {&flags, &arg};
+    struct lysp_ext_instance *exts = NULL;
+
+    /* max subelems */
+    data = ELEMENT_WRAPPER_START
+           "<argument name=\"arg-name\">"
+                "<yin-element value=\"true\" />"
+                EXT_SUBELEM
+           "</argument>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &arg_meta, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(arg, "arg-name");
+    assert_true(flags & LYS_YINELEM_TRUE);
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_ARGUMENT);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+    flags = 0;
+    FREE_STRING(st->ctx, arg);
+    arg = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START
+           "<argument name=\"arg\">"
+           "</argument>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &arg_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(arg, "arg");
+    assert_true(flags == 0);
+    FREE_STRING(st->ctx, arg);
+
+    st->finished_correctly = true;
+}
+
+static void
+test_base_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    const char **bases = NULL;
+    struct lysp_ext_instance *exts = NULL;
+    struct lysp_type type = {};
+
+    /* as identity subelement */
+    data = "<identity xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+                "<base name=\"base-name\">"
+                    EXT_SUBELEM
+                "</base>"
+           "</identity>";
+    assert_int_equal(test_element_helper(st, &data, &bases, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(*bases, "base-name");
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_BASE);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+    FREE_STRING(st->ctx, *bases);
+    LY_ARRAY_FREE(bases);
+
+    /* as type subelement */
+    data = "<type xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+                "<base name=\"base-name\">"
+                    EXT_SUBELEM
+                "</base>"
+           "</type>";
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(*type.bases, "base-name");
+    assert_true(type.flags & LYS_SET_BASE);
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_BASE);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+    FREE_STRING(st->ctx, *type.bases);
+    LY_ARRAY_FREE(type.bases);
+
+    st->finished_correctly = true;
+}
+
+static void
+test_belongsto_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_submodule submod;
+    struct lysp_ext_instance *exts = NULL;
+
+    data = ELEMENT_WRAPPER_START
+                "<belongs-to module=\"module-name\"><prefix value=\"pref\"/>"EXT_SUBELEM"</belongs-to>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &submod, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(submod.belongsto, "module-name");
+    assert_string_equal(submod.prefix, "pref");
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_BELONGSTO);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+    FREE_STRING(st->ctx, submod.belongsto);
+    FREE_STRING(st->ctx, submod.prefix);
+
+    data = ELEMENT_WRAPPER_START "<belongs-to module=\"module-name\"></belongs-to>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &submod, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Missing mandatory sub-element \"prefix\" of \"belongs-to\" element. Line number 1.");
+    FREE_STRING(st->ctx, submod.belongsto);
+
+    st->finished_correctly = true;
+}
+
+static void
+test_config_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    uint16_t flags = 0;
+    struct lysp_ext_instance *exts = NULL;
+
+    data = ELEMENT_WRAPPER_START "<config value=\"true\">" EXT_SUBELEM "</config>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &flags, NULL, &exts, true), LY_SUCCESS);
+    assert_true(flags & LYS_CONFIG_W);
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_CONFIG);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+    flags = 0;
+
+    data = ELEMENT_WRAPPER_START "<config value=\"false\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, true), LY_SUCCESS);
+    assert_true(flags & LYS_CONFIG_R);
+    flags = 0;
+
+    data = ELEMENT_WRAPPER_START "<config value=\"invalid\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"invalid\" of \"value\" attribute in \"config\" element. Valid values are \"true\" and \"false\". Line number 1.");
+
+    st->finished_correctly = true;
+}
+
+static void
+test_default_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    const char *val = NULL;
+    struct lysp_ext_instance *exts = NULL;
+
+    data = ELEMENT_WRAPPER_START "<default value=\"defaul-value\">"EXT_SUBELEM"</default>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &val, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(val, "defaul-value");
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_DEFAULT);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+    FREE_STRING(st->ctx, val);
+    val = NULL;
+
+    data = ELEMENT_WRAPPER_START "<default/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Missing mandatory attribute value of default element. Line number 1.");
+
+    st->finished_correctly = true;
+}
+
+static void
+test_err_app_tag_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    const char *val = NULL;
+    struct lysp_ext_instance *exts = NULL;
+
+    data = ELEMENT_WRAPPER_START "<error-app-tag value=\"val\">"EXT_SUBELEM"</error-app-tag>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &val, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(val, "val");
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_ERRTAG);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+    FREE_STRING(st->ctx, val);
+    val = NULL;
+
+    data = ELEMENT_WRAPPER_START "<error-app-tag/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Missing mandatory attribute value of error-app-tag element. Line number 1.");
+
+    st->finished_correctly = true;
+}
+
+static void
+test_err_msg_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    const char *val = NULL;
+    struct lysp_ext_instance *exts = NULL;
+
+    data = ELEMENT_WRAPPER_START "<error-message><value>val</value>"EXT_SUBELEM"</error-message>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &val, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(val, "val");
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_ERRMSG);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+    FREE_STRING(st->ctx, val);
+
+    data = ELEMENT_WRAPPER_START "<error-message></error-message>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Missing mandatory sub-element \"value\" of \"error-message\" element. Line number 1.");
+
+    data = ELEMENT_WRAPPER_START "<error-message invalid=\"text\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Unexpected attribute \"invalid\" of \"error-message\" element. Line number 1.");
+
+    st->finished_correctly = true;
+}
+
+static void
+test_fracdigits_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_type type = {};
+
+    /* valid value */
+    data = ELEMENT_WRAPPER_START "<fraction-digits value=\"10\">"EXT_SUBELEM"</fraction-digits>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(type.exts[0].name, "myext:c-define");
+    assert_int_equal(type.exts[0].insubstmt_index, 0);
+    assert_int_equal(type.exts[0].insubstmt, LYEXT_SUBSTMT_FRACDIGITS);
+    assert_int_equal(type.fraction_digits, 10);
+    assert_true(type.flags & LYS_SET_FRDIGITS);
+    FREE_ARRAY(st->ctx, type.exts, lysp_ext_instance_free);
+
+    /* invalid values */
+    data = ELEMENT_WRAPPER_START "<fraction-digits value=\"-1\"></fraction-digits>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"-1\" of \"value\" attribute in \"fraction-digits\" element. Line number 1.");
+
+    data = ELEMENT_WRAPPER_START "<fraction-digits value=\"02\"></fraction-digits>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"02\" of \"value\" attribute in \"fraction-digits\" element. Line number 1.");
+
+    data = ELEMENT_WRAPPER_START "<fraction-digits value=\"1p\"></fraction-digits>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"1p\" of \"value\" attribute in \"fraction-digits\" element. Line number 1.");
+
+    data = ELEMENT_WRAPPER_START "<fraction-digits value=\"19\"></fraction-digits>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"19\" of \"value\" attribute in \"fraction-digits\" element. Line number 1.");
+
+    data = ELEMENT_WRAPPER_START "<fraction-digits value=\"999999999999999999\"></fraction-digits>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"999999999999999999\" of \"value\" attribute in \"fraction-digits\" element. Line number 1.");
+
+    st->finished_correctly = true;
+}
+
+static void
+test_iffeature_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    const char **iffeatures = NULL;
+    struct lysp_ext_instance *exts = NULL;
+
+    data = ELEMENT_WRAPPER_START "<if-feature name=\"local-storage\">"EXT_SUBELEM"</if-feature>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &iffeatures, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(*iffeatures, "local-storage");
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_IFFEATURE);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+    FREE_STRING(st->ctx, *iffeatures);
+    LY_ARRAY_FREE(iffeatures);
+    iffeatures = NULL;
+
+    data = ELEMENT_WRAPPER_START "<if-feature/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &iffeatures, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Missing mandatory attribute name of if-feature element. Line number 1.");
+    LY_ARRAY_FREE(iffeatures);
+    iffeatures = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_length_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_type type = {};
+
+    /* max subelems */
+    data = ELEMENT_WRAPPER_START
+                "<length value=\"length-str\">"
+                    "<error-message><value>err-msg</value></error-message>"
+                    "<error-app-tag value=\"err-app-tag\"/>"
+                    "<description><text>desc</text></description>"
+                    "<reference><text>ref</text></reference>"
+                    EXT_SUBELEM
+                "</length>"
+            ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(type.length->arg, "length-str");
+    assert_string_equal(type.length->emsg, "err-msg");
+    assert_string_equal(type.length->eapptag, "err-app-tag");
+    assert_string_equal(type.length->dsc, "desc");
+    assert_string_equal(type.length->ref, "ref");
+    assert_true(type.flags & LYS_SET_LENGTH);
+    assert_string_equal(type.length->exts[0].name, "myext:c-define");
+    assert_int_equal(type.length->exts[0].insubstmt_index, 0);
+    assert_int_equal(type.length->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_type_free(st->ctx, &type);
+    memset(&type, 0, sizeof(type));
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START
+                "<length value=\"length-str\">"
+                "</length>"
+            ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(type.length->arg, "length-str");
+    lysp_type_free(st->ctx, &type);
+    assert_true(type.flags & LYS_SET_LENGTH);
+    memset(&type, 0, sizeof(type));
+
+    data = ELEMENT_WRAPPER_START "<length></length>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Missing mandatory attribute value of length element. Line number 1.");
+    lysp_type_free(st->ctx, &type);
+    memset(&type, 0, sizeof(type));
+
+    st->finished_correctly = true;
+}
+
+static void
+test_modifier_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    const char *pat = lydict_insert(st->ctx, "\006pattern", 8);
+    struct lysp_ext_instance *exts = NULL;
+
+    data = ELEMENT_WRAPPER_START "<modifier value=\"invert-match\">" EXT_SUBELEM "</modifier>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &pat, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(pat, "\x015pattern");
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_MODIFIER);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+    FREE_STRING(st->ctx, pat);
+
+    pat = lydict_insert(st->ctx, "\006pattern", 8);
+    data = ELEMENT_WRAPPER_START "<modifier value=\"invert\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &pat, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"invert\" of \"value\" attribute in \"modifier\" element. Only valid value is \"invert-match\". Line number 1.");
+    FREE_STRING(st->ctx, pat);
+
+    st->finished_correctly = true;
+}
+
+static void
+test_namespace_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    const char *ns;
+    struct lysp_ext_instance *exts = NULL;
+
+    data = ELEMENT_WRAPPER_START "<namespace uri=\"ns\">" EXT_SUBELEM "</namespace>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &ns, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(ns, "ns");
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_NAMESPACE);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+    FREE_STRING(st->ctx, ns);
+
+    data = ELEMENT_WRAPPER_START "<namespace/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &ns, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Missing mandatory attribute uri of namespace element. Line number 1.");
+
+    st->finished_correctly = true;
+}
+
+static void
+test_path_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_type type = {};
+
+    data = ELEMENT_WRAPPER_START "<path value=\"p&amp;th-val\">" EXT_SUBELEM "</path>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal("p&th-val", type.path);
+    assert_true(type.flags & LYS_SET_PATH);
+    assert_string_equal(type.exts[0].name, "myext:c-define");
+    assert_int_equal(type.exts[0].insubstmt_index, 0);
+    assert_int_equal(type.exts[0].insubstmt, LYEXT_SUBSTMT_PATH);
+    lysp_type_free(st->ctx, &type);
+
+    st->finished_correctly = true;
+}
+
+static void
+test_pattern_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_type type = {};
+
+    /* max subelems */
+    data = ELEMENT_WRAPPER_START
+                "<pattern value=\"super_pattern\">"
+                    "<modifier value=\"invert-match\"/>"
+                    "<error-message><value>err-msg-value</value></error-message>"
+                    "<error-app-tag value=\"err-app-tag-value\"/>"
+                    "<description><text>&quot;pattern-desc&quot;</text></description>"
+                    "<reference><text>pattern-ref</text></reference>"
+                    EXT_SUBELEM
+                "</pattern>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+    assert_true(type.flags & LYS_SET_PATTERN);
+    assert_string_equal(type.patterns->arg, "\x015super_pattern");
+    assert_string_equal(type.patterns->dsc, "\"pattern-desc\"");
+    assert_string_equal(type.patterns->eapptag, "err-app-tag-value");
+    assert_string_equal(type.patterns->emsg, "err-msg-value");
+    assert_string_equal(type.patterns->ref, "pattern-ref");
+    assert_string_equal(type.patterns->exts[0].name, "myext:c-define");
+    assert_int_equal(type.patterns->exts[0].insubstmt_index, 0);
+    assert_int_equal(type.patterns->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_type_free(st->ctx, &type);
+    memset(&type, 0, sizeof(type));
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<pattern value=\"pattern\"> </pattern>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(type.patterns->arg, "\x006pattern");
+    lysp_type_free(st->ctx, &type);
+    memset(&type, 0, sizeof(type));
+
+    st->finished_correctly = true;
+}
+
+static void
+test_value_position_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_type_enum en = {};
+
+    /* valid values */
+    data = ELEMENT_WRAPPER_START "<value value=\"55\">" EXT_SUBELEM "</value>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(en.value, 55);
+    assert_true(en.flags & LYS_SET_VALUE);
+    assert_string_equal(en.exts[0].name, "myext:c-define");
+    assert_int_equal(en.exts[0].insubstmt_index, 0);
+    assert_int_equal(en.exts[0].insubstmt, LYEXT_SUBSTMT_VALUE);
+    FREE_ARRAY(st->ctx, en.exts, lysp_ext_instance_free);
+    memset(&en, 0, sizeof(en));
+
+    data = ELEMENT_WRAPPER_START "<value value=\"-55\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(en.value, -55);
+    assert_true(en.flags & LYS_SET_VALUE);
+    memset(&en, 0, sizeof(en));
+
+    data = ELEMENT_WRAPPER_START "<value value=\"0\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(en.value, 0);
+    assert_true(en.flags & LYS_SET_VALUE);
+    memset(&en, 0, sizeof(en));
+
+    data = ELEMENT_WRAPPER_START "<value value=\"-0\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(en.value, 0);
+    assert_true(en.flags & LYS_SET_VALUE);
+    memset(&en, 0, sizeof(en));
+
+    /* valid positions */
+    data = ELEMENT_WRAPPER_START "<position value=\"55\">" EXT_SUBELEM "</position>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(en.value, 55);
+    assert_true(en.flags & LYS_SET_VALUE);
+    assert_string_equal(en.exts[0].name, "myext:c-define");
+    assert_int_equal(en.exts[0].insubstmt_index, 0);
+    assert_int_equal(en.exts[0].insubstmt, LYEXT_SUBSTMT_POSITION);
+    FREE_ARRAY(st->ctx, en.exts, lysp_ext_instance_free);
+    memset(&en, 0, sizeof(en));
+
+    data = ELEMENT_WRAPPER_START "<position value=\"0\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(en.value, 0);
+    assert_true(en.flags & LYS_SET_VALUE);
+    memset(&en, 0, sizeof(en));
+
+    /* invalid values */
+    data = ELEMENT_WRAPPER_START "<value value=\"99999999999999999999999\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"99999999999999999999999\" of \"value\" attribute in \"value\" element. Line number 1.");
+
+    data = ELEMENT_WRAPPER_START "<value value=\"1k\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"1k\" of \"value\" attribute in \"value\" element. Line number 1.");
+
+    data = ELEMENT_WRAPPER_START "<value value=\"\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"\" of \"value\" attribute in \"value\" element. Line number 1.");
+
+    /*invalid positions */
+    data = ELEMENT_WRAPPER_START "<position value=\"-5\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"-5\" of \"value\" attribute in \"position\" element. Line number 1.");
+
+    data = ELEMENT_WRAPPER_START "<position value=\"-0\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"-0\" of \"value\" attribute in \"position\" element. Line number 1.");
+
+    data = ELEMENT_WRAPPER_START "<position value=\"99999999999999999999\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"99999999999999999999\" of \"value\" attribute in \"position\" element. Line number 1.");
+
+    data = ELEMENT_WRAPPER_START "<position value=\"\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"\" of \"value\" attribute in \"position\" element. Line number 1.");
+
+    st->finished_correctly = true;
+}
+
+static void
+test_prefix_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    const char *value = NULL;
+    struct lysp_ext_instance *exts = NULL;
+
+    data = ELEMENT_WRAPPER_START "<prefix value=\"pref\">" EXT_SUBELEM "</prefix>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &value, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(value, "pref");
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_PREFIX);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    exts = NULL;
+    FREE_STRING(st->ctx, value);
+
+    data = ELEMENT_WRAPPER_START "<prefix value=\"pref\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &value, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(value, "pref");
+    FREE_STRING(st->ctx, value);
+
+    st->finished_correctly = true;
+}
+
+static void
+test_range_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_type type = {};
+
+    /* max subelems */
+    data = ELEMENT_WRAPPER_START
+                "<range value=\"range-str\">"
+                    "<error-message><value>err-msg</value></error-message>"
+                    "<error-app-tag value=\"err-app-tag\" />"
+                    "<description><text>desc</text></description>"
+                    "<reference><text>ref</text></reference>"
+                    EXT_SUBELEM
+                "</range>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(type.range->arg, "range-str");
+    assert_string_equal(type.range->dsc, "desc");
+    assert_string_equal(type.range->eapptag, "err-app-tag");
+    assert_string_equal(type.range->emsg, "err-msg");
+    assert_string_equal(type.range->ref, "ref");
+    assert_true(type.flags & LYS_SET_RANGE);
+    assert_string_equal(type.range->exts[0].name, "myext:c-define");
+    assert_int_equal(type.range->exts[0].insubstmt_index, 0);
+    assert_int_equal(type.range->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_type_free(st->ctx, &type);
+    memset(&type, 0, sizeof(type));
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<range value=\"range-str\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(type.range->arg, "range-str");
+    lysp_type_free(st->ctx, &type);
+    memset(&type, 0, sizeof(type));
+
+    st->finished_correctly = true;
+}
+
+static void
+test_reqinstance_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_type type = {};
+
+    data = ELEMENT_WRAPPER_START "<require-instance value=\"true\">" EXT_SUBELEM "</require-instance>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(type.require_instance, 1);
+    assert_true(type.flags & LYS_SET_REQINST);
+    assert_string_equal(type.exts[0].name, "myext:c-define");
+    assert_int_equal(type.exts[0].insubstmt_index, 0);
+    assert_int_equal(type.exts[0].insubstmt, LYEXT_SUBSTMT_REQINSTANCE);
+    lysp_type_free(st->ctx, &type);
+    memset(&type, 0, sizeof(type));
+
+    data = ELEMENT_WRAPPER_START "<require-instance value=\"false\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(type.require_instance, 0);
+    assert_true(type.flags & LYS_SET_REQINST);
+    memset(&type, 0, sizeof(type));
+
+    data = ELEMENT_WRAPPER_START "<require-instance value=\"invalid\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, false), LY_EVALID);
+    memset(&type, 0, sizeof(type));
+    logbuf_assert("Invalid value \"invalid\" of \"value\" attribute in \"require-instance\" element. Valid values are \"true\" and \"false\". Line number 1.");
+
+    st->finished_correctly = true;
+}
+
+static void
+test_revision_date_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    char rev[LY_REV_SIZE];
+    struct lysp_ext_instance *exts = NULL;
+
+    data = ELEMENT_WRAPPER_START "<revision-date date=\"2000-01-01\">"EXT_SUBELEM"</revision-date>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, rev, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(rev, "2000-01-01");
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_REVISIONDATE);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+
+    data = ELEMENT_WRAPPER_START "<revision-date date=\"2000-01-01\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, rev, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(rev, "2000-01-01");
+
+    data = ELEMENT_WRAPPER_START "<revision-date date=\"2000-50-05\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, rev, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"2000-50-05\" of \"revision-date\". Line number 1.");
+
+    st->finished_correctly = true;
+}
+
+static void
+test_unique_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    const char **values = NULL;
+    struct lysp_ext_instance *exts = NULL;
+
+    data = ELEMENT_WRAPPER_START "<unique tag=\"tag\">"EXT_SUBELEM"</unique>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &values, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(*values, "tag");
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_UNIQUE);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    FREE_STRING(st->ctx, *values);
+    LY_ARRAY_FREE(values);
+    values = NULL;
+
+    data = ELEMENT_WRAPPER_START "<unique tag=\"tag\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &values, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(*values, "tag");
+    FREE_STRING(st->ctx, *values);
+    LY_ARRAY_FREE(values);
+    values = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_units_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    const char *values = NULL;
+    struct lysp_ext_instance *exts = NULL;
+
+    data = ELEMENT_WRAPPER_START "<units name=\"name\">"EXT_SUBELEM"</units>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &values, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(values, "name");
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_UNITS);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    FREE_STRING(st->ctx, values);
+    values = NULL;
+
+    data = ELEMENT_WRAPPER_START "<units name=\"name\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &values, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(values, "name");
+    FREE_STRING(st->ctx, values);
+    values = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_when_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_when *when = NULL;
+
+    data = ELEMENT_WRAPPER_START
+                "<when condition=\"cond\">"
+                    "<description><text>desc</text></description>"
+                    "<reference><text>ref</text></reference>"
+                    EXT_SUBELEM
+                "</when>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &when, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(when->cond, "cond");
+    assert_string_equal(when->dsc, "desc");
+    assert_string_equal(when->ref, "ref");
+    assert_string_equal(when->exts[0].name, "myext:c-define");
+    assert_int_equal(when->exts[0].insubstmt_index, 0);
+    assert_int_equal(when->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_when_free(st->ctx, when);
+    free(when);
+    when = NULL;
+
+    data = ELEMENT_WRAPPER_START "<when condition=\"cond\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &when, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(when->cond, "cond");
+    lysp_when_free(st->ctx, when);
+    free(when);
+    when = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_yin_text_value_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    const char *val;
+
+    data = ELEMENT_WRAPPER_START "<text>text</text>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(val, "text");
+    FREE_STRING(st->ctx, val);
+
+    data = "<error-message xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <value>text</value> </error-message>";
+    assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(val, "text");
+    FREE_STRING(st->ctx, val);
+
+    data = ELEMENT_WRAPPER_START "<text></text>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal("", val);
+    FREE_STRING(st->ctx, val);
+
+    st->finished_correctly = true;
+}
+
+static void
+test_type_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_type type = {};
+
+    /* max subelems */
+    data = ELEMENT_WRAPPER_START
+                "<type name=\"type-name\">"
+                    "<base name=\"base-name\"/>"
+                    "<bit name=\"bit\"/>"
+                    "<enum name=\"enum\"/>"
+                    "<fraction-digits value=\"2\"/>"
+                    "<length value=\"length\"/>"
+                    "<path value=\"path\"/>"
+                    "<pattern value=\"pattern\"/>"
+                    "<range value=\"range\" />"
+                    "<require-instance value=\"true\"/>"
+                    "<type name=\"sub-type-name\"/>"
+                    EXT_SUBELEM
+                "</type>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(type.name, "type-name");
+    assert_string_equal(*type.bases, "base-name");
+    assert_string_equal(type.bits->name,  "bit");
+    assert_string_equal(type.enums->name,  "enum");
+    assert_int_equal(type.fraction_digits, 2);
+    assert_string_equal(type.length->arg, "length");
+    assert_string_equal(type.path, "path");
+    assert_string_equal(type.patterns->arg, "\006pattern");
+    assert_string_equal(type.range->arg, "range");
+    assert_int_equal(type.require_instance, 1);
+    assert_string_equal(type.types->name, "sub-type-name");
+    assert_string_equal(type.exts[0].name, "myext:c-define");
+    assert_int_equal(type.exts[0].insubstmt_index, 0);
+    assert_int_equal(type.exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    assert_true(type.flags & LYS_SET_BASE);
+    assert_true(type.flags & LYS_SET_BIT);
+    assert_true(type.flags & LYS_SET_ENUM);
+    assert_true(type.flags & LYS_SET_FRDIGITS);
+    assert_true(type.flags & LYS_SET_LENGTH);
+    assert_true(type.flags & LYS_SET_PATH);
+    assert_true(type.flags & LYS_SET_PATTERN);
+    assert_true(type.flags & LYS_SET_RANGE);
+    assert_true(type.flags & LYS_SET_REQINST);
+    assert_true(type.flags & LYS_SET_TYPE);
+    lysp_type_free(st->ctx, &type);
+    memset(&type, 0, sizeof(type));
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<type name=\"type-name\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+    lysp_type_free(st->ctx, &type);
+    memset(&type, 0, sizeof(type));
+
+    st->finished_correctly = true;
+}
+
+static void
+test_max_elems_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_node_list list = {};
+    struct lysp_node_leaflist llist = {};
+    struct lysp_refine refine = {};
+
+    data = "<refine xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <max-elements value=\"unbounded\">"EXT_SUBELEM"</max-elements> </refine>";
+    assert_int_equal(test_element_helper(st, &data, &refine, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(refine.max, 0);
+    assert_true(refine.flags & LYS_SET_MAX);
+    assert_string_equal(refine.exts[0].name, "myext:c-define");
+    assert_int_equal(refine.exts[0].insubstmt_index, 0);
+    assert_int_equal(refine.exts[0].insubstmt, LYEXT_SUBSTMT_MAX);
+    FREE_ARRAY(st->ctx, refine.exts, lysp_ext_instance_free);
+
+    data = "<list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <max-elements value=\"5\">"EXT_SUBELEM"</max-elements> </list>";
+    assert_int_equal(test_element_helper(st, &data, &list, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(list.max, 5);
+    assert_true(list.flags & LYS_SET_MAX);
+    assert_string_equal(list.exts[0].name, "myext:c-define");
+    assert_int_equal(list.exts[0].insubstmt_index, 0);
+    assert_int_equal(list.exts[0].insubstmt, LYEXT_SUBSTMT_MAX);
+    FREE_ARRAY(st->ctx, list.exts, lysp_ext_instance_free);
+
+    data = "<leaf-list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <max-elements value=\"85\">"EXT_SUBELEM"</max-elements> </leaf-list>";
+    assert_int_equal(test_element_helper(st, &data, &llist, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(llist.max, 85);
+    assert_true(llist.flags & LYS_SET_MAX);
+    assert_string_equal(llist.exts[0].name, "myext:c-define");
+    assert_int_equal(llist.exts[0].insubstmt_index, 0);
+    assert_int_equal(llist.exts[0].insubstmt, LYEXT_SUBSTMT_MAX);
+    FREE_ARRAY(st->ctx, llist.exts, lysp_ext_instance_free);
+
+    data = "<refine xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <max-elements value=\"10\"/> </refine>";
+    assert_int_equal(test_element_helper(st, &data, &refine, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(refine.max, 10);
+    assert_true(refine.flags & LYS_SET_MAX);
+
+    data = "<list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <max-elements value=\"0\"/> </list>";
+    assert_int_equal(test_element_helper(st, &data, &list, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"0\" of \"value\" attribute in \"max-elements\" element. Line number 1.");
+
+    data = "<list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <max-elements value=\"-10\"/> </list>";
+    assert_int_equal(test_element_helper(st, &data, &list, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"-10\" of \"value\" attribute in \"max-elements\" element. Line number 1.");
+
+    data = "<list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <max-elements value=\"k\"/> </list>";
+    assert_int_equal(test_element_helper(st, &data, &list, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"k\" of \"value\" attribute in \"max-elements\" element. Line number 1.");
+
+    data = "<list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <max-elements value=\"u12\"/> </list>";
+    assert_int_equal(test_element_helper(st, &data, &list, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"u12\" of \"value\" attribute in \"max-elements\" element. Line number 1.");
+
+    st->finished_correctly = true;
+}
+
+static void
+test_min_elems_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_node_list list = {};
+    struct lysp_node_leaflist llist = {};
+    struct lysp_refine refine = {};
+
+    data = "<refine xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <min-elements value=\"0\">"EXT_SUBELEM"</min-elements> </refine>";
+    assert_int_equal(test_element_helper(st, &data, &refine, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(refine.min, 0);
+    assert_true(refine.flags & LYS_SET_MIN);
+    assert_string_equal(refine.exts[0].name, "myext:c-define");
+    assert_int_equal(refine.exts[0].insubstmt_index, 0);
+    assert_int_equal(refine.exts[0].insubstmt, LYEXT_SUBSTMT_MIN);
+    FREE_ARRAY(st->ctx, refine.exts, lysp_ext_instance_free);
+
+    data = "<list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <min-elements value=\"41\">"EXT_SUBELEM"</min-elements> </list>";
+    assert_int_equal(test_element_helper(st, &data, &list, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(list.min, 41);
+    assert_true(list.flags & LYS_SET_MIN);
+    assert_string_equal(list.exts[0].name, "myext:c-define");
+    assert_int_equal(list.exts[0].insubstmt_index, 0);
+    assert_int_equal(list.exts[0].insubstmt, LYEXT_SUBSTMT_MIN);
+    FREE_ARRAY(st->ctx, list.exts, lysp_ext_instance_free);
+
+    data = "<leaf-list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <min-elements value=\"50\">"EXT_SUBELEM"</min-elements> </leaf-list>";
+    assert_int_equal(test_element_helper(st, &data, &llist, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(llist.min, 50);
+    assert_true(llist.flags & LYS_SET_MIN);
+    assert_string_equal(llist.exts[0].name, "myext:c-define");
+    assert_int_equal(llist.exts[0].insubstmt_index, 0);
+    assert_int_equal(llist.exts[0].insubstmt, LYEXT_SUBSTMT_MIN);
+    FREE_ARRAY(st->ctx, llist.exts, lysp_ext_instance_free);
+
+    data = "<leaf-list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <min-elements value=\"-5\"/> </leaf-list>";
+    assert_int_equal(test_element_helper(st, &data, &llist, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Value \"-5\" of \"value\" attribute in \"min-elements\" element is out of bounds. Line number 1.");
+
+    data = "<leaf-list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <min-elements value=\"99999999999999999\"/> </leaf-list>";
+    assert_int_equal(test_element_helper(st, &data, &llist, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Value \"99999999999999999\" of \"value\" attribute in \"min-elements\" element is out of bounds. Line number 1.");
+
+    data = "<leaf-list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <min-elements value=\"5k\"/> </leaf-list>";
+    assert_int_equal(test_element_helper(st, &data, &llist, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"5k\" of \"value\" attribute in \"min-elements\" element. Line number 1.");
+
+    data = "<leaf-list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <min-elements value=\"05\"/> </leaf-list>";
+    assert_int_equal(test_element_helper(st, &data, &llist, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"05\" of \"value\" attribute in \"min-elements\" element. Line number 1.");
+
+    st->finished_correctly = true;
+}
+
+static void
+test_ordby_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    uint16_t flags = 0;
+    struct lysp_ext_instance *exts = NULL;
+
+    data = ELEMENT_WRAPPER_START "<ordered-by value=\"system\">"EXT_SUBELEM"</ordered-by>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &flags, NULL, &exts, true), LY_SUCCESS);
+    assert_true(flags & LYS_ORDBY_SYSTEM);
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_ORDEREDBY);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+
+    data = ELEMENT_WRAPPER_START "<ordered-by value=\"user\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, true), LY_SUCCESS);
+    assert_true(flags & LYS_ORDBY_USER);
+
+    data = ELEMENT_WRAPPER_START "<ordered-by value=\"inv\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"inv\" of \"value\" attribute in \"ordered-by\" element. Valid values are \"system\" and \"user\". Line number 1.");
+
+    st->finished_correctly = true;
+}
+
+static void
+test_any_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_node *siblings = NULL;
+    struct tree_node_meta node_meta = {.parent = NULL, .nodes = &siblings};
+    struct lysp_node_anydata *parsed = NULL;
+
+    /* anyxml max subelems */
+    data = ELEMENT_WRAPPER_START
+                "<anyxml name=\"any-name\">"
+                    "<config value=\"true\" />"
+                    "<description><text>desc</text></description>"
+                    "<if-feature name=\"feature\" />"
+                    "<mandatory value=\"true\" />"
+                    "<must condition=\"must-cond\" />"
+                    "<reference><text>ref</text></reference>"
+                    "<status value=\"deprecated\"/>"
+                    "<when condition=\"when-cond\"/>"
+                    EXT_SUBELEM
+                "</anyxml>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_anydata *)siblings;
+    assert_null(parsed->parent);
+    assert_int_equal(parsed->nodetype, LYS_ANYXML);
+    assert_true(parsed->flags & LYS_CONFIG_W);
+    assert_true(parsed->flags & LYS_MAND_TRUE);
+    assert_true(parsed->flags & LYS_STATUS_DEPRC);
+    assert_null(parsed->next);
+    assert_string_equal(parsed->name, "any-name");
+    assert_string_equal(parsed->dsc, "desc");
+    assert_string_equal(parsed->ref, "ref");
+    assert_string_equal(parsed->when->cond, "when-cond");
+    assert_string_equal(*parsed->iffeatures, "feature");
+    assert_string_equal(parsed->exts[0].name, "myext:c-define");
+    assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+    assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    /* anydata max subelems */
+    data = ELEMENT_WRAPPER_START
+                "<anydata name=\"any-name\">"
+                    "<config value=\"true\" />"
+                    "<description><text>desc</text></description>"
+                    "<if-feature name=\"feature\" />"
+                    "<mandatory value=\"true\" />"
+                    "<must condition=\"must-cond\" />"
+                    "<reference><text>ref</text></reference>"
+                    "<status value=\"deprecated\"/>"
+                    "<when condition=\"when-cond\"/>"
+                    EXT_SUBELEM
+                "</anydata>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_anydata *)siblings;
+    assert_null(parsed->parent);
+    assert_int_equal(parsed->nodetype, LYS_ANYDATA);
+    assert_true(parsed->flags & LYS_CONFIG_W);
+    assert_true(parsed->flags & LYS_MAND_TRUE);
+    assert_true(parsed->flags & LYS_STATUS_DEPRC);
+    assert_null(parsed->next);
+    assert_string_equal(parsed->name, "any-name");
+    assert_string_equal(parsed->dsc, "desc");
+    assert_string_equal(parsed->ref, "ref");
+    assert_string_equal(parsed->when->cond, "when-cond");
+    assert_string_equal(*parsed->iffeatures, "feature");
+    assert_string_equal(parsed->exts[0].name, "myext:c-define");
+    assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+    assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    /* min subelems */
+    node_meta.parent = (void *)0x10;
+    data = ELEMENT_WRAPPER_START "<anydata name=\"any-name\"> </anydata>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_anydata *)siblings;
+    assert_ptr_equal(parsed->parent, node_meta.parent);
+    assert_int_equal(parsed->nodetype, LYS_ANYDATA);
+    assert_null(parsed->next);
+    assert_null(parsed->exts);
+    lysp_node_free(st->ctx, siblings);
+
+    st->finished_correctly = true;
+}
+
+static void
+test_leaf_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_node *siblings = NULL;
+    struct tree_node_meta node_meta = {.parent = NULL, .nodes = &siblings};
+    struct lysp_node_leaf *parsed = NULL;
+
+    /* max elements */
+    data = ELEMENT_WRAPPER_START
+                "<leaf name=\"leaf\">"
+                    "<config value=\"true\" />"
+                    "<default value=\"def-val\"/>"
+                    "<description><text>desc</text></description>"
+                    "<if-feature name=\"feature\" />"
+                    "<mandatory value=\"true\" />"
+                    "<must condition=\"must-cond\" />"
+                    "<reference><text>ref</text></reference>"
+                    "<status value=\"deprecated\"/>"
+                    "<type name=\"type\"/>"
+                    "<units name=\"uni\"/>"
+                    "<when condition=\"when-cond\"/>"
+                    EXT_SUBELEM
+                "</leaf>"
+            ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_leaf *)siblings;
+    assert_null(parsed->parent);
+    assert_int_equal(parsed->nodetype, LYS_LEAF);
+    assert_true(parsed->flags & LYS_CONFIG_W);
+    assert_true(parsed->flags & LYS_MAND_TRUE);
+    assert_true(parsed->flags & LYS_STATUS_DEPRC);
+    assert_null(parsed->next);
+    assert_string_equal(parsed->name, "leaf");
+    assert_string_equal(parsed->dsc, "desc");
+    assert_string_equal(parsed->ref, "ref");
+    assert_string_equal(parsed->when->cond, "when-cond");
+    assert_string_equal(*parsed->iffeatures, "feature");
+    assert_string_equal(parsed->exts[0].name, "myext:c-define");
+    assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+    assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    assert_string_equal(parsed->musts->arg, "must-cond");
+    assert_string_equal(parsed->type.name, "type");
+    assert_string_equal(parsed->units, "uni");
+    assert_string_equal(parsed->dflt, "def-val");
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    /* min elements */
+    data = ELEMENT_WRAPPER_START "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_leaf *)siblings;
+    assert_string_equal(parsed->name, "leaf");
+    assert_string_equal(parsed->type.name, "type");
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_leaf_list_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_node *siblings = NULL;
+    struct tree_node_meta node_meta = {.parent = NULL, .nodes = &siblings};
+    struct lysp_node_leaflist *parsed = NULL;
+
+    data = ELEMENT_WRAPPER_START
+                "<leaf-list name=\"llist\">"
+                    "<config value=\"true\" />"
+                    "<default value=\"def-val0\"/>"
+                    "<default value=\"def-val1\"/>"
+                    "<description><text>desc</text></description>"
+                    "<if-feature name=\"feature\"/>"
+                    "<max-elements value=\"5\"/>"
+                    "<must condition=\"must-cond\"/>"
+                    "<ordered-by value=\"user\" />"
+                    "<reference><text>ref</text></reference>"
+                    "<status value=\"current\"/>"
+                    "<type name=\"type\"/>"
+                    "<units name=\"uni\"/>"
+                    "<when condition=\"when-cond\"/>"
+                    EXT_SUBELEM
+                "</leaf-list>"
+            ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_leaflist *)siblings;
+    assert_string_equal(parsed->dflts[0], "def-val0");
+    assert_string_equal(parsed->dflts[1], "def-val1");
+    assert_string_equal(parsed->dsc, "desc");
+    assert_string_equal(*parsed->iffeatures, "feature");
+    assert_int_equal(parsed->max, 5);
+    assert_string_equal(parsed->musts->arg, "must-cond");
+    assert_string_equal(parsed->name, "llist");
+    assert_null(parsed->next);
+    assert_int_equal(parsed->nodetype, LYS_LEAFLIST);
+    assert_null(parsed->parent);
+    assert_string_equal(parsed->ref, "ref");
+    assert_string_equal(parsed->type.name, "type");
+    assert_string_equal(parsed->units, "uni");
+    assert_string_equal(parsed->when->cond, "when-cond");
+    assert_true(parsed->flags & LYS_CONFIG_W);
+    assert_true(parsed->flags & LYS_ORDBY_USER);
+    assert_true(parsed->flags & LYS_STATUS_CURR);
+    assert_string_equal(parsed->exts[0].name, "myext:c-define");
+    assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+    assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    data = ELEMENT_WRAPPER_START
+                "<leaf-list name=\"llist\">"
+                    "<config value=\"true\" />"
+                    "<description><text>desc</text></description>"
+                    "<if-feature name=\"feature\"/>"
+                    "<min-elements value=\"5\"/>"
+                    "<must condition=\"must-cond\"/>"
+                    "<ordered-by value=\"user\" />"
+                    "<reference><text>ref</text></reference>"
+                    "<status value=\"current\"/>"
+                    "<type name=\"type\"/>"
+                    "<units name=\"uni\"/>"
+                    "<when condition=\"when-cond\"/>"
+                    EXT_SUBELEM
+                "</leaf-list>"
+            ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_leaflist *)siblings;
+    assert_string_equal(parsed->dsc, "desc");
+    assert_string_equal(*parsed->iffeatures, "feature");
+    assert_int_equal(parsed->min, 5);
+    assert_string_equal(parsed->musts->arg, "must-cond");
+    assert_string_equal(parsed->name, "llist");
+    assert_null(parsed->next);
+    assert_int_equal(parsed->nodetype, LYS_LEAFLIST);
+    assert_null(parsed->parent);
+    assert_string_equal(parsed->ref, "ref");
+    assert_string_equal(parsed->type.name, "type");
+    assert_string_equal(parsed->units, "uni");
+    assert_string_equal(parsed->when->cond, "when-cond");
+    assert_true(parsed->flags & LYS_CONFIG_W);
+    assert_true(parsed->flags & LYS_ORDBY_USER);
+    assert_true(parsed->flags & LYS_STATUS_CURR);
+    assert_string_equal(parsed->exts[0].name, "myext:c-define");
+    assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+    assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    data = ELEMENT_WRAPPER_START
+                "<leaf-list name=\"llist\">"
+                    "<config value=\"true\" />"
+                    "<description><text>desc</text></description>"
+                    "<if-feature name=\"feature\"/>"
+                    "<max-elements value=\"15\"/>"
+                    "<min-elements value=\"5\"/>"
+                    "<must condition=\"must-cond\"/>"
+                    "<ordered-by value=\"user\" />"
+                    "<reference><text>ref</text></reference>"
+                    "<status value=\"current\"/>"
+                    "<type name=\"type\"/>"
+                    "<units name=\"uni\"/>"
+                    "<when condition=\"when-cond\"/>"
+                "</leaf-list>"
+            ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_leaflist *)siblings;
+    assert_string_equal(parsed->dsc, "desc");
+    assert_string_equal(*parsed->iffeatures, "feature");
+    assert_int_equal(parsed->min, 5);
+    assert_int_equal(parsed->max, 15);
+    assert_string_equal(parsed->musts->arg, "must-cond");
+    assert_string_equal(parsed->name, "llist");
+    assert_null(parsed->next);
+    assert_int_equal(parsed->nodetype, LYS_LEAFLIST);
+    assert_null(parsed->parent);
+    assert_string_equal(parsed->ref, "ref");
+    assert_string_equal(parsed->type.name, "type");
+    assert_string_equal(parsed->units, "uni");
+    assert_string_equal(parsed->when->cond, "when-cond");
+    assert_true(parsed->flags & LYS_CONFIG_W);
+    assert_true(parsed->flags & LYS_ORDBY_USER);
+    assert_true(parsed->flags & LYS_STATUS_CURR);
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    data = ELEMENT_WRAPPER_START
+                "<leaf-list name=\"llist\">"
+                    "<type name=\"type\"/>"
+                "</leaf-list>"
+            ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_leaflist *)siblings;
+    assert_string_equal(parsed->name, "llist");
+    assert_string_equal(parsed->type.name, "type");
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    /* invalid combinations */
+    data = ELEMENT_WRAPPER_START
+                "<leaf-list name=\"llist\">"
+                    "<max-elements value=\"5\"/>"
+                    "<min-elements value=\"15\"/>"
+                    "<type name=\"type\"/>"
+                "</leaf-list>"
+            ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid combination of min-elements and max-elements: min value 15 is bigger than the max value 5. Line number 1.");
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    data = ELEMENT_WRAPPER_START
+                "<leaf-list name=\"llist\">"
+                    "<default value=\"def-val1\"/>"
+                    "<min-elements value=\"15\"/>"
+                    "<type name=\"type\"/>"
+                "</leaf-list>"
+            ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid combination of sub-elemnts \"min-elements\" and \"default\" in \"leaf-list\" element. Line number 1.");
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    data = ELEMENT_WRAPPER_START
+                "<leaf-list name=\"llist\">"
+                "</leaf-list>"
+            ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Missing mandatory sub-element \"type\" of \"leaf-list\" element. Line number 1.");
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_presence_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    const char *val;
+    struct lysp_ext_instance *exts = NULL;
+
+    data = ELEMENT_WRAPPER_START "<presence value=\"presence-val\">"EXT_SUBELEM"</presence>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &val, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(val, "presence-val");
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_PRESENCE);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    FREE_STRING(st->ctx, val);
+
+    data = ELEMENT_WRAPPER_START "<presence value=\"presence-val\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(val, "presence-val");
+    FREE_STRING(st->ctx, val);
+
+    data = ELEMENT_WRAPPER_START "<presence/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Missing mandatory attribute value of presence element. Line number 1.");
+
+    st->finished_correctly = true;
+}
+
+static void
+test_key_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    const char *val;
+    struct lysp_ext_instance *exts = NULL;
+
+    data = ELEMENT_WRAPPER_START "<key value=\"key-value\">"EXT_SUBELEM"</key>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &val, NULL, &exts, true), LY_SUCCESS);
+    assert_string_equal(val, "key-value");
+    assert_string_equal(exts[0].name, "myext:c-define");
+    assert_int_equal(exts[0].insubstmt_index, 0);
+    assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_KEY);
+    FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+    FREE_STRING(st->ctx, val);
+
+    data = ELEMENT_WRAPPER_START "<key value=\"key-value\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(val, "key-value");
+    FREE_STRING(st->ctx, val);
+
+    data = ELEMENT_WRAPPER_START "<key/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Missing mandatory attribute value of key element. Line number 1.");
+
+    st->finished_correctly = true;
+}
+
+static void
+test_typedef_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_tpdf *tpdfs = NULL;
+    struct tree_node_meta typdef_meta = {NULL, (struct lysp_node **)&tpdfs};
+
+    data = ELEMENT_WRAPPER_START
+                "<typedef name=\"tpdf-name\">"
+                    "<default value=\"def-val\"/>"
+                    "<description><text>desc-text</text></description>"
+                    "<reference><text>ref-text</text></reference>"
+                    "<status value=\"current\"/>"
+                    "<type name=\"type\"/>"
+                    "<units name=\"uni\"/>"
+                    EXT_SUBELEM
+                "</typedef>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &typdef_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(tpdfs[0].dflt, "def-val");
+    assert_string_equal(tpdfs[0].dsc, "desc-text");
+    assert_string_equal(tpdfs[0].name, "tpdf-name");
+    assert_string_equal(tpdfs[0].ref, "ref-text");
+    assert_string_equal(tpdfs[0].type.name, "type");
+    assert_string_equal(tpdfs[0].units, "uni");
+    assert_true(tpdfs[0].flags & LYS_STATUS_CURR);
+    assert_string_equal(tpdfs[0].exts[0].name, "myext:c-define");
+    assert_int_equal(tpdfs[0].exts[0].insubstmt_index, 0);
+    assert_int_equal(tpdfs[0].exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    FREE_ARRAY(st->ctx, tpdfs, lysp_tpdf_free);
+    tpdfs = NULL;
+
+    data = ELEMENT_WRAPPER_START
+                "<typedef name=\"tpdf-name\">"
+                    "<type name=\"type\"/>"
+                "</typedef>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &typdef_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(tpdfs[0].name, "tpdf-name");
+    assert_string_equal(tpdfs[0].type.name, "type");
+    FREE_ARRAY(st->ctx, tpdfs, lysp_tpdf_free);
+    tpdfs = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_refine_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_refine *refines = NULL;
+
+    /* max subelems */
+    data = ELEMENT_WRAPPER_START
+                "<refine target-node=\"target\">"
+                    "<if-feature name=\"feature\" />"
+                    "<must condition=\"cond\" />"
+                    "<presence value=\"presence\" />"
+                    "<default value=\"def\" />"
+                    "<config value=\"true\" />"
+                    "<mandatory value=\"true\" />"
+                    "<min-elements value=\"10\" />"
+                    "<max-elements value=\"20\" />"
+                    "<description><text>desc</text></description>"
+                    "<reference><text>ref</text></reference>"
+                    EXT_SUBELEM
+                "</refine>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &refines, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(refines->nodeid, "target");
+    assert_string_equal(*refines->dflts, "def");
+    assert_string_equal(refines->dsc, "desc");
+    assert_true(refines->flags & LYS_CONFIG_W);
+    assert_true(refines->flags & LYS_MAND_TRUE);
+    assert_string_equal(*refines->iffeatures, "feature");
+    assert_int_equal(refines->max, 20);
+    assert_int_equal(refines->min, 10);
+    assert_string_equal(refines->musts->arg, "cond");
+    assert_string_equal(refines->presence, "presence");
+    assert_string_equal(refines->ref, "ref");
+    assert_string_equal(refines->exts[0].name, "myext:c-define");
+    assert_int_equal(refines->exts[0].insubstmt_index, 0);
+    assert_int_equal(refines->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    FREE_ARRAY(st->ctx, refines, lysp_refine_free);
+    refines = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<refine target-node=\"target\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &refines, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(refines->nodeid, "target");
+    FREE_ARRAY(st->ctx, refines, lysp_refine_free);
+    refines = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_uses_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_node *siblings = NULL;
+    struct tree_node_meta node_meta = {NULL, &siblings};
+    struct lysp_node_uses *parsed = NULL;
+
+    /* max subelems */
+    data = ELEMENT_WRAPPER_START
+                "<uses name=\"uses-name\">"
+                    "<when condition=\"cond\" />"
+                    "<if-feature name=\"feature\" />"
+                    "<status value=\"obsolete\" />"
+                    "<description><text>desc</text></description>"
+                    "<reference><text>ref</text></reference>"
+                    "<refine target-node=\"target\"/>"
+                    "<augment target-node=\"target\" />"
+                    EXT_SUBELEM
+                "</uses>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_uses *)&siblings[0];
+    assert_string_equal(parsed->name, "uses-name");
+    assert_string_equal(parsed->dsc, "desc");
+    assert_true(parsed->flags & LYS_STATUS_OBSLT);
+    assert_string_equal(*parsed->iffeatures, "feature");
+    assert_null(parsed->next);
+    assert_int_equal(parsed->nodetype, LYS_USES);
+    assert_null(parsed->parent);
+    assert_string_equal(parsed->ref, "ref");
+    assert_string_equal(parsed->refines->nodeid, "target");
+    assert_string_equal(parsed->when->cond, "cond");
+    assert_string_equal(parsed->augments->nodeid, "target");
+    assert_string_equal(parsed->exts[0].name, "myext:c-define");
+    assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+    assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<uses name=\"uses-name\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(siblings[0].name, "uses-name");
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_revision_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_revision *revs = NULL;
+
+    /* max subelems */
+    data = ELEMENT_WRAPPER_START
+                "<revision date=\"2018-12-25\">"
+                    "<description><text>desc</text></description>"
+                    "<reference><text>ref</text></reference>"
+                    EXT_SUBELEM
+                "</revision>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &revs, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(revs->date, "2018-12-25");
+    assert_string_equal(revs->dsc, "desc");
+    assert_string_equal(revs->ref, "ref");
+    assert_string_equal(revs->exts[0].name, "myext:c-define");
+    assert_int_equal(revs->exts[0].insubstmt_index, 0);
+    assert_int_equal(revs->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    FREE_ARRAY(st->ctx, revs, lysp_revision_free);
+    revs = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<revision date=\"2005-05-05\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &revs, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(revs->date, "2005-05-05");
+    FREE_ARRAY(st->ctx, revs, lysp_revision_free);
+    revs = NULL;
+
+    /* invalid value */
+    data = ELEMENT_WRAPPER_START "<revision date=\"05-05-2005\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &revs, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"05-05-2005\" of \"revision\". Line number 1.");
+    FREE_ARRAY(st->ctx, revs, lysp_revision_free);
+    revs = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_include_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_include *includes = NULL;
+    struct include_meta inc_meta = {"module-name", &includes};
+
+    /* max subelems */
+    st->yin_ctx->mod_version = LYS_VERSION_1_1;
+    data = ELEMENT_WRAPPER_START
+                "<include module=\"mod\">"
+                    "<description><text>desc</text></description>"
+                    "<reference><text>ref</text></reference>"
+                    "<revision-date date=\"1999-09-09\"/>"
+                    EXT_SUBELEM
+                "</include>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &inc_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(includes->name, "mod");
+    assert_string_equal(includes->dsc, "desc");
+    assert_string_equal(includes->ref, "ref");
+    assert_string_equal(includes->rev, "1999-09-09");
+    assert_string_equal(includes->exts[0].name, "myext:c-define");
+    assert_int_equal(includes->exts[0].insubstmt_index, 0);
+    assert_int_equal(includes->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    FREE_ARRAY(st->ctx, includes, lysp_include_free);
+    includes = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<include module=\"mod\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &inc_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(includes->name, "mod");
+    FREE_ARRAY(st->ctx, includes, lysp_include_free);
+    includes = NULL;
+
+    /* invalid combinations */
+    st->yin_ctx->mod_version = LYS_VERSION_1_0;
+    data = ELEMENT_WRAPPER_START
+                "<include module=\"mod\">"
+                    "<description><text>desc</text></description>"
+                    "<revision-date date=\"1999-09-09\"/>"
+                "</include>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &inc_meta, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid sub-elemnt \"description\" of \"include\" element - this sub-element is allowed only in modules with version 1.1 or newer. Line number 1.");
+    FREE_ARRAY(st->ctx, includes, lysp_include_free);
+    includes = NULL;
+
+    st->yin_ctx->mod_version = LYS_VERSION_1_0;
+    data = ELEMENT_WRAPPER_START
+                "<include module=\"mod\">"
+                    "<reference><text>ref</text></reference>"
+                    "<revision-date date=\"1999-09-09\"/>"
+                "</include>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &inc_meta, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid sub-elemnt \"reference\" of \"include\" element - this sub-element is allowed only in modules with version 1.1 or newer. Line number 1.");
+    FREE_ARRAY(st->ctx, includes, lysp_include_free);
+    includes = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_feature_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_feature *features = NULL;
+
+    /* max subelems */
+    data = ELEMENT_WRAPPER_START
+                "<feature name=\"feature-name\">"
+                    "<if-feature name=\"iff\"/>"
+                    "<status value=\"deprecated\"/>"
+                    "<description><text>desc</text></description>"
+                    "<reference><text>ref</text></reference>"
+                    EXT_SUBELEM
+                "</feature>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &features, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(features->name, "feature-name");
+    assert_string_equal(features->dsc, "desc");
+    assert_true(features->flags & LYS_STATUS_DEPRC);
+    assert_string_equal(*features->iffeatures, "iff");
+    assert_string_equal(features->ref, "ref");
+    assert_string_equal(features->exts[0].name, "myext:c-define");
+    assert_int_equal(features->exts[0].insubstmt_index, 0);
+    assert_int_equal(features->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    FREE_ARRAY(st->ctx, features, lysp_feature_free);
+    features = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<feature name=\"feature-name\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &features, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(features->name, "feature-name");
+    FREE_ARRAY(st->ctx, features, lysp_feature_free);
+    features = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_identity_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_ident *identities = NULL;
+
+    /* max subelems */
+    st->yin_ctx->mod_version = LYS_VERSION_1_1;
+    data = ELEMENT_WRAPPER_START
+                "<identity name=\"ident-name\">"
+                    "<if-feature name=\"iff\"/>"
+                    "<base name=\"base-name\"/>"
+                    "<status value=\"deprecated\"/>"
+                    "<description><text>desc</text></description>"
+                    "<reference><text>ref</text></reference>"
+                    EXT_SUBELEM
+                "</identity>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &identities, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(identities->name, "ident-name");
+    assert_string_equal(*identities->bases, "base-name");
+    assert_string_equal(*identities->iffeatures, "iff");
+    assert_string_equal(identities->dsc, "desc");
+    assert_string_equal(identities->ref, "ref");
+    assert_true(identities->flags & LYS_STATUS_DEPRC);
+    assert_string_equal(identities->exts[0].name, "myext:c-define");
+    assert_int_equal(identities->exts[0].insubstmt_index, 0);
+    assert_int_equal(identities->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    FREE_ARRAY(st->ctx, identities, lysp_ident_free);
+    identities = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<identity name=\"ident-name\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &identities, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(identities->name, "ident-name");
+    FREE_ARRAY(st->ctx, identities, lysp_ident_free);
+    identities = NULL;
+
+    /* invalid */
+    st->yin_ctx->mod_version = LYS_VERSION_1_0;
+    data = ELEMENT_WRAPPER_START
+                "<identity name=\"ident-name\">"
+                    "<if-feature name=\"iff\"/>"
+                "</identity>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &identities, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid sub-elemnt \"if-feature\" of \"identity\" element - this sub-element is allowed only in modules with version 1.1 or newer. Line number 1.");
+    FREE_ARRAY(st->ctx, identities, lysp_ident_free);
+    identities = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_list_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_node *siblings = NULL;
+    struct tree_node_meta node_meta = {NULL, &siblings};
+    struct lysp_node_list *parsed = NULL;
+
+    /* max subelems */
+    data = ELEMENT_WRAPPER_START
+                "<list name=\"list-name\">"
+                    "<when condition=\"when\"/>"
+                    "<if-feature name=\"iff\"/>"
+                    "<must condition=\"must-cond\"/>"
+                    "<key value=\"key\"/>"
+                    "<unique tag=\"utag\"/>"
+                    "<config value=\"true\"/>"
+                    "<min-elements value=\"10\"/>"
+                    "<ordered-by value=\"user\"/>"
+                    "<status value=\"deprecated\"/>"
+                    "<description><text>desc</text></description>"
+                    "<reference><text>ref</text></reference>"
+                    "<anydata name=\"anyd\"/>"
+                    "<anyxml name=\"anyx\"/>"
+                    "<container name=\"cont\"/>"
+                    "<choice name=\"choice\"/>"
+                    "<action name=\"action\"/>"
+                    "<grouping name=\"grp\"/>"
+                    "<notification name=\"notf\"/>"
+                    "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+                    "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+                    "<list name=\"sub-list\"/>"
+                    "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>"
+                    "<uses name=\"uses-name\"/>"
+                    EXT_SUBELEM
+                "</list>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_list *)&siblings[0];
+    assert_string_equal(parsed->dsc, "desc");
+    assert_string_equal(parsed->child->name, "anyd");
+    assert_int_equal(parsed->child->nodetype, LYS_ANYDATA);
+    assert_string_equal(parsed->child->next->name, "anyx");
+    assert_int_equal(parsed->child->next->nodetype, LYS_ANYXML);
+    assert_string_equal(parsed->child->next->next->name, "cont");
+    assert_int_equal(parsed->child->next->next->nodetype, LYS_CONTAINER);
+    assert_string_equal(parsed->child->next->next->next->name, "choice");
+    assert_int_equal(parsed->child->next->next->next->nodetype, LYS_CHOICE);
+    assert_string_equal(parsed->child->next->next->next->next->name, "leaf");
+    assert_int_equal(parsed->child->next->next->next->next->nodetype, LYS_LEAF);
+    assert_string_equal(parsed->child->next->next->next->next->next->name, "llist");
+    assert_int_equal(parsed->child->next->next->next->next->next->nodetype, LYS_LEAFLIST);
+    assert_string_equal(parsed->child->next->next->next->next->next->next->name, "sub-list");
+    assert_int_equal(parsed->child->next->next->next->next->next->next->nodetype, LYS_LIST);
+    assert_string_equal(parsed->child->next->next->next->next->next->next->next->name, "uses-name");
+    assert_int_equal(parsed->child->next->next->next->next->next->next->next->nodetype, LYS_USES);
+    assert_null(parsed->child->next->next->next->next->next->next->next->next);
+    assert_string_equal(parsed->groupings->name, "grp");
+    assert_string_equal(parsed->actions->name, "action");
+    assert_int_equal(parsed->groupings->nodetype, LYS_GROUPING);
+    assert_string_equal(parsed->notifs->name, "notf");
+    assert_true(parsed->flags & LYS_ORDBY_USER);
+    assert_true(parsed->flags & LYS_STATUS_DEPRC);
+    assert_true(parsed->flags & LYS_CONFIG_W);
+    assert_string_equal(*parsed->iffeatures, "iff");
+    assert_string_equal(parsed->key, "key");
+    assert_int_equal(parsed->min, 10);
+    assert_string_equal(parsed->musts->arg, "must-cond");
+    assert_string_equal(parsed->name, "list-name");
+    assert_null(parsed->next);
+    assert_int_equal(parsed->nodetype, LYS_LIST);
+    assert_null(parsed->parent);
+    assert_string_equal(parsed->ref, "ref");
+    assert_string_equal(parsed->typedefs->name, "tpdf");
+    assert_string_equal(*parsed->uniques, "utag");
+    assert_string_equal(parsed->when->cond, "when");
+    assert_string_equal(parsed->exts[0].name, "myext:c-define");
+    assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+    assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_node_free(st->ctx, siblings);
+    ly_set_erase(&st->yin_ctx->tpdfs_nodes, NULL);
+    siblings = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<list name=\"list-name\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_list *)&siblings[0];
+    assert_string_equal(parsed->name, "list-name");
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_notification_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_notif *notifs = NULL;
+    struct tree_node_meta notif_meta = {NULL, (struct lysp_node **)&notifs};
+
+    /* max subelems */
+    st->yin_ctx->mod_version = LYS_VERSION_1_1;
+    data = ELEMENT_WRAPPER_START
+                "<notification name=\"notif-name\">"
+                    "<anydata name=\"anyd\"/>"
+                    "<anyxml name=\"anyx\"/>"
+                    "<description><text>desc</text></description>"
+                    "<if-feature name=\"iff\"/>"
+                    "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+                    "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+                    "<list name=\"sub-list\"/>"
+                    "<must condition=\"cond\"/>"
+                    "<reference><text>ref</text></reference>"
+                    "<status value=\"deprecated\"/>"
+                    "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>"
+                    "<uses name=\"uses-name\"/>"
+                    "<container name=\"cont\"/>"
+                    "<choice name=\"choice\"/>"
+                    "<grouping name=\"grp\"/>"
+                    EXT_SUBELEM
+                "</notification>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &notif_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(notifs->name, "notif-name");
+    assert_string_equal(notifs->data->name, "anyd");
+    assert_int_equal(notifs->data->nodetype, LYS_ANYDATA);
+    assert_string_equal(notifs->data->next->name, "anyx");
+    assert_int_equal(notifs->data->next->nodetype, LYS_ANYXML);
+    assert_string_equal(notifs->data->next->next->name, "leaf");
+    assert_int_equal(notifs->data->next->next->nodetype, LYS_LEAF);
+    assert_string_equal(notifs->data->next->next->next->name, "llist");
+    assert_int_equal(notifs->data->next->next->next->nodetype, LYS_LEAFLIST);
+    assert_string_equal(notifs->data->next->next->next->next->name, "sub-list");
+    assert_int_equal(notifs->data->next->next->next->next->nodetype, LYS_LIST);
+    assert_true(notifs->flags & LYS_STATUS_DEPRC);
+    assert_string_equal(notifs->groupings->name, "grp");
+    assert_int_equal(notifs->groupings->nodetype, LYS_GROUPING);
+    assert_string_equal(notifs->data->next->next->next->next->next->name, "uses-name");
+    assert_int_equal(notifs->data->next->next->next->next->next->nodetype, LYS_USES);
+    assert_string_equal(notifs->data->next->next->next->next->next->next->name, "cont");
+    assert_int_equal(notifs->data->next->next->next->next->next->next->nodetype, LYS_CONTAINER);
+    assert_int_equal(notifs->data->next->next->next->next->next->next->next->nodetype, LYS_CHOICE);
+    assert_string_equal(notifs->data->next->next->next->next->next->next->next->name, "choice");
+    assert_null(notifs->data->next->next->next->next->next->next->next->next);
+    assert_string_equal(*notifs->iffeatures, "iff");
+    assert_string_equal(notifs->musts->arg, "cond");
+    assert_int_equal(notifs->nodetype, LYS_NOTIF);
+    assert_null(notifs->parent);
+    assert_string_equal(notifs->ref, "ref");
+    assert_string_equal(notifs->typedefs->name, "tpdf");
+    assert_string_equal(notifs->exts[0].name, "myext:c-define");
+    assert_int_equal(notifs->exts[0].insubstmt_index, 0);
+    assert_int_equal(notifs->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    FREE_ARRAY(st->ctx, notifs, lysp_notif_free);
+    notifs = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<notification name=\"notif-name\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &notif_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(notifs->name, "notif-name");
+    FREE_ARRAY(st->ctx, notifs, lysp_notif_free);
+    notifs = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_grouping_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_grp *grps = NULL;
+    struct tree_node_meta grp_meta = {NULL, (struct lysp_node **)&grps};
+
+    /* max subelems */
+    data = ELEMENT_WRAPPER_START
+                "<grouping name=\"grp-name\">"
+                    "<anydata name=\"anyd\"/>"
+                    "<anyxml name=\"anyx\"/>"
+                    "<description><text>desc</text></description>"
+                    "<grouping name=\"sub-grp\"/>"
+                    "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+                    "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+                    "<list name=\"list\"/>"
+                    "<notification name=\"notf\"/>"
+                    "<reference><text>ref</text></reference>"
+                    "<status value=\"current\"/>"
+                    "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>"
+                    "<uses name=\"uses-name\"/>"
+                    "<action name=\"act\"/>"
+                    "<container name=\"cont\"/>"
+                    "<choice name=\"choice\"/>"
+                    EXT_SUBELEM
+                "</grouping>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &grp_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(grps->name, "grp-name");
+    assert_string_equal(grps->data->name, "anyd");
+    assert_string_equal(grps->data->next->name, "anyx");
+    assert_string_equal(grps->data->next->next->name, "leaf");
+    assert_string_equal(grps->data->next->next->next->name, "llist");
+    assert_string_equal(grps->data->next->next->next->next->name, "list");
+    assert_string_equal(grps->dsc, "desc");
+    assert_true(grps->flags & LYS_STATUS_CURR);
+    assert_string_equal(grps->groupings->name, "sub-grp");
+    assert_int_equal(grps->nodetype, LYS_GROUPING);
+    assert_string_equal(grps->notifs->name, "notf");
+    assert_null(grps->parent);
+    assert_string_equal(grps->ref, "ref");
+    assert_string_equal(grps->typedefs->name, "tpdf");
+    assert_string_equal(grps->actions->name, "act");
+    assert_string_equal(grps->data->next->next->next->next->next->name, "uses-name");
+    assert_int_equal(grps->data->next->next->next->next->next->nodetype, LYS_USES);
+    assert_string_equal(grps->data->next->next->next->next->next->next->name, "cont");
+    assert_int_equal(grps->data->next->next->next->next->next->next->nodetype, LYS_CONTAINER);
+    assert_string_equal(grps->data->next->next->next->next->next->next->next->name, "choice");
+    assert_int_equal(grps->data->next->next->next->next->next->next->next->nodetype, LYS_CHOICE);
+    assert_string_equal(grps->exts[0].name, "myext:c-define");
+    assert_int_equal(grps->exts[0].insubstmt_index, 0);
+    assert_int_equal(grps->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    FREE_ARRAY(st->ctx, grps, lysp_grp_free);
+    grps = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<grouping name=\"grp-name\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &grp_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(grps->name, "grp-name");
+    FREE_ARRAY(st->ctx, grps, lysp_grp_free);
+    grps = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_container_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_node *siblings = NULL;
+    struct tree_node_meta node_meta = {NULL, &siblings};
+    struct lysp_node_container *parsed = NULL;
+
+    /* max subelems */
+    st->yin_ctx->mod_version = LYS_VERSION_1_1;
+    data = ELEMENT_WRAPPER_START
+                "<container name=\"cont-name\">"
+                    "<anydata name=\"anyd\"/>"
+                    "<anyxml name=\"anyx\"/>"
+                    "<config value=\"true\"/>"
+                    "<container name=\"subcont\"/>"
+                    "<description><text>desc</text></description>"
+                    "<grouping name=\"sub-grp\"/>"
+                    "<if-feature name=\"iff\"/>"
+                    "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+                    "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+                    "<list name=\"list\"/>"
+                    "<must condition=\"cond\"/>"
+                    "<notification name=\"notf\"/>"
+                    "<presence value=\"presence\"/>"
+                    "<reference><text>ref</text></reference>"
+                    "<status value=\"current\"/>"
+                    "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>"
+                    "<uses name=\"uses-name\"/>"
+                    "<when condition=\"when-cond\"/>"
+                    "<action name=\"act\"/>"
+                    "<choice name=\"choice\"/>"
+                    EXT_SUBELEM
+                "</container>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_container *)siblings;
+    assert_string_equal(parsed->name, "cont-name");
+    assert_null(parsed->parent);
+    assert_int_equal(parsed->nodetype, LYS_CONTAINER);
+    assert_true(parsed->flags & LYS_CONFIG_W);
+    assert_true(parsed->flags & LYS_STATUS_CURR);
+    assert_null(parsed->next);
+    assert_string_equal(parsed->dsc, "desc");
+    assert_string_equal(parsed->ref, "ref");
+    assert_string_equal(parsed->when->cond, "when-cond");
+    assert_string_equal(*parsed->iffeatures, "iff");
+    assert_string_equal(parsed->musts->arg, "cond");
+    assert_string_equal(parsed->presence, "presence");
+    assert_string_equal(parsed->typedefs->name, "tpdf");
+    assert_string_equal(parsed->groupings->name, "sub-grp");
+    assert_string_equal(parsed->child->name, "anyd");
+    assert_int_equal(parsed->child->nodetype, LYS_ANYDATA);
+    assert_string_equal(parsed->child->next->name, "anyx");
+    assert_int_equal(parsed->child->next->nodetype, LYS_ANYXML);
+    assert_string_equal(parsed->child->next->next->name, "subcont");
+    assert_int_equal(parsed->child->next->next->nodetype, LYS_CONTAINER);
+    assert_string_equal(parsed->child->next->next->next->name, "leaf");
+    assert_int_equal(parsed->child->next->next->next->nodetype, LYS_LEAF);
+    assert_string_equal(parsed->child->next->next->next->next->name, "llist");
+    assert_int_equal(parsed->child->next->next->next->next->nodetype, LYS_LEAFLIST);
+    assert_string_equal(parsed->child->next->next->next->next->next->name, "list");
+    assert_int_equal(parsed->child->next->next->next->next->next->nodetype, LYS_LIST);
+    assert_string_equal(parsed->child->next->next->next->next->next->next->name, "uses-name");
+    assert_int_equal(parsed->child->next->next->next->next->next->next->nodetype, LYS_USES);
+    assert_string_equal(parsed->child->next->next->next->next->next->next->next->name, "choice");
+    assert_int_equal(parsed->child->next->next->next->next->next->next->next->nodetype, LYS_CHOICE);
+    assert_null(parsed->child->next->next->next->next->next->next->next->next);
+    assert_string_equal(parsed->notifs->name, "notf");
+    assert_string_equal(parsed->actions->name, "act");
+    assert_string_equal(parsed->exts[0].name, "myext:c-define");
+    assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+    assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_node_free(st->ctx, siblings);
+    ly_set_erase(&st->yin_ctx->tpdfs_nodes, NULL);
+    siblings = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<container name=\"cont-name\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_container *)siblings;
+    assert_string_equal(parsed->name, "cont-name");
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_case_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_node *siblings = NULL;
+    struct tree_node_meta node_meta = {NULL, &siblings};
+    struct lysp_node_case *parsed = NULL;
+
+    /* max subelems */
+    st->yin_ctx->mod_version = LYS_VERSION_1_1;
+    data = ELEMENT_WRAPPER_START
+                "<case name=\"case-name\">"
+                    "<anydata name=\"anyd\"/>"
+                    "<anyxml name=\"anyx\"/>"
+                    "<container name=\"subcont\"/>"
+                    "<description><text>desc</text></description>"
+                    "<if-feature name=\"iff\"/>"
+                    "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+                    "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+                    "<list name=\"list\"/>"
+                    "<reference><text>ref</text></reference>"
+                    "<status value=\"current\"/>"
+                    "<uses name=\"uses-name\"/>"
+                    "<when condition=\"when-cond\"/>"
+                    "<choice name=\"choice\"/>"
+                    EXT_SUBELEM
+                "</case>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_case *)siblings;
+    assert_string_equal(parsed->name, "case-name");
+    assert_null(parsed->parent);
+    assert_int_equal(parsed->nodetype, LYS_CASE);
+    assert_true(parsed->flags & LYS_STATUS_CURR);
+    assert_null(parsed->next);
+    assert_string_equal(parsed->dsc, "desc");
+    assert_string_equal(parsed->ref, "ref");
+    assert_string_equal(parsed->when->cond, "when-cond");
+    assert_string_equal(*parsed->iffeatures, "iff");
+    assert_string_equal(parsed->child->name, "anyd");
+    assert_int_equal(parsed->child->nodetype, LYS_ANYDATA);
+    assert_string_equal(parsed->child->next->name, "anyx");
+    assert_int_equal(parsed->child->next->nodetype, LYS_ANYXML);
+    assert_string_equal(parsed->child->next->next->name, "subcont");
+    assert_int_equal(parsed->child->next->next->nodetype, LYS_CONTAINER);
+    assert_string_equal(parsed->child->next->next->next->name, "leaf");
+    assert_int_equal(parsed->child->next->next->next->nodetype, LYS_LEAF);
+    assert_string_equal(parsed->child->next->next->next->next->name, "llist");
+    assert_int_equal(parsed->child->next->next->next->next->nodetype, LYS_LEAFLIST);
+    assert_string_equal(parsed->child->next->next->next->next->next->name, "list");
+    assert_int_equal(parsed->child->next->next->next->next->next->nodetype, LYS_LIST);
+    assert_string_equal(parsed->child->next->next->next->next->next->next->name, "uses-name");
+    assert_int_equal(parsed->child->next->next->next->next->next->next->nodetype, LYS_USES);
+    assert_string_equal(parsed->child->next->next->next->next->next->next->next->name, "choice");
+    assert_int_equal(parsed->child->next->next->next->next->next->next->next->nodetype, LYS_CHOICE);
+    assert_null(parsed->child->next->next->next->next->next->next->next->next);
+    assert_string_equal(parsed->exts[0].name, "myext:c-define");
+    assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+    assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<case name=\"case-name\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_case *)siblings;
+    assert_string_equal(parsed->name, "case-name");
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_choice_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_node *siblings = NULL;
+    struct tree_node_meta node_meta = {NULL, &siblings};
+    struct lysp_node_choice *parsed = NULL;
+
+    /* max subelems */
+    st->yin_ctx->mod_version = LYS_VERSION_1_1;
+    data = ELEMENT_WRAPPER_START
+                "<choice name=\"choice-name\">"
+                    "<anydata name=\"anyd\"/>"
+                    "<anyxml name=\"anyx\"/>"
+                    "<case name=\"sub-case\"/>"
+                    "<choice name=\"choice\"/>"
+                    "<config value=\"true\"/>"
+                    "<container name=\"subcont\"/>"
+                    "<default value=\"def\"/>"
+                    "<description><text>desc</text></description>"
+                    "<if-feature name=\"iff\"/>"
+                    "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+                    "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+                    "<list name=\"list\"/>"
+                    "<mandatory value=\"true\" />"
+                    "<reference><text>ref</text></reference>"
+                    "<status value=\"current\"/>"
+                    "<when condition=\"when-cond\"/>"
+                    EXT_SUBELEM
+                "</choice>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_choice *)siblings;
+    assert_string_equal(parsed->name, "choice-name");
+    assert_null(parsed->parent);
+    assert_int_equal(parsed->nodetype, LYS_CHOICE);
+    assert_true(parsed->flags & LYS_CONFIG_W && parsed->flags & LYS_MAND_TRUE  && parsed->flags & LYS_STATUS_CURR);
+    assert_null(parsed->next);
+    assert_string_equal(parsed->dsc, "desc");
+    assert_string_equal(parsed->ref, "ref");
+    assert_string_equal(parsed->when->cond, "when-cond");
+    assert_string_equal(*parsed->iffeatures, "iff");
+    assert_string_equal(parsed->child->name, "anyd");
+    assert_int_equal(parsed->child->nodetype, LYS_ANYDATA);
+    assert_string_equal(parsed->child->next->name, "anyx");
+    assert_int_equal(parsed->child->next->nodetype, LYS_ANYXML);
+    assert_string_equal(parsed->child->next->next->name, "sub-case");
+    assert_int_equal(parsed->child->next->next->nodetype, LYS_CASE);
+    assert_string_equal(parsed->child->next->next->next->name, "choice");
+    assert_int_equal(parsed->child->next->next->next->nodetype, LYS_CHOICE);
+    assert_string_equal(parsed->child->next->next->next->next->name, "subcont");
+    assert_int_equal(parsed->child->next->next->next->next->nodetype, LYS_CONTAINER);
+    assert_string_equal(parsed->child->next->next->next->next->next->name, "leaf");
+    assert_int_equal(parsed->child->next->next->next->next->next->nodetype, LYS_LEAF);
+    assert_string_equal(parsed->child->next->next->next->next->next->next->name, "llist");
+    assert_int_equal(parsed->child->next->next->next->next->next->next->nodetype, LYS_LEAFLIST);
+    assert_string_equal(parsed->child->next->next->next->next->next->next->next->name, "list");
+    assert_int_equal(parsed->child->next->next->next->next->next->next->next->nodetype, LYS_LIST);
+    assert_null(parsed->child->next->next->next->next->next->next->next->next);
+    assert_string_equal(parsed->exts[0].name, "myext:c-define");
+    assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+    assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<choice name=\"choice-name\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+    parsed = (struct lysp_node_choice *)siblings;
+    assert_string_equal(parsed->name, "choice-name");
+    lysp_node_free(st->ctx, siblings);
+    siblings = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_inout_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_action_inout inout = {};
+    struct inout_meta inout_meta = {NULL, &inout};
+
+    /* max subelements */
+    st->yin_ctx->mod_version = LYS_VERSION_1_1;
+    data = ELEMENT_WRAPPER_START
+                "<input>"
+                    "<anydata name=\"anyd\"/>"
+                    "<anyxml name=\"anyx\"/>"
+                    "<choice name=\"choice\"/>"
+                    "<container name=\"subcont\"/>"
+                    "<grouping name=\"sub-grp\"/>"
+                    "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+                    "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+                    "<list name=\"list\"/>"
+                    "<must condition=\"cond\"/>"
+                    "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>"
+                    "<uses name=\"uses-name\"/>"
+                    EXT_SUBELEM
+                "</input>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &inout_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_null(inout.parent);
+    assert_int_equal(inout.nodetype, LYS_INPUT);
+    assert_string_equal(inout.musts->arg, "cond");
+    assert_string_equal(inout.typedefs->name, "tpdf");
+    assert_string_equal(inout.groupings->name, "sub-grp");
+    assert_string_equal(inout.data->name, "anyd");
+    assert_int_equal(inout.data->nodetype, LYS_ANYDATA);
+    assert_string_equal(inout.data->next->name, "anyx");
+    assert_int_equal(inout.data->next->nodetype, LYS_ANYXML);
+    assert_string_equal(inout.data->next->next->name, "choice");
+    assert_int_equal(inout.data->next->next->nodetype, LYS_CHOICE);
+    assert_string_equal(inout.data->next->next->next->name, "subcont");
+    assert_int_equal(inout.data->next->next->next->nodetype, LYS_CONTAINER);
+    assert_string_equal(inout.data->next->next->next->next->name, "leaf");
+    assert_int_equal(inout.data->next->next->next->next->nodetype, LYS_LEAF);
+    assert_string_equal(inout.data->next->next->next->next->next->name, "llist");
+    assert_int_equal(inout.data->next->next->next->next->next->nodetype, LYS_LEAFLIST);
+    assert_string_equal(inout.data->next->next->next->next->next->next->name, "list");
+    assert_int_equal(inout.data->next->next->next->next->next->next->nodetype, LYS_LIST);
+    assert_string_equal(inout.data->next->next->next->next->next->next->next->name, "uses-name");
+    assert_int_equal(inout.data->next->next->next->next->next->next->next->nodetype, LYS_USES);
+    assert_null(inout.data->next->next->next->next->next->next->next->next);
+    assert_string_equal(inout.exts[0].name, "myext:c-define");
+    assert_int_equal(inout.exts[0].insubstmt_index, 0);
+    assert_int_equal(inout.exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_action_inout_free(st->ctx, &inout);
+    memset(&inout, 0, sizeof inout);
+
+    /* max subelements */
+    st->yin_ctx->mod_version = LYS_VERSION_1_1;
+    data = ELEMENT_WRAPPER_START
+                "<output>"
+                    "<anydata name=\"anyd\"/>"
+                    "<anyxml name=\"anyx\"/>"
+                    "<choice name=\"choice\"/>"
+                    "<container name=\"subcont\"/>"
+                    "<grouping name=\"sub-grp\"/>"
+                    "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+                    "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+                    "<list name=\"list\"/>"
+                    "<must condition=\"cond\"/>"
+                    "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>"
+                    "<uses name=\"uses-name\"/>"
+                    EXT_SUBELEM
+                "</output>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &inout_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_null(inout.parent);
+    assert_int_equal(inout.nodetype, LYS_OUTPUT);
+    assert_string_equal(inout.musts->arg, "cond");
+    assert_string_equal(inout.typedefs->name, "tpdf");
+    assert_string_equal(inout.groupings->name, "sub-grp");
+    assert_string_equal(inout.data->name, "anyd");
+    assert_int_equal(inout.data->nodetype, LYS_ANYDATA);
+    assert_string_equal(inout.data->next->name, "anyx");
+    assert_int_equal(inout.data->next->nodetype, LYS_ANYXML);
+    assert_string_equal(inout.data->next->next->name, "choice");
+    assert_int_equal(inout.data->next->next->nodetype, LYS_CHOICE);
+    assert_string_equal(inout.data->next->next->next->name, "subcont");
+    assert_int_equal(inout.data->next->next->next->nodetype, LYS_CONTAINER);
+    assert_string_equal(inout.data->next->next->next->next->name, "leaf");
+    assert_int_equal(inout.data->next->next->next->next->nodetype, LYS_LEAF);
+    assert_string_equal(inout.data->next->next->next->next->next->name, "llist");
+    assert_int_equal(inout.data->next->next->next->next->next->nodetype, LYS_LEAFLIST);
+    assert_string_equal(inout.data->next->next->next->next->next->next->name, "list");
+    assert_int_equal(inout.data->next->next->next->next->next->next->nodetype, LYS_LIST);
+    assert_string_equal(inout.data->next->next->next->next->next->next->next->name, "uses-name");
+    assert_int_equal(inout.data->next->next->next->next->next->next->next->nodetype, LYS_USES);
+    assert_null(inout.data->next->next->next->next->next->next->next->next);
+    assert_string_equal(inout.exts[0].name, "myext:c-define");
+    assert_int_equal(inout.exts[0].insubstmt_index, 0);
+    assert_int_equal(inout.exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_action_inout_free(st->ctx, &inout);
+    memset(&inout, 0, sizeof inout);
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<input />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &inout_meta, NULL, NULL, true), LY_SUCCESS);
+    memset(&inout, 0, sizeof inout);
+
+    data = ELEMENT_WRAPPER_START "<output />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &inout_meta, NULL, NULL, true), LY_SUCCESS);
+    memset(&inout, 0, sizeof inout);
+
+    /* invalid combinations */
+    data = ELEMENT_WRAPPER_START "<input name=\"test\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &inout_meta, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Unexpected attribute \"name\" of \"input\" element. Line number 1.");
+    memset(&inout, 0, sizeof inout);
+
+    st->finished_correctly = true;
+}
+
+static void
+test_action_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_action *actions = NULL;
+    struct tree_node_meta act_meta = {NULL, (struct lysp_node **)&actions};
+
+    /* max subelems */
+    st->yin_ctx->mod_version = LYS_VERSION_1_1;
+    data = ELEMENT_WRAPPER_START
+                "<action name=\"act\">"
+                    "<description><text>desc</text></description>"
+                    "<grouping name=\"grouping\"/>"
+                    "<if-feature name=\"iff\"/>"
+                    "<input><uses name=\"uses-name\"/></input>"
+                    "<output><must condition=\"cond\"/></output>"
+                    "<reference><text>ref</text></reference>"
+                    "<status value=\"deprecated\"/>"
+                    "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>"
+                    EXT_SUBELEM
+                "</action>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &act_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_null(actions->parent);
+    assert_int_equal(actions->nodetype, LYS_ACTION);
+    assert_true(actions->flags & LYS_STATUS_DEPRC);
+    assert_string_equal(actions->name, "act");
+    assert_string_equal(actions->dsc, "desc");
+    assert_string_equal(actions->ref, "ref");
+    assert_string_equal(*actions->iffeatures, "iff");
+    assert_string_equal(actions->typedefs->name, "tpdf");
+    assert_string_equal(actions->groupings->name, "grouping");
+    assert_string_equal(actions->input.data->name, "uses-name");
+    assert_string_equal(actions->output.musts->arg, "cond");
+    assert_string_equal(actions->exts[0].name, "myext:c-define");
+    assert_int_equal(actions->exts[0].insubstmt_index, 0);
+    assert_int_equal(actions->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    FREE_ARRAY(st->ctx, actions, lysp_action_free)
+    actions = NULL;
+
+    st->yin_ctx->mod_version = LYS_VERSION_1_1;
+    data = ELEMENT_WRAPPER_START
+                "<rpc name=\"act\">"
+                    "<description><text>desc</text></description>"
+                    "<grouping name=\"grouping\"/>"
+                    "<if-feature name=\"iff\"/>"
+                    "<input><uses name=\"uses-name\"/></input>"
+                    "<output><must condition=\"cond\"/></output>"
+                    "<reference><text>ref</text></reference>"
+                    "<status value=\"deprecated\"/>"
+                    "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>"
+                    EXT_SUBELEM
+                "</rpc>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &act_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_null(actions->parent);
+    assert_int_equal(actions->nodetype, LYS_ACTION);
+    assert_true(actions->flags & LYS_STATUS_DEPRC);
+    assert_string_equal(actions->name, "act");
+    assert_string_equal(actions->dsc, "desc");
+    assert_string_equal(actions->ref, "ref");
+    assert_string_equal(*actions->iffeatures, "iff");
+    assert_string_equal(actions->typedefs->name, "tpdf");
+    assert_string_equal(actions->groupings->name, "grouping");
+    assert_string_equal(actions->input.data->name, "uses-name");
+    assert_string_equal(actions->output.musts->arg, "cond");
+    assert_string_equal(actions->exts[0].name, "myext:c-define");
+    assert_int_equal(actions->exts[0].insubstmt_index, 0);
+    assert_int_equal(actions->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    FREE_ARRAY(st->ctx, actions, lysp_action_free)
+    actions = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<action name=\"act\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &act_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(actions->name, "act");
+    FREE_ARRAY(st->ctx, actions, lysp_action_free)
+    actions = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_augment_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_augment *augments = NULL;
+    struct tree_node_meta aug_meta = {NULL, (struct lysp_node **)&augments};
+
+    st->yin_ctx->mod_version = LYS_VERSION_1_1;
+    data = ELEMENT_WRAPPER_START
+                "<augment target-node=\"target\">"
+                    "<action name=\"action\"/>"
+                    "<anydata name=\"anyd\"/>"
+                    "<anyxml name=\"anyx\"/>"
+                    "<case name=\"case\"/>"
+                    "<choice name=\"choice\"/>"
+                    "<container name=\"subcont\"/>"
+                    "<description><text>desc</text></description>"
+                    "<if-feature name=\"iff\"/>"
+                    "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+                    "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+                    "<list name=\"list\"/>"
+                    "<notification name=\"notif\"/>"
+                    "<reference><text>ref</text></reference>"
+                    "<status value=\"current\"/>"
+                    "<uses name=\"uses\"/>"
+                    "<when condition=\"when-cond\"/>"
+                    EXT_SUBELEM
+                "</augment>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &aug_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(augments->nodeid, "target");
+    assert_null(augments->parent);
+    assert_int_equal(augments->nodetype, LYS_AUGMENT);
+    assert_true(augments->flags & LYS_STATUS_CURR);
+    assert_string_equal(augments->dsc, "desc");
+    assert_string_equal(augments->ref, "ref");
+    assert_string_equal(augments->when->cond, "when-cond");
+    assert_string_equal(*augments->iffeatures, "iff");
+    assert_string_equal(augments->child->name, "anyd");
+    assert_int_equal(augments->child->nodetype, LYS_ANYDATA);
+    assert_string_equal(augments->child->next->name, "anyx");
+    assert_int_equal(augments->child->next->nodetype, LYS_ANYXML);
+    assert_string_equal(augments->child->next->next->name, "case");
+    assert_int_equal(augments->child->next->next->nodetype, LYS_CASE);
+    assert_string_equal(augments->child->next->next->next->name, "choice");
+    assert_int_equal(augments->child->next->next->next->nodetype, LYS_CHOICE);
+    assert_string_equal(augments->child->next->next->next->next->name, "subcont");
+    assert_int_equal(augments->child->next->next->next->next->nodetype, LYS_CONTAINER);
+    assert_string_equal(augments->child->next->next->next->next->next->name, "leaf");
+    assert_int_equal(augments->child->next->next->next->next->next->nodetype, LYS_LEAF);
+    assert_string_equal(augments->child->next->next->next->next->next->next->name, "llist");
+    assert_int_equal(augments->child->next->next->next->next->next->next->nodetype, LYS_LEAFLIST);
+    assert_string_equal(augments->child->next->next->next->next->next->next->next->name, "list");
+    assert_int_equal(augments->child->next->next->next->next->next->next->next->nodetype, LYS_LIST);
+    assert_string_equal(augments->child->next->next->next->next->next->next->next->next->name, "uses");
+    assert_int_equal(augments->child->next->next->next->next->next->next->next->next->nodetype, LYS_USES);
+    assert_null(augments->child->next->next->next->next->next->next->next->next->next);
+    assert_string_equal(augments->actions->name, "action");
+    assert_string_equal(augments->notifs->name, "notif");
+    assert_string_equal(augments->exts[0].name, "myext:c-define");
+    assert_int_equal(augments->exts[0].insubstmt_index, 0);
+    assert_int_equal(augments->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    FREE_ARRAY(st->ctx, augments, lysp_augment_free)
+    augments = NULL;
+
+    data = ELEMENT_WRAPPER_START "<augment target-node=\"target\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &aug_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(augments->nodeid, "target");
+    FREE_ARRAY(st->ctx, augments, lysp_augment_free)
+    augments = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_deviate_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_deviate *deviates = NULL;
+    struct lysp_deviate_add *d_add;
+    struct lysp_deviate_rpl *d_rpl;
+    struct lysp_deviate_del *d_del;
+
+    /* all valid arguments with min subelems */
+    data = ELEMENT_WRAPPER_START "<deviate value=\"not-supported\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(deviates->mod, LYS_DEV_NOT_SUPPORTED);
+    lysp_deviate_free(st->ctx, deviates);
+    free(deviates);
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START "<deviate value=\"add\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(deviates->mod, LYS_DEV_ADD);
+    lysp_deviate_free(st->ctx, deviates);
+    free(deviates);
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START "<deviate value=\"replace\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(deviates->mod, LYS_DEV_REPLACE);
+    lysp_deviate_free(st->ctx, deviates);
+    free(deviates);
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START "<deviate value=\"delete\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(deviates->mod, LYS_DEV_DELETE);
+    lysp_deviate_free(st->ctx, deviates);
+    free(deviates);
+    deviates = NULL;
+
+    /* max subelems and valid arguments */
+    data = ELEMENT_WRAPPER_START
+                "<deviate value=\"not-supported\">"
+                    EXT_SUBELEM
+                "</deviate>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+    assert_int_equal(deviates->mod, LYS_DEV_NOT_SUPPORTED);
+    assert_string_equal(deviates->exts[0].name, "myext:c-define");
+    assert_int_equal(deviates->exts[0].insubstmt_index, 0);
+    assert_int_equal(deviates->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_deviate_free(st->ctx, deviates);
+    free(deviates);
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START
+                "<deviate value=\"add\">"
+                    "<units name=\"units\"/>"
+                    "<must condition=\"cond\"/>"
+                    "<unique tag=\"utag\"/>"
+                    "<default value=\"def\"/>"
+                    "<config value=\"true\"/>"
+                    "<mandatory value=\"true\"/>"
+                    "<min-elements value=\"5\"/>"
+                    "<max-elements value=\"15\"/>"
+                    EXT_SUBELEM
+                "</deviate>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+    d_add = (struct lysp_deviate_add *)deviates;
+    assert_int_equal(d_add->mod, LYS_DEV_ADD);
+    assert_null(d_add->next);
+    assert_string_equal(d_add->units, "units");
+    assert_string_equal(d_add->musts->arg, "cond");
+    assert_string_equal(*d_add->uniques, "utag");
+    assert_string_equal(*d_add->dflts, "def");
+    assert_true(d_add->flags & LYS_MAND_TRUE && d_add->flags & LYS_CONFIG_W);
+    assert_int_equal(d_add->min, 5);
+    assert_int_equal(d_add->max, 15);
+    assert_string_equal(deviates->exts[0].name, "myext:c-define");
+    assert_int_equal(deviates->exts[0].insubstmt_index, 0);
+    assert_int_equal(deviates->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_deviate_free(st->ctx, deviates);
+    free(deviates);
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START
+                "<deviate value=\"replace\">"
+                    "<type name=\"newtype\"/>"
+                    "<units name=\"uni\"/>"
+                    "<default value=\"def\"/>"
+                    "<config value=\"true\"/>"
+                    "<mandatory value=\"true\"/>"
+                    "<min-elements value=\"5\"/>"
+                    "<max-elements value=\"15\"/>"
+                    EXT_SUBELEM
+                "</deviate>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+    d_rpl = (struct lysp_deviate_rpl *)deviates;
+    assert_int_equal(d_rpl->mod, LYS_DEV_REPLACE);
+    assert_null(d_rpl->next);
+    assert_string_equal(d_rpl->type->name, "newtype");
+    assert_string_equal(d_rpl->units, "uni");
+    assert_string_equal(d_rpl->dflt, "def");
+    assert_true(d_rpl->flags & LYS_MAND_TRUE && d_rpl->flags & LYS_CONFIG_W);
+    assert_int_equal(d_rpl->min, 5);
+    assert_int_equal(d_rpl->max, 15);
+    assert_string_equal(deviates->exts[0].name, "myext:c-define");
+    assert_int_equal(deviates->exts[0].insubstmt_index, 0);
+    assert_int_equal(deviates->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_deviate_free(st->ctx, deviates);
+    free(deviates);
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START
+                "<deviate value=\"delete\">"
+                    "<units name=\"u\"/>"
+                    "<must condition=\"c\"/>"
+                    "<unique tag=\"tag\"/>"
+                    "<default value=\"default\"/>"
+                    EXT_SUBELEM
+                "</deviate>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+    d_del = (struct lysp_deviate_del *)deviates;
+    assert_int_equal(d_del->mod, LYS_DEV_DELETE);
+    assert_null(d_del->next);
+    assert_string_equal(d_del->units, "u");
+    assert_string_equal(d_del->musts->arg, "c");
+    assert_string_equal(*d_del->uniques, "tag");
+    assert_string_equal(*d_del->dflts, "default");
+    assert_string_equal(deviates->exts[0].name, "myext:c-define");
+    assert_int_equal(deviates->exts[0].insubstmt_index, 0);
+    assert_int_equal(deviates->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_deviate_free(st->ctx, deviates);
+    free(deviates);
+    deviates = NULL;
+
+    /* invalid arguments */
+    data = ELEMENT_WRAPPER_START "<deviate value=\"\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"\" of \"value\" attribute in \"deviate\" element. Valid values are \"not-supported\", \"add\", \"replace\" and \"delete\". Line number 1.");
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START "<deviate value=\"invalid\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"invalid\" of \"value\" attribute in \"deviate\" element. Valid values are \"not-supported\", \"add\", \"replace\" and \"delete\". Line number 1.");
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START "<deviate value=\"ad\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"ad\" of \"value\" attribute in \"deviate\" element. Valid values are \"not-supported\", \"add\", \"replace\" and \"delete\". Line number 1.");
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START "<deviate value=\"adds\" />" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid value \"adds\" of \"value\" attribute in \"deviate\" element. Valid values are \"not-supported\", \"add\", \"replace\" and \"delete\". Line number 1.");
+    deviates = NULL;
+
+    data = ELEMENT_WRAPPER_START
+                "<deviate value=\"not-supported\">"
+                    "<must condition=\"c\"/>"
+                "</deviate>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Deviate of this type doesn't allow \"must\" as it's sub-element. Line number 1.");
+
+    st->finished_correctly = true;
+}
+
+static void
+test_deviation_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_deviation *deviations = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START
+                "<deviation target-node=\"target\">"
+                    "<deviate value=\"not-supported\"/>"
+                "</deviation>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviations, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(deviations->nodeid, "target");
+    assert_int_equal(deviations->deviates->mod, LYS_DEV_NOT_SUPPORTED);
+    FREE_ARRAY(st->ctx, deviations, lysp_deviation_free);
+    deviations = NULL;
+
+    /* max subelems */
+    data = ELEMENT_WRAPPER_START
+                "<deviation target-node=\"target\">"
+                    "<reference><text>ref</text></reference>"
+                    "<description><text>desc</text></description>"
+                    "<deviate value=\"add\"/>"
+                    EXT_SUBELEM
+                "</deviation>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviations, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(deviations->nodeid, "target");
+    assert_int_equal(deviations->deviates->mod, LYS_DEV_ADD);
+    assert_string_equal(deviations->ref, "ref");
+    assert_string_equal(deviations->dsc, "desc");
+    assert_string_equal(deviations->exts[0].name, "myext:c-define");
+    assert_int_equal(deviations->exts[0].insubstmt_index, 0);
+    assert_int_equal(deviations->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    FREE_ARRAY(st->ctx, deviations, lysp_deviation_free);
+    deviations = NULL;
+
+    /* invalid */
+    data = ELEMENT_WRAPPER_START "<deviation target-node=\"target\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &deviations, NULL, NULL, false), LY_EVALID);
+    FREE_ARRAY(st->ctx, deviations, lysp_deviation_free);
+    deviations = NULL;
+    logbuf_assert("Missing mandatory sub-element \"deviate\" of \"deviation\" element. Line number 1.");
+    /* TODO */
+    st->finished_correctly = true;
+}
+
+static void
+test_module_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data, *name, *prefix;
+    size_t name_len, prefix_len;
+    struct yin_arg_record *attrs = NULL;
+    struct lys_module *lys_mod = NULL;
+    struct lysp_module *lysp_mod = NULL;
+
+    /* max subelems */
+    st->yin_ctx->xml_ctx.status = LYXML_ELEMENT;
+    lys_mod = calloc(1, sizeof *lys_mod);
+    lysp_mod = calloc(1, sizeof *lysp_mod);
+    lys_mod->ctx = st->ctx;
+    lysp_mod->mod = lys_mod;
+    data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" name=\"mod\">\n"
+                "<yang-version value=\"1.1\"/>\n"
+                "<namespace uri=\"ns\"/>\n"
+                "<prefix value=\"pref\"/>\n"
+                "<include module=\"b-mod\"/>\n"
+                "<import module=\"a-mod\"><prefix value=\"imp-pref\"/></import>\n"
+                "<organization><text>org</text></organization>\n"
+                "<contact><text>contact</text></contact>\n"
+                "<description><text>desc</text></description>"
+                "<reference><text>ref</text></reference>\n"
+                "<revision date=\"2019-02-02\"/>\n"
+                "<anydata name=\"anyd\"/>\n"
+                "<anyxml name=\"anyx\"/>\n"
+                "<choice name=\"choice\"/>\n"
+                "<container name=\"cont\"/>\n"
+                "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>\n"
+                "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>\n"
+                "<list name=\"sub-list\"/>\n"
+                "<uses name=\"uses-name\"/>\n"
+                "<augment target-node=\"target\"/>\n"
+                "<deviation target-node=\"target\">""<deviate value=\"not-supported\"/>""</deviation>\n"
+                "<extension name=\"ext\"/>\n"
+                "<feature name=\"feature\"/>\n"
+                "<grouping name=\"grp\"/>\n"
+                "<identity name=\"ident-name\"/>\n"
+                "<notification name=\"notf\"/>\n"
+                "<rpc name=\"rpc-name\"/>\n"
+                "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>\n"
+                EXT_SUBELEM"\n"
+           "</module>\n";
+    assert_int_equal(lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len), LY_SUCCESS);
+    assert_int_equal(yin_load_attributes(st->yin_ctx, &data, &attrs), LY_SUCCESS);
+    assert_int_equal(yin_parse_mod(st->yin_ctx, attrs, &data, lysp_mod), LY_SUCCESS);
+    assert_string_equal(lysp_mod->mod->name, "mod");
+    assert_string_equal(lysp_mod->revs, "2019-02-02");
+    assert_string_equal(lysp_mod->mod->ns, "ns");
+    assert_string_equal(lysp_mod->mod->prefix, "pref");
+    assert_null(lysp_mod->mod->filepath);
+    assert_string_equal(lysp_mod->mod->org, "org");
+    assert_string_equal(lysp_mod->mod->contact, "contact");
+    assert_string_equal(lysp_mod->mod->dsc, "desc");
+    assert_string_equal(lysp_mod->mod->ref, "ref");
+    assert_int_equal(lysp_mod->mod->version, LYS_VERSION_1_1);
+    assert_string_equal(lysp_mod->imports->name, "a-mod");
+    assert_string_equal(lysp_mod->includes->name, "b-mod");
+    assert_string_equal(lysp_mod->extensions->name, "ext");
+    assert_string_equal(lysp_mod->features->name, "feature");
+    assert_string_equal(lysp_mod->identities->name, "ident-name");
+    assert_string_equal(lysp_mod->typedefs->name, "tpdf");
+    assert_string_equal(lysp_mod->groupings->name, "grp");
+    assert_string_equal(lysp_mod->data->name, "anyd");
+    assert_int_equal(lysp_mod->data->nodetype, LYS_ANYDATA);
+    assert_string_equal(lysp_mod->data->next->name, "anyx");
+    assert_int_equal(lysp_mod->data->next->nodetype, LYS_ANYXML);
+    assert_string_equal(lysp_mod->data->next->next->name, "choice");
+    assert_int_equal(lysp_mod->data->next->next->nodetype, LYS_CHOICE);
+    assert_string_equal(lysp_mod->data->next->next->next->name, "cont");
+    assert_int_equal(lysp_mod->data->next->next->next->nodetype, LYS_CONTAINER);
+    assert_string_equal(lysp_mod->data->next->next->next->next->name, "leaf");
+    assert_int_equal(lysp_mod->data->next->next->next->next->nodetype, LYS_LEAF);
+    assert_string_equal(lysp_mod->data->next->next->next->next->next->name, "llist");
+    assert_int_equal(lysp_mod->data->next->next->next->next->next->nodetype, LYS_LEAFLIST);
+    assert_string_equal(lysp_mod->data->next->next->next->next->next->next->name, "sub-list");
+    assert_int_equal(lysp_mod->data->next->next->next->next->next->next->nodetype, LYS_LIST);
+    assert_string_equal(lysp_mod->data->next->next->next->next->next->next->next->name, "uses-name");
+    assert_int_equal(lysp_mod->data->next->next->next->next->next->next->next->nodetype, LYS_USES);
+    assert_null(lysp_mod->data->next->next->next->next->next->next->next->next);
+    assert_string_equal(lysp_mod->augments->nodeid, "target");
+    assert_string_equal(lysp_mod->rpcs->name, "rpc-name");
+    assert_string_equal(lysp_mod->notifs->name, "notf");
+    assert_string_equal(lysp_mod->deviations->nodeid, "target");
+    assert_string_equal(lysp_mod->exts[0].name, "myext:c-define");
+    assert_int_equal(lysp_mod->exts[0].insubstmt_index, 0);
+    assert_int_equal(lysp_mod->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+    lysp_module_free(lysp_mod);
+    lys_module_free(lys_mod, NULL);
+    FREE_ARRAY(st->yin_ctx, attrs, free_arg_rec);
+    attrs = NULL;
+
+    /* min subelems */
+    st->yin_ctx->xml_ctx.status = LYXML_ELEMENT;
+    lys_mod = calloc(1, sizeof *lys_mod);
+    lysp_mod = calloc(1, sizeof *lysp_mod);
+    lys_mod->ctx = st->ctx;
+    lysp_mod->mod = lys_mod;
+    data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" name=\"mod\">"
+                "<namespace uri=\"ns\"/>"
+                "<prefix value=\"pref\"/>"
+                "<yang-version value=\"1.1\"/>"
+           "</module>";
+    assert_int_equal(lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len), LY_SUCCESS);
+    assert_int_equal(yin_load_attributes(st->yin_ctx, &data, &attrs), LY_SUCCESS);
+    assert_int_equal(yin_parse_mod(st->yin_ctx, attrs, &data, lysp_mod), LY_SUCCESS);
+    assert_string_equal(lysp_mod->mod->name, "mod");
+    lysp_module_free(lysp_mod);
+    lys_module_free(lys_mod, NULL);
+    FREE_ARRAY(st->yin_ctx, attrs, free_arg_rec);
+    attrs = NULL;
+
+    /* incorrect subelem order */
+    st->yin_ctx->xml_ctx.status = LYXML_ELEMENT;
+    lys_mod = calloc(1, sizeof *lys_mod);
+    lysp_mod = calloc(1, sizeof *lysp_mod);
+    lys_mod->ctx = st->ctx;
+    lysp_mod->mod = lys_mod;
+    data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" name=\"mod\">"
+                "<feature name=\"feature\"/>\n"
+                "<namespace uri=\"ns\"/>"
+                "<prefix value=\"pref\"/>"
+                "<yang-version value=\"1.1\"/>"
+           "</module>";
+    assert_int_equal(lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len), LY_SUCCESS);
+    assert_int_equal(yin_load_attributes(st->yin_ctx, &data, &attrs), LY_SUCCESS);
+    assert_int_equal(yin_parse_mod(st->yin_ctx, attrs, &data, lysp_mod), LY_EVALID);
+    logbuf_assert("Invalid order of module\'s sub-elements \"namespace\" can\'t appear after \"feature\". Line number 30.");
+    lysp_module_free(lysp_mod);
+    lys_module_free(lys_mod, NULL);
+    FREE_ARRAY(st->yin_ctx, attrs, free_arg_rec);
+    attrs = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_submodule_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data, *name, *prefix;
+    size_t name_len, prefix_len;
+    struct yin_arg_record *attrs = NULL;
+    struct lysp_submodule *lysp_submod = NULL;
+
+    /* max subelements */
+    st->yin_ctx->xml_ctx.status = LYXML_ELEMENT;
+    lysp_submod = calloc(1, sizeof *lysp_submod);
+    data = "<submodule xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" name=\"mod\">\n"
+                "<yang-version value=\"1.1\"/>\n"
+                "<belongs-to module=\"mod-name\"><prefix value=\"pref\"/></belongs-to>"
+                "<include module=\"b-mod\"/>\n"
+                "<import module=\"a-mod\"><prefix value=\"imp-pref\"/></import>\n"
+                "<organization><text>org</text></organization>\n"
+                "<contact><text>contact</text></contact>\n"
+                "<description><text>desc</text></description>"
+                "<reference><text>ref</text></reference>\n"
+                "<revision date=\"2019-02-02\"/>\n"
+                "<anydata name=\"anyd\"/>\n"
+                "<anyxml name=\"anyx\"/>\n"
+                "<choice name=\"choice\"/>\n"
+                "<container name=\"cont\"/>\n"
+                "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>\n"
+                "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>\n"
+                "<list name=\"sub-list\"/>\n"
+                "<uses name=\"uses-name\"/>\n"
+                "<augment target-node=\"target\"/>\n"
+                "<deviation target-node=\"target\">""<deviate value=\"not-supported\"/>""</deviation>\n"
+                "<extension name=\"ext\"/>\n"
+                "<feature name=\"feature\"/>\n"
+                "<grouping name=\"grp\"/>\n"
+                "<identity name=\"ident-name\"/>\n"
+                "<notification name=\"notf\"/>\n"
+                "<rpc name=\"rpc-name\"/>\n"
+                "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>\n"
+                EXT_SUBELEM"\n"
+           "</submodule>\n";
+    assert_int_equal(lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len), LY_SUCCESS);
+    assert_int_equal(yin_load_attributes(st->yin_ctx, &data, &attrs), LY_SUCCESS);
+    assert_int_equal(yin_parse_submod(st->yin_ctx, attrs, &data, lysp_submod), LY_SUCCESS);
+
+    assert_string_equal(lysp_submod->name, "mod");
+    assert_string_equal(lysp_submod->revs, "2019-02-02");
+    assert_string_equal(lysp_submod->prefix, "pref");
+    assert_null(lysp_submod->filepath);
+    assert_string_equal(lysp_submod->org, "org");
+    assert_string_equal(lysp_submod->contact, "contact");
+    assert_string_equal(lysp_submod->dsc, "desc");
+    assert_string_equal(lysp_submod->ref, "ref");
+    assert_int_equal(lysp_submod->version, LYS_VERSION_1_1);
+    assert_string_equal(lysp_submod->imports->name, "a-mod");
+    assert_string_equal(lysp_submod->includes->name, "b-mod");
+    assert_string_equal(lysp_submod->extensions->name, "ext");
+    assert_string_equal(lysp_submod->features->name, "feature");
+    assert_string_equal(lysp_submod->identities->name, "ident-name");
+    assert_string_equal(lysp_submod->typedefs->name, "tpdf");
+    assert_string_equal(lysp_submod->groupings->name, "grp");
+    assert_string_equal(lysp_submod->data->name, "anyd");
+    assert_int_equal(lysp_submod->data->nodetype, LYS_ANYDATA);
+    assert_string_equal(lysp_submod->data->next->name, "anyx");
+    assert_int_equal(lysp_submod->data->next->nodetype, LYS_ANYXML);
+    assert_string_equal(lysp_submod->data->next->next->name, "choice");
+    assert_int_equal(lysp_submod->data->next->next->nodetype, LYS_CHOICE);
+    assert_string_equal(lysp_submod->data->next->next->next->name, "cont");
+    assert_int_equal(lysp_submod->data->next->next->next->nodetype, LYS_CONTAINER);
+    assert_string_equal(lysp_submod->data->next->next->next->next->name, "leaf");
+    assert_int_equal(lysp_submod->data->next->next->next->next->nodetype, LYS_LEAF);
+    assert_string_equal(lysp_submod->data->next->next->next->next->next->name, "llist");
+    assert_int_equal(lysp_submod->data->next->next->next->next->next->nodetype, LYS_LEAFLIST);
+    assert_string_equal(lysp_submod->data->next->next->next->next->next->next->name, "sub-list");
+    assert_int_equal(lysp_submod->data->next->next->next->next->next->next->nodetype, LYS_LIST);
+    assert_string_equal(lysp_submod->data->next->next->next->next->next->next->next->name, "uses-name");
+    assert_int_equal(lysp_submod->data->next->next->next->next->next->next->next->nodetype, LYS_USES);
+    assert_null(lysp_submod->data->next->next->next->next->next->next->next->next);
+    assert_string_equal(lysp_submod->augments->nodeid, "target");
+    assert_string_equal(lysp_submod->rpcs->name, "rpc-name");
+    assert_string_equal(lysp_submod->notifs->name, "notf");
+    assert_string_equal(lysp_submod->deviations->nodeid, "target");
+    assert_string_equal(lysp_submod->exts[0].name, "myext:c-define");
+    assert_int_equal(lysp_submod->exts[0].insubstmt_index, 0);
+    assert_int_equal(lysp_submod->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+
+    lysp_submodule_free(st->ctx, lysp_submod);
+    FREE_ARRAY(st->yin_ctx, attrs, free_arg_rec);
+    attrs = NULL;
+
+    /* min subelemnts */
+    st->yin_ctx->xml_ctx.status = LYXML_ELEMENT;
+    lysp_submod = calloc(1, sizeof *lysp_submod);
+    data = "<submodule xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" name=\"submod\">"
+                "<yang-version value=\"1.0\"/>"
+                "<belongs-to module=\"mod-name\"><prefix value=\"pref\"/></belongs-to>"
+           "</submodule>";
+    assert_int_equal(lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len), LY_SUCCESS);
+    assert_int_equal(yin_load_attributes(st->yin_ctx, &data, &attrs), LY_SUCCESS);
+    assert_int_equal(yin_parse_submod(st->yin_ctx, attrs, &data, lysp_submod), LY_SUCCESS);
+    assert_string_equal(lysp_submod->prefix, "pref");
+    assert_string_equal(lysp_submod->belongsto, "mod-name");
+    assert_int_equal(lysp_submod->version, LYS_VERSION_1_0);
+    lysp_submodule_free(st->ctx, lysp_submod);
+    FREE_ARRAY(st->yin_ctx, attrs, free_arg_rec);
+    attrs = NULL;
+
+    /* incorrect subelem order */
+    st->yin_ctx->xml_ctx.status = LYXML_ELEMENT;
+    lysp_submod = calloc(1, sizeof *lysp_submod);
+    data = "<submodule xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" name=\"submod\">"
+                "<yang-version value=\"1.0\"/>"
+                "<reference><text>ref</text></reference>\n"
+                "<belongs-to module=\"mod-name\"><prefix value=\"pref\"/></belongs-to>"
+           "</submodule>";
+    assert_int_equal(lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len), LY_SUCCESS);
+    assert_int_equal(yin_load_attributes(st->yin_ctx, &data, &attrs), LY_SUCCESS);
+    assert_int_equal(yin_parse_submod(st->yin_ctx, attrs, &data, lysp_submod), LY_EVALID);
+    logbuf_assert("Invalid order of submodule's sub-elements \"belongs-to\" can't appear after \"reference\". Line number 28.");
+    lysp_submodule_free(st->ctx, lysp_submod);
+    FREE_ARRAY(st->yin_ctx, attrs, free_arg_rec);
+    attrs = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_yin_parse_module(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lys_module *mod;
+    struct yin_parser_ctx *yin_ctx = NULL;
+
+    mod = calloc(1, sizeof *mod);
+    mod->ctx = st->ctx;
+    data =  "<module name=\"example-foo\""
+             "xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\""
+             "xmlns:foo=\"urn:example:foo\""
+             "xmlns:myext=\"urn:example:extensions\">\n"
+
+                "<yang-version value=\"1.0\"/>\n"
+
+                "<namespace uri=\"urn:example:foo\"/>\n"
+                "<prefix value=\"foo\"/>\n"
+
+                "<import module=\"example-extensions\">\n"
+                    "<prefix value=\"myext\"/>\n"
+                "</import>\n"
+
+                "<list name=\"interface\">\n"
+                    "<key value=\"name\"/>\n"
+                    "<leaf name=\"name\">\n"
+                        "<type name=\"string\"/>\n"
+                    "</leaf>\n"
+                    "<leaf name=\"mtu\">\n"
+                        "<type name=\"uint32\"/>\n"
+                        "<description>\n"
+                            "<text>The MTU of the interface.</text>\n"
+                        "</description>\n"
+                        "<myext:c-define name=\"MY_MTU\"/>\n"
+                    "</leaf>\n"
+                "</list>\n"
+            "</module>\n";
+    assert_int_equal(yin_parse_module(&yin_ctx, data, mod), LY_SUCCESS);
+    lys_module_free(mod, NULL);
+    yin_parser_ctx_free(yin_ctx);
+    mod = NULL;
+    yin_ctx = NULL;
+
+    mod = calloc(1, sizeof *mod);
+    mod->ctx = st->ctx;
+    data =  "<module name=\"example-foo\" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">\n"
+                "<yang-version value=\"1.0\"/>\n"
+                "<namespace uri=\"urn:example:foo\"/>\n"
+                "<prefix value=\"foo\"/>\n"
+            "</module>\n";
+    assert_int_equal(yin_parse_module(&yin_ctx, data, mod), LY_SUCCESS);
+    lys_module_free(mod, NULL);
+    yin_parser_ctx_free(yin_ctx);
+    mod = NULL;
+    yin_ctx = NULL;
+
+
+    mod = calloc(1, sizeof *mod);
+    mod->ctx = st->ctx;
+    data =  "<submodule name=\"example-foo\" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+            "</submodule>\n";
+    assert_int_equal(yin_parse_module(&yin_ctx, data, mod), LY_EINVAL);
+    logbuf_assert("Input data contains submodule which cannot be parsed directly without its main module.");
+    lys_module_free(mod, NULL);
+    yin_parser_ctx_free(yin_ctx);
+
+    mod = calloc(1, sizeof *mod);
+    mod->ctx = st->ctx;
+    data =  "<module name=\"example-foo\" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">\n"
+                "<yang-version value=\"1.0\"/>\n"
+                "<namespace uri=\"urn:example:foo\"/>\n"
+                "<prefix value=\"foo\"/>\n"
+            "</module>"
+            "<module>";
+    assert_int_equal(yin_parse_module(&yin_ctx, data, mod), LY_EVALID);
+    logbuf_assert("Trailing garbage \"<module>\" after module, expected end-of-input. Line number 5.");
+    lys_module_free(mod, NULL);
+    yin_parser_ctx_free(yin_ctx);
+    mod = NULL;
+    yin_ctx = NULL;
+
+    st->finished_correctly = true;
+}
+
+static void
+test_yin_parse_submodule(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct yin_parser_ctx *yin_ctx = NULL;
+    struct lysp_submodule *submod = NULL;
+    struct lys_parser_ctx main_ctx = {};
+
+    data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+            "<submodule name=\"asub\""
+              "xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\""
+              "xmlns:a=\"urn:a\">"
+                "<yang-version value=\"1.0\"/>\n"
+                "<belongs-to module=\"a\">"
+                    "<prefix value=\"a_pref\"/>"
+                "</belongs-to>"
+                "<include module=\"atop\"/>"
+                "<feature name=\"fox\"/>"
+                "<notification name=\"bar-notif\">"
+                    "<if-feature name=\"bar\"/>"
+                "</notification>"
+                "<notification name=\"fox-notif\">"
+                    "<if-feature name=\"fox\"/>"
+                "</notification>"
+                "<augment target-node=\"/a_pref:top\">"
+                    "<if-feature name=\"bar\"/>"
+                    "<container name=\"bar-sub\"/>"
+                "</augment>"
+                "<augment target-node=\"/top\">"
+                    "<container name=\"bar-sub2\"/>"
+                "</augment>"
+            "</submodule>";
+    assert_int_equal(yin_parse_submodule(&yin_ctx, st->ctx, &main_ctx, data, &submod), LY_SUCCESS);
+    lysp_submodule_free(st->ctx, submod);
+    yin_parser_ctx_free(yin_ctx);
+    yin_ctx = NULL;
+    submod = NULL;
+
+    data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+            "<submodule name=\"asub\" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+                "<yang-version value=\"1.0\"/>\n"
+                "<belongs-to module=\"a\">"
+                    "<prefix value=\"a_pref\"/>"
+                "</belongs-to>"
+            "</submodule>";
+    assert_int_equal(yin_parse_submodule(&yin_ctx, st->ctx, &main_ctx, data, &submod), LY_SUCCESS);
+    lysp_submodule_free(st->ctx, submod);
+    yin_parser_ctx_free(yin_ctx);
+    yin_ctx = NULL;
+    submod = NULL;
+
+    data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+            "<module name=\"inval\" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+            "</module>";
+    assert_int_equal(yin_parse_submodule(&yin_ctx, st->ctx, &main_ctx, data, &submod), LY_EINVAL);
+    logbuf_assert("Input data contains module in situation when a submodule is expected.");
+    lysp_submodule_free(st->ctx, submod);
+    yin_parser_ctx_free(yin_ctx);
+    yin_ctx = NULL;
+    submod = NULL;
+
+    data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+            "<submodule name=\"asub\" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+                "<yang-version value=\"1.0\"/>\n"
+                "<belongs-to module=\"a\">"
+                    "<prefix value=\"a_pref\"/>"
+                "</belongs-to>"
+            "</submodule>"
+            "<submodule name=\"asub\" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+                "<yang-version value=\"1.0\"/>\n"
+                "<belongs-to module=\"a\">"
+                    "<prefix value=\"a_pref\"/>"
+                "</belongs-to>"
+            "</submodule>";
+    assert_int_equal(yin_parse_submodule(&yin_ctx, st->ctx, &main_ctx, data, &submod), LY_EVALID);
+    logbuf_assert("Trailing garbage \"<submodule name...\" after submodule, expected end-of-input. Line number 2.");
+    lysp_submodule_free(st->ctx, submod);
+    yin_parser_ctx_free(yin_ctx);
+    yin_ctx = NULL;
+    submod = NULL;
+
+    st->finished_correctly = true;
+}
+
+int
+main(void)
+{
+
+    const struct CMUnitTest tests[] = {
+        cmocka_unit_test_setup_teardown(test_yin_match_keyword, setup_f, teardown_f),
+        cmocka_unit_test_setup_teardown(test_yin_parse_element_generic, setup_f, teardown_f),
+        cmocka_unit_test_setup_teardown(test_yin_parse_extension_instance, setup_f, teardown_f),
+        cmocka_unit_test_setup_teardown(test_yin_parse_content, setup_f, teardown_f),
+        cmocka_unit_test_setup_teardown(test_validate_value, setup_f, teardown_f),
+
+        cmocka_unit_test(test_yin_match_argument_name),
+        cmocka_unit_test_setup_teardown(test_enum_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_bit_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_meta_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_import_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_status_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_ext_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_yin_element_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_yangversion_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_mandatory_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_argument_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_base_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_belongsto_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_config_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_default_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_err_app_tag_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_err_msg_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_fracdigits_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_iffeature_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_length_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_modifier_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_namespace_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_path_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_pattern_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_value_position_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_prefix_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_range_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_reqinstance_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_revision_date_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_unique_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_units_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_when_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_yin_text_value_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_type_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_max_elems_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_min_elems_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_ordby_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_any_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_leaf_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_leaf_list_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_presence_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_key_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_typedef_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_refine_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_uses_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_revision_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_include_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_feature_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_identity_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_list_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_notification_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_grouping_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_container_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_case_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_choice_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_inout_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_action_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_augment_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_deviate_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_deviation_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_module_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_submodule_elem, setup_element_test, teardown_element_test),
+
+        cmocka_unit_test_setup_teardown(test_yin_parse_module, setup_logger, teardown_logger),
+        cmocka_unit_test_setup_teardown(test_yin_parse_submodule, setup_logger, teardown_logger),
+    };
+
+    return cmocka_run_group_tests(tests, setup_ly_ctx, destroy_ly_ctx);
+}
diff --git a/tests/src/test_tree_schema_compile.c b/tests/src/test_tree_schema_compile.c
index 1be0815..6ebe998 100644
--- a/tests/src/test_tree_schema_compile.c
+++ b/tests/src/test_tree_schema_compile.c
@@ -26,6 +26,7 @@
 #include "../../src/plugins_types.h"
 
 void lysc_feature_free(struct ly_ctx *ctx, struct lysc_feature *feat);
+void lys_parser_ctx_free(struct lys_parser_ctx *ctx);
 
 LY_ERR lys_path_token(const char **path, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len,
                       int *parent_times, int *has_predicate);
@@ -95,20 +96,21 @@
 }
 
 static void
-reset_mod(struct ly_ctx *ctx, struct lys_module *module)
+reset_mod(struct lys_module *module)
 {
+    struct ly_ctx *ctx = module->ctx;
     lysc_module_free(module->compiled, NULL);
     lysp_module_free(module->parsed);
 
-    FREE_STRING(module->ctx, module->name);
-    FREE_STRING(module->ctx, module->ns);
-    FREE_STRING(module->ctx, module->prefix);
-    FREE_STRING(module->ctx, module->filepath);
-    FREE_STRING(module->ctx, module->org);
-    FREE_STRING(module->ctx, module->contact);
-    FREE_STRING(module->ctx, module->dsc);
-    FREE_STRING(module->ctx, module->ref);
-    FREE_ARRAY(module->ctx, module->off_features, lysc_feature_free);
+    FREE_STRING(ctx, module->name);
+    FREE_STRING(ctx, module->ns);
+    FREE_STRING(ctx, module->prefix);
+    FREE_STRING(ctx, module->filepath);
+    FREE_STRING(ctx, module->org);
+    FREE_STRING(ctx, module->contact);
+    FREE_STRING(ctx, module->dsc);
+    FREE_STRING(ctx, module->ref);
+    FREE_ARRAY(ctx, module->off_features, lysc_feature_free);
 
     memset(module, 0, sizeof *module);
     module->ctx = ctx;
@@ -121,21 +123,22 @@
     *state = test_module;
 
     const char *str;
-    struct lys_parser_ctx ctx = {0};
+    struct lys_parser_ctx *ctx = NULL;
     struct lys_module mod = {0};
     struct lysc_feature *f;
     struct lysc_iffeature *iff;
 
     str = "module test {namespace urn:test; prefix t;"
           "feature f1;feature f2 {if-feature f1;}}";
-    assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
-    reset_mod(ctx.ctx, &mod);
+    assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &mod.ctx));
+    reset_mod(&mod);
 
     assert_int_equal(LY_EINVAL, lys_compile(NULL, 0));
     logbuf_assert("Invalid argument mod (lys_compile()).");
     assert_int_equal(LY_EINVAL, lys_compile(&mod, 0));
     logbuf_assert("Invalid argument mod->parsed (lys_compile()).");
     assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, str, &mod));
+    lys_parser_ctx_free(ctx);
     mod.implemented = 0;
     assert_int_equal(LY_SUCCESS, lys_compile(&mod, 0));
     assert_null(mod.compiled);
@@ -168,20 +171,22 @@
     /* submodules cannot be compiled directly */
     str = "submodule test {belongs-to xxx {prefix x;}}";
     assert_int_equal(LY_EINVAL, yang_parse_module(&ctx, str, &mod));
+    lys_parser_ctx_free(ctx);
     logbuf_assert("Input data contains submodule which cannot be parsed directly without its main module.");
     assert_null(mod.parsed);
-    reset_mod(ctx.ctx, &mod);
+    reset_mod(&mod);
 
     /* data definition name collision in top level */
     assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module aa {namespace urn:aa;prefix aa;"
                                                   "leaf a {type string;} container a{presence x;}}", &mod));
+    lys_parser_ctx_free(ctx);
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Duplicate identifier \"a\" of data definition/RPC/action/Notification statement. /aa:a");
     assert_null(mod.compiled);
-    reset_mod(ctx.ctx, &mod);
+    reset_mod(&mod);
 
     *state = NULL;
-    ly_ctx_destroy(ctx.ctx, NULL);
+    ly_ctx_destroy(mod.ctx, NULL);
 }
 
 static void
@@ -189,7 +194,7 @@
 {
     *state = test_feature;
 
-    struct lys_parser_ctx ctx = {0};
+    struct lys_parser_ctx *ctx = NULL;
     struct lys_module mod = {0}, *modp;
     const char *str;
     struct lysc_feature *f, *f1;
@@ -203,10 +208,11 @@
           "feature f8 {if-feature \"f1 or f2 or f3 or orfeature or andfeature\";}\n"
           "feature f9 {if-feature \"not not f1\";}}";
 
-    assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
-    reset_mod(ctx.ctx, &mod);
+    assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &mod.ctx));
+    reset_mod(&mod);
 
     assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, str, &mod));
+    lys_parser_ctx_free(ctx);
     assert_int_equal(LY_SUCCESS, lys_compile(&mod, 0));
     assert_non_null(mod.compiled);
     assert_non_null(mod.compiled->features);
@@ -283,7 +289,7 @@
     assert_int_equal(1, lys_feature_value(&mod, "f1"));
     assert_int_equal(0, lys_feature_value(&mod, "f2"));
 
-    assert_non_null(modp = lys_parse_mem(ctx.ctx, "module b {namespace urn:b;prefix b;"
+    assert_non_null(modp = lys_parse_mem(mod.ctx, "module b {namespace urn:b;prefix b;"
                                          "feature f1 {if-feature f2;}feature f2;}", LYS_IN_YANG));
     assert_non_null(modp->compiled);
     assert_non_null(modp->compiled->features);
@@ -303,83 +309,91 @@
     assert_int_equal(LY_EINVAL, lys_feature_enable(&mod, "xxx"));
     logbuf_assert("Feature \"xxx\" not found in module \"a\".");
 
-    reset_mod(ctx.ctx, &mod);
+    reset_mod(&mod);
 
     /* some invalid expressions */
     assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f{if-feature f1;}}", &mod));
+    lys_parser_ctx_free(ctx);
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Invalid value \"f1\" of if-feature - unable to find feature \"f1\". /b:{feature='f'}");
-    reset_mod(ctx.ctx, &mod);
+    reset_mod(&mod);
 
     assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature 'f and';}}", &mod));
+    lys_parser_ctx_free(ctx);
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Invalid value \"f and\" of if-feature - unexpected end of expression. /b:{feature='f2'}");
-    reset_mod(ctx.ctx, &mod);
+    reset_mod(&mod);
 
     assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f{if-feature 'or';}}", &mod));
+    lys_parser_ctx_free(ctx);
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Invalid value \"or\" of if-feature - unexpected end of expression. /b:{feature='f'}");
-    reset_mod(ctx.ctx, &mod);
+    reset_mod(&mod);
 
     assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature '(f1';}}", &mod));
+    lys_parser_ctx_free(ctx);
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Invalid value \"(f1\" of if-feature - non-matching opening and closing parentheses. /b:{feature='f2'}");
-    reset_mod(ctx.ctx, &mod);
+    reset_mod(&mod);
 
     assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature 'f1)';}}", &mod));
+    lys_parser_ctx_free(ctx);
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Invalid value \"f1)\" of if-feature - non-matching opening and closing parentheses. /b:{feature='f2'}");
-    reset_mod(ctx.ctx, &mod);
+    reset_mod(&mod);
 
     assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature ---;}}", &mod));
+    lys_parser_ctx_free(ctx);
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Invalid value \"---\" of if-feature - unable to find feature \"---\". /b:{feature='f2'}");
-    reset_mod(ctx.ctx, &mod);
+    reset_mod(&mod);
 
     assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{namespace urn:b; prefix b; feature f1; feature f2{if-feature 'not f1';}}", &mod));
+    lys_parser_ctx_free(ctx);
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Invalid value \"not f1\" of if-feature - YANG 1.1 expression in YANG 1.0 module. /b:{feature='f2'}");
-    reset_mod(ctx.ctx, &mod);
+    reset_mod(&mod);
 
     assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{namespace urn:b; prefix b; feature f1; feature f1;}", &mod));
+    lys_parser_ctx_free(ctx);
     assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
     logbuf_assert("Duplicate identifier \"f1\" of feature statement. /b:{feature='f1'}");
-    reset_mod(ctx.ctx, &mod);
+    reset_mod(&mod);
 
-    ly_ctx_set_module_imp_clb(ctx.ctx, test_imp_clb, "submodule sz {belongs-to z {prefix z;} feature f1;}");
-    assert_null(lys_parse_mem(ctx.ctx, "module z{namespace urn:z; prefix z; include sz;feature f1;}", LYS_IN_YANG));
+    ly_ctx_set_module_imp_clb(mod.ctx, test_imp_clb, "submodule sz {belongs-to z {prefix z;} feature f1;}");
+    assert_null(lys_parse_mem(mod.ctx, "module z{namespace urn:z; prefix z; include sz;feature f1;}", LYS_IN_YANG));
     logbuf_assert("Duplicate identifier \"f1\" of feature statement. /z:{feature='f1'}");
 
-    assert_null(lys_parse_mem(ctx.ctx, "module aa{namespace urn:aa; prefix aa; feature f1 {if-feature f2;} feature f2 {if-feature f1;}}", LYS_IN_YANG));
+    assert_null(lys_parse_mem(mod.ctx, "module aa{namespace urn:aa; prefix aa; feature f1 {if-feature f2;} feature f2 {if-feature f1;}}", LYS_IN_YANG));
     logbuf_assert("Feature \"f1\" is indirectly referenced from itself. /aa:{feature='f2'}");
-    assert_null(lys_parse_mem(ctx.ctx, "module ab{namespace urn:ab; prefix ab; feature f1 {if-feature f1;}}", LYS_IN_YANG));
+    assert_null(lys_parse_mem(mod.ctx, "module ab{namespace urn:ab; prefix ab; feature f1 {if-feature f1;}}", LYS_IN_YANG));
     logbuf_assert("Feature \"f1\" is referenced from itself. /ab:{feature='f1'}");
 
-    assert_null(lys_parse_mem(ctx.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f {if-feature ();}}", LYS_IN_YANG));
+    assert_null(lys_parse_mem(mod.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f {if-feature ();}}", LYS_IN_YANG));
     logbuf_assert("Invalid value \"()\" of if-feature - number of features in expression does not match the required number "
             "of operands for the operations. /bb:{feature='f'}");
-    assert_null(lys_parse_mem(ctx.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f {if-feature 'f1(';}}", LYS_IN_YANG));
+    assert_null(lys_parse_mem(mod.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f {if-feature 'f1(';}}", LYS_IN_YANG));
     logbuf_assert("Invalid value \"f1(\" of if-feature - non-matching opening and closing parentheses. /bb:{feature='f'}");
-    assert_null(lys_parse_mem(ctx.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f {if-feature 'and f1';}}", LYS_IN_YANG));
+    assert_null(lys_parse_mem(mod.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f {if-feature 'and f1';}}", LYS_IN_YANG));
     logbuf_assert("Invalid value \"and f1\" of if-feature - missing feature/expression before \"and\" operation. /bb:{feature='f'}");
-    assert_null(lys_parse_mem(ctx.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f {if-feature 'f1 not ';}}", LYS_IN_YANG));
+    assert_null(lys_parse_mem(mod.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f {if-feature 'f1 not ';}}", LYS_IN_YANG));
     logbuf_assert("Invalid value \"f1 not \" of if-feature - unexpected end of expression. /bb:{feature='f'}");
-    assert_null(lys_parse_mem(ctx.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f {if-feature 'f1 not not ';}}", LYS_IN_YANG));
+    assert_null(lys_parse_mem(mod.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f {if-feature 'f1 not not ';}}", LYS_IN_YANG));
     logbuf_assert("Invalid value \"f1 not not \" of if-feature - unexpected end of expression. /bb:{feature='f'}");
-    assert_null(lys_parse_mem(ctx.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f2; "
+    assert_null(lys_parse_mem(mod.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f2; "
                               "feature f {if-feature 'or f1 f2';}}", LYS_IN_YANG));
     logbuf_assert("Invalid value \"or f1 f2\" of if-feature - missing feature/expression before \"or\" operation. /bb:{feature='f'}");
 
     /* import reference */
-    assert_non_null(modp = lys_parse_mem(ctx.ctx, str, LYS_IN_YANG));
+    assert_non_null(modp = lys_parse_mem(mod.ctx, str, LYS_IN_YANG));
     assert_int_equal(LY_SUCCESS, lys_feature_enable(modp, "f1"));
-    assert_non_null(modp = lys_parse_mem(ctx.ctx, "module c{namespace urn:c; prefix c; import a {prefix a;} feature f1; feature f2{if-feature 'a:f1';}}", LYS_IN_YANG));
+    assert_non_null(modp = lys_parse_mem(mod.ctx, "module c{namespace urn:c; prefix c; import a {prefix a;} feature f1; feature f2{if-feature 'a:f1';}}", LYS_IN_YANG));
     assert_int_equal(LY_SUCCESS, lys_feature_enable(modp, "f2"));
     assert_int_equal(0, lys_feature_value(modp, "f1"));
     assert_int_equal(1, lys_feature_value(modp, "f2"));
 
     *state = NULL;
-    ly_ctx_destroy(ctx.ctx, NULL);
+    ly_ctx_destroy(mod.ctx, NULL);
 }
 
 static void
@@ -1515,7 +1529,7 @@
     assert_int_equal(8, ((struct lysc_type_bits*)type)->bits[4].position);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module b {yang-version 1.1;namespace urn:b;prefix b;feature f; typedef mytype {type bits {"
-                                        "bit automin; bit one;bit two; bit seven {value 7;}bit eight;}} leaf l { type mytype {bit eight;bit seven;bit automin;}}}",
+                                        "bit automin; bit one;bit two; bit seven {position 7;}bit eight;}} leaf l { type mytype {bit eight;bit seven;bit automin;}}}",
                                         LYS_IN_YANG));
     type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
     assert_non_null(type);
@@ -1538,8 +1552,8 @@
                                    "bit one {position -1;}}}}", LYS_IN_YANG));
     logbuf_assert("Invalid value \"-1\" of \"position\". Line number 1.");
     assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa; leaf l {type bits {"
-                                   "bit one {value 4294967296;}}}}", LYS_IN_YANG));
-    logbuf_assert("Invalid value \"4294967296\" of \"value\". Line number 1.");
+                                   "bit one {position 4294967296;}}}}", LYS_IN_YANG));
+    logbuf_assert("Invalid value \"4294967296\" of \"position\". Line number 1.");
     assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa; leaf l {type bits {"
                                    "bit one; bit one;}}}", LYS_IN_YANG));
     logbuf_assert("Duplicate identifier \"one\" of bit statement. Line number 1.");
@@ -1563,7 +1577,7 @@
     assert_null(lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee;leaf l {type bits {bit x {position 4294967295;}bit y;}}}", LYS_IN_YANG));
     logbuf_assert("Invalid bits - it is not possible to auto-assign bit position for \"y\" since the highest value is already 4294967295. /ee:l");
 
-    assert_null(lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff;leaf l {type bits {bit x {value 1;}bit y {value 1;}}}}", LYS_IN_YANG));
+    assert_null(lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff;leaf l {type bits {bit x {position 1;}bit y {position 1;}}}}", LYS_IN_YANG));
     logbuf_assert("Invalid bits - position 1 collide in items \"y\" and \"x\". /ff:l");
 
     assert_null(lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg;typedef mytype {type bits;}"
diff --git a/tests/src/test_xml.c b/tests/src/test_xml.c
index 1622b92..ffa1e2d 100644
--- a/tests/src/test_xml.c
+++ b/tests/src/test_xml.c
@@ -224,6 +224,15 @@
     logbuf_assert("Mixed XML content is not allowed (text <b>). Line number 1.");
     lyxml_context_clear(&ctx);
 
+    /* tag missmatch */
+    str = "<a>text</b>";
+    assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
+    assert_string_equal("text</b>", str);
+    assert_int_equal(LYXML_ELEM_CONTENT, ctx.status);
+    assert_int_equal(LY_EVALID, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
+    logbuf_assert("Opening and closing elements tag missmatch (\"b\"). Line number 1.");
+    lyxml_context_clear(&ctx);
+
 }
 
 static void