parser xml CHANGE major refactorization

Completely new XML parser and also some
schema parser refactoring.
diff --git a/src/common.c b/src/common.c
index 0abfcd6..2372cee 100644
--- a/src/common.c
+++ b/src/common.c
@@ -183,9 +183,9 @@
 }
 
 LY_ERR
-ly_getutf8(const char **input, unsigned int *utf8_char, size_t *bytes_read)
+ly_getutf8(const char **input, uint32_t *utf8_char, size_t *bytes_read)
 {
-    unsigned int c, len;
+    uint32_t c, len;
     int aux;
     int i;
 
diff --git a/src/common.h b/src/common.h
index 2b58fbf..ab4aa13 100644
--- a/src/common.h
+++ b/src/common.h
@@ -304,6 +304,17 @@
  * Generic useful functions.
  *****************************************************************************/
 
+/**
+ * @brief Insert string into dictionary.
+ *
+ * @param[in] CTX libyang context.
+ * @param[in] STRING string to store.
+ * @param[in] LEN length of the string in WORD to store.
+ * @param[in,out] DYNAMIC Set to 1 if STR is dynamically allocated, 0 otherwise. If set to 1, zerocopy version of lydict_insert is used.
+ */
+#define INSERT_STRING(CTX, STRING, LEN, DYNAMIC) \
+    (DYNAMIC ? lydict_insert_zc(CTX, (char *)(STRING)) : lydict_insert(CTX, LEN ? (STRING) : "", LEN)); DYNAMIC = 0
+
 #define FREE_STRING(CTX, STRING) if (STRING) {lydict_remove(CTX, STRING);}
 
 /**
@@ -346,7 +357,7 @@
  * @param[out] bytes_read Number of bytes used to encode the read utf8_char.
  * @return LY_ERR value
  */
-LY_ERR ly_getutf8(const char **input, unsigned int *utf8_char, size_t *bytes_read);
+LY_ERR ly_getutf8(const char **input, uint32_t *utf8_char, size_t *bytes_read);
 
 /**
  * @brief Get number of characters in the @p str, taking multibyte characters into account.
diff --git a/src/context.h b/src/context.h
index a3c6366..53634cd 100644
--- a/src/context.h
+++ b/src/context.h
@@ -172,7 +172,7 @@
                                         recursively). */
 #define LY_CTX_PREFER_SEARCHDIRS 0x20 /**< When searching for schema, prefer searchdirs instead of user callback. */
 
-/**@} contextoptions */
+/** @} contextoptions */
 
 /**
  * @brief Create libyang context.
diff --git a/src/parser_stmt.c b/src/parser_stmt.c
index f282322..c9fe163 100644
--- a/src/parser_stmt.c
+++ b/src/parser_stmt.c
@@ -69,17 +69,17 @@
 {
     struct lysp_ext_instance *e;
 
-    LY_ARRAY_NEW_RET(ctx->ctx, *exts, e, LY_EMEM);
+    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *exts, e, LY_EMEM);
 
     /* store name and insubstmt info */
-    e->name = lydict_insert(ctx->ctx, stmt->stmt, 0);
+    e->name = lydict_insert(PARSER_CTX(ctx), stmt->stmt, 0);
     e->insubstmt = insubstmt;
     e->insubstmt_index = insubstmt_index;
     /* TODO (duplicate) e->child = stmt->child; */
 
     /* get optional argument */
     if (stmt->arg) {
-        e->argument = lydict_insert(ctx->ctx, stmt->arg, 0);
+        e->argument = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
     }
 
     return LY_SUCCESS;
@@ -111,7 +111,7 @@
     }
 
     LY_CHECK_RET(lysp_stmt_validate_value(ctx, arg, stmt->arg));
-    *value = lydict_insert(ctx->ctx, stmt->arg, 0);
+    *value = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
 
     for (child = stmt->child; child; child = child->next) {
         const char *s = child->stmt;
@@ -151,8 +151,8 @@
     LY_CHECK_RET(lysp_stmt_validate_value(ctx, arg, stmt->arg));
 
     /* allocate new pointer */
-    LY_ARRAY_NEW_RET(ctx->ctx, *texts, item, LY_EMEM);
-    *item = lydict_insert(ctx->ctx, stmt->arg, 0);
+    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *texts, item, LY_EMEM);
+    *item = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
 
     for (child = stmt->child; child; child = child->next) {
         const char *s = child->stmt;
@@ -236,7 +236,7 @@
     const struct lysp_stmt *child;
 
     LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
-    restr->arg = lydict_insert(ctx->ctx, stmt->arg, 0);
+    restr->arg = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
 
     for (child = stmt->child; child; child = child->next) {
         const char *s = child->stmt;
@@ -281,7 +281,7 @@
 {
     struct lysp_restr *restr;
 
-    LY_ARRAY_NEW_RET(ctx->ctx, *restrs, restr, LY_EMEM);
+    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *restrs, restr, LY_EMEM);
     return lysp_stmt_restr(ctx, stmt, restr_kw, restr);
 }
 
@@ -387,13 +387,13 @@
 
     LY_CHECK_RET(lysp_stmt_validate_value(ctx, enum_kw == LY_STMT_ENUM ? Y_STR_ARG : Y_IDENTIF_ARG, stmt->arg));
 
-    LY_ARRAY_NEW_RET(ctx->ctx, *enums, enm, LY_EMEM);
+    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *enums, enm, LY_EMEM);
 
     if (enum_kw == LY_STMT_ENUM) {
         LY_CHECK_RET(lysp_check_enum_name(ctx, stmt->arg, strlen(stmt->arg)));
     } /* else nothing specific for YANG_BIT */
 
-    enm->name = lydict_insert(ctx->ctx, stmt->arg, 0);
+    enm->name = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
     CHECK_UNIQUENESS(ctx, *enums, name, ly_stmt2str(enum_kw), enm->name);
 
     for (child = stmt->child; child; child = child->next) {
@@ -574,13 +574,13 @@
 
     /* replace the value in the dictionary */
     buf = malloc(strlen(*pat) + 1);
-    LY_CHECK_ERR_RET(!buf, LOGMEM(ctx->ctx), LY_EMEM);
+    LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
     strcpy(buf, *pat);
-    lydict_remove(ctx->ctx, *pat);
+    lydict_remove(PARSER_CTX(ctx), *pat);
 
     assert(buf[0] == 0x06);
     buf[0] = 0x15;
-    *pat = lydict_insert_zc(ctx->ctx, buf);
+    *pat = lydict_insert_zc(PARSER_CTX(ctx), buf);
 
     for (child = stmt->child; child; child = child->next) {
         const char *s = child->stmt;
@@ -616,16 +616,16 @@
     struct lysp_restr *restr;
 
     LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
-    LY_ARRAY_NEW_RET(ctx->ctx, *patterns, restr, LY_EMEM);
+    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *patterns, restr, LY_EMEM);
     arg_len = strlen(stmt->arg);
 
     /* add special meaning first byte */
     buf = malloc(arg_len + 2);
-    LY_CHECK_ERR_RET(!buf, LOGMEM(ctx->ctx), LY_EMEM);
+    LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
     memmove(buf + 1, stmt->arg, arg_len);
     buf[0] = 0x06; /* pattern's default regular-match flag */
     buf[arg_len + 1] = '\0'; /* terminating NULL byte */
-    restr->arg = lydict_insert_zc(ctx->ctx, buf);
+    restr->arg = lydict_insert_zc(PARSER_CTX(ctx), buf);
 
     for (child = stmt->child; child; child = child->next) {
         const char *s = child->stmt;
@@ -678,7 +678,7 @@
         LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "type");
         return LY_EVALID;
     }
-    type->name = lydict_insert(ctx->ctx, stmt->arg, 0);
+    type->name = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
 
     for (child = stmt->child; child; child = child->next) {
         const char *s = child->stmt;
@@ -707,7 +707,7 @@
                 return LY_EVALID;
             }
             type->length = calloc(1, sizeof *type->length);
-            LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx->ctx), LY_EMEM);
+            LY_CHECK_ERR_RET(!type->length, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
 
             LY_CHECK_RET(lysp_stmt_restr(ctx, child, kw, type->length));
             type->flags |= LYS_SET_LENGTH;
@@ -726,7 +726,7 @@
                 return LY_EVALID;
             }
             type->range = calloc(1, sizeof *type->range);
-            LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx->ctx), LY_EMEM);
+            LY_CHECK_ERR_RET(!type->range, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
 
             LY_CHECK_RET(lysp_stmt_restr(ctx, child, kw, type->range));
             type->flags |= LYS_SET_RANGE;
@@ -736,7 +736,7 @@
             /* LYS_SET_REQINST checked and set inside parse_type_reqinstance() */
             break;
         case LY_STMT_TYPE:
-            LY_ARRAY_NEW_RET(ctx->ctx, type->types, nest_type, LY_EMEM);
+            LY_ARRAY_NEW_RET(PARSER_CTX(ctx), type->types, nest_type, LY_EMEM);
             LY_CHECK_RET(lysp_stmt_type(ctx, child, nest_type));
             type->flags |= LYS_SET_TYPE;
             break;
@@ -755,8 +755,9 @@
 lysp_stmt_parse(struct lysc_ctx *ctx, const struct lysp_stmt *stmt, enum ly_stmt kw, void **result, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
-    struct lys_parser_ctx pctx = {0};
+    struct lys_yang_parser_ctx pctx = {0};
 
+    pctx.format = LYS_IN_YANG;
     pctx.ctx = ctx->ctx;
     pctx.mod_version = ctx->mod->version;
     pctx.pos_type = LY_VLOG_STR;
@@ -764,14 +765,14 @@
 
     switch(kw) {
     case LY_STMT_STATUS: {
-        ret = lysp_stmt_status(&pctx, stmt, *(uint16_t**)result, exts);
+        ret = lysp_stmt_status((struct lys_parser_ctx *)&pctx, stmt, *(uint16_t**)result, exts);
         break;
     }
     case LY_STMT_TYPE: {
         struct lysp_type *type;
         type = calloc(1, sizeof *type);
 
-        ret = lysp_stmt_type(&pctx, stmt, type);
+        ret = lysp_stmt_type((struct lys_parser_ctx *)&pctx, stmt, type);
         (*result) = type;
         break;
         }
diff --git a/src/parser_xml.c b/src/parser_xml.c
index e05f170..792d377 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -31,16 +31,10 @@
 #include "validation.h"
 
 /**
- * @brief internal context for XML YANG data parser.
- *
- * The leading part is compatible with the struct lyxml_context
+ * @brief Internal context for XML YANG data parser.
  */
 struct lyd_xml_ctx {
-    struct ly_ctx *ctx;              /**< libyang context */
-    uint64_t line;                   /**< number of the line being currently processed */
-    enum LYXML_PARSER_STATUS status; /**< status providing information about the next expected object in input data */
-    struct ly_set elements;          /**< list of not-yet-closed elements */
-    struct ly_set ns;                /**< handled with LY_SET_OPT_USEASLIST */
+    struct lyxml_ctx *xmlctx;        /**< XML context */
 
     uint32_t options;                /**< various @ref dataparseroptions. */
     uint32_t path_len;               /**< used bytes in the path buffer */
@@ -52,14 +46,14 @@
 };
 
 /**
- * @brief XML-parser's implementation of ly_type_resolve_prefix() callback to provide mapping between prefixes used in the values to the schema
- * via XML namespaces.
+ * @brief XML-parser's implementation of ly_type_resolve_prefix() callback to provide mapping between prefixes used
+ * in the values to the schema via XML namespaces.
  */
 static const struct lys_module *
 lydxml_resolve_prefix(const struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *parser)
 {
     const struct lyxml_ns *ns;
-    struct lyxml_context *xmlctx = (struct lyxml_context*)parser;
+    struct lyxml_ctx *xmlctx = (struct lyxml_ctx *)parser;
 
     ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
     if (!ns) {
@@ -69,101 +63,41 @@
     return ly_ctx_get_module_implemented_ns(ctx, ns->uri);
 }
 
-struct attr_data_s {
-    const char *prefix;
-    const char *name;
-    char *value;
-    size_t prefix_len;
-    size_t name_len;
-    size_t value_len;
-    int dynamic;
-};
-
-/**
- * @brief Parse XML attributes of the XML element of YANG data.
- *
- * @param[in] xmlctx XML parser context.
- * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
- * @param[out] attributes Resulting list of the parsed attributes. XML namespace definitions are not parsed
- * as attributes, they are stored internally in the parser context.
- * @reutn LY_ERR value.
- */
 static LY_ERR
-lydxml_attributes_parse(struct lyxml_context *xmlctx, const char **data, struct ly_set *attrs_data)
+lydxml_metadata(struct lyxml_ctx *xmlctx, const struct lysc_node *sparent, int strict, struct ly_set *type_meta_check,
+                struct lyd_meta **meta)
 {
-    LY_ERR ret = LY_SUCCESS;
-    unsigned int u;
-    const char *prefix, *name;
-    size_t prefix_len, name_len;
-    struct attr_data_s *attr_data;
-
-    while (xmlctx->status == LYXML_ATTRIBUTE &&
-            lyxml_get_attribute(xmlctx, data, &prefix, &prefix_len, &name, &name_len) == LY_SUCCESS) {
-        char *buffer = NULL;
-        size_t buffer_size = 0;
-
-        if (!name) {
-            /* seems like all the attrributes were internally processed as namespace definitions */
-            continue;
-        }
-
-        /* auxiliary store the prefix information and value string, because we have to wait with resolving prefix
-         * to the time when all the namespaces, defined in this element, are parsed. With the prefix we can find the
-         * annotation definition for the attribute and correctly process the value */
-        attr_data = malloc(sizeof *attr_data);
-        attr_data->prefix = prefix;
-        attr_data->name = name;
-        attr_data->prefix_len = prefix_len;
-        attr_data->name_len = name_len;
-        ret = lyxml_get_string(xmlctx, data, &buffer, &buffer_size, &attr_data->value, &attr_data->value_len, &attr_data->dynamic);
-        LY_CHECK_ERR_GOTO(ret, free(attr_data), error);
-        ly_set_add(attrs_data, attr_data, LY_SET_OPT_USEASLIST);
-    }
-
-    return LY_SUCCESS;
-
-error:
-    for (u = 0; u < attrs_data->count; ++u) {
-        if (((struct attr_data_s*)attrs_data->objs[u])->dynamic) {
-            free(((struct attr_data_s*)attrs_data->objs[u])->value);
-        }
-    }
-    ly_set_erase(attrs_data, free);
-    return ret;
-}
-
-static LY_ERR
-lydxml_metadata(struct lyxml_context *xmlctx, struct ly_set *attrs_data, const struct lysc_node *sparent, int strict,
-                struct ly_set *type_meta_check,  struct lyd_meta **meta)
-{
-    LY_ERR ret = LY_EVALID, rc;
+    LY_ERR ret = LY_EVALID;
     const struct lyxml_ns *ns;
     struct lys_module *mod;
+    const char *name;
+    size_t name_len;
 
-    for (unsigned int u = 0; u < attrs_data->count; ++u) {
-        struct attr_data_s *attr_data = (struct attr_data_s*)attrs_data->objs[u];
+    *meta = NULL;
 
-        if (!attr_data->prefix_len) {
+    while (xmlctx->status == LYXML_ATTRIBUTE) {
+        if (!xmlctx->prefix_len) {
             /* in XML, all attributes must be prefixed
              * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
             if (strict) {
                 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
-                       attr_data->name_len, attr_data->name);
+                       xmlctx->name_len, xmlctx->name);
+                goto cleanup;
             }
+
 skip_attr:
-            if (attr_data->dynamic) {
-                free(attr_data->value);
-                attr_data->dynamic = 0;
-            }
+            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
+            assert(xmlctx->status == LYXML_ATTR_CONTENT);
+            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
             continue;
         }
 
         /* get namespace of the attribute to find its annotation definition */
-        ns = lyxml_ns_get(xmlctx, attr_data->prefix, attr_data->prefix_len);
+        ns = lyxml_ns_get(xmlctx, xmlctx->prefix, xmlctx->prefix_len);
         if (!ns) {
             /* unknown namespace, XML error */
             LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
-                   attr_data->prefix_len, attr_data->prefix);
+                   xmlctx->prefix_len, xmlctx->prefix);
             goto cleanup;
         }
         mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
@@ -172,57 +106,65 @@
             if (strict) {
                 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE,
                        "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
-                       ns, attr_data->prefix_len, attr_data->prefix, attr_data->prefix_len ? ":" : "", attr_data->name_len,
-                       attr_data->name);
+                       ns->uri, xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "", xmlctx->name_len,
+                       xmlctx->name);
+                goto cleanup;
             }
             goto skip_attr;
         }
 
-        rc = lyd_create_meta(NULL, meta, mod, attr_data->name, attr_data->name_len, attr_data->value, attr_data->value_len,
-                             &attr_data->dynamic, lydxml_resolve_prefix, xmlctx, LYD_XML, sparent);
-        if (rc == LY_EINCOMPLETE) {
+        /* remember attr name and get its content */
+        name = xmlctx->name;
+        name_len = xmlctx->name_len;
+        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
+        assert(xmlctx->status == LYXML_ATTR_CONTENT);
+
+        /* create metadata */
+        ret = lyd_create_meta(NULL, meta, mod, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic,
+                              lydxml_resolve_prefix, xmlctx, LYD_XML, sparent);
+        if (ret == LY_EINCOMPLETE) {
             if (type_meta_check) {
                 ly_set_add(type_meta_check, meta, LY_SET_OPT_USEASLIST);
             }
-        } else if (rc) {
-            ret = rc;
+        } else if (ret) {
             goto cleanup;
         }
+
+        /* next attribute */
+        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
     }
 
     ret = LY_SUCCESS;
 
 cleanup:
-    for (unsigned int u = 0; u < attrs_data->count; ++u) {
-        if (((struct attr_data_s*)attrs_data->objs[u])->dynamic) {
-            free(((struct attr_data_s*)attrs_data->objs[u])->value);
-        }
+    if (ret) {
+        lyd_free_meta(xmlctx->ctx, *meta, 1);
+        *meta = NULL;
     }
-    ly_set_erase(attrs_data, free);
-
     return ret;
 }
 
 static LY_ERR
-lydxml_attrs(struct lyxml_context *xmlctx, struct ly_set *attrs_data, struct ly_attr **attr)
+lydxml_attrs(struct lyxml_ctx *xmlctx, struct ly_attr **attr)
 {
     LY_ERR ret = LY_SUCCESS;
     const struct lyxml_ns *ns;
     struct ly_prefix *val_prefs;
     struct ly_attr *attr2;
+    const char *name, *prefix;
+    size_t name_len, prefix_len;
 
     assert(attr);
+    *attr = NULL;
 
-    for (unsigned int u = 0; u < attrs_data->count; ++u) {
-        struct attr_data_s *attr_data = (struct attr_data_s *)attrs_data->objs[u];
-
+    while (xmlctx->status == LYXML_ATTRIBUTE) {
         ns = NULL;
-        if (attr_data->prefix_len) {
+        if (xmlctx->prefix_len) {
             /* get namespace of the attribute */
-            ns = lyxml_ns_get(xmlctx, attr_data->prefix, attr_data->prefix_len);
+            ns = lyxml_ns_get(xmlctx, xmlctx->prefix, xmlctx->prefix_len);
             if (!ns) {
                 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
-                       attr_data->prefix_len, attr_data->prefix);
+                       xmlctx->prefix_len, xmlctx->prefix);
                 ret = LY_EVALID;
                 goto cleanup;
             }
@@ -234,42 +176,46 @@
             attr2 = NULL;
         }
 
+        /* remember attr prefix, name, and get its content */
+        prefix = xmlctx->prefix;
+        prefix_len = xmlctx->prefix_len;
+        name = xmlctx->name;
+        name_len = xmlctx->name_len;
+        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
+        assert(xmlctx->status == LYXML_ATTR_CONTENT);
+
         /* get value prefixes */
-        ret = lyxml_get_prefixes(xmlctx, attr_data->value, attr_data->value_len, &val_prefs);
-        LY_CHECK_GOTO(ret, cleanup);
+        LY_CHECK_GOTO(ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs), cleanup);
 
         /* attr2 is always changed to the created attribute */
-        ret = ly_create_attr(NULL, &attr2, xmlctx->ctx, attr_data->name, attr_data->name_len, attr_data->value,
-                             attr_data->value_len, &attr_data->dynamic, LYD_XML, val_prefs, attr_data->prefix,
-                             attr_data->prefix_len, ns ? ns->uri : NULL);
+        ret = ly_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, xmlctx->value, xmlctx->value_len,
+                             &xmlctx->dynamic, LYD_XML, val_prefs, prefix, prefix_len, ns ? ns->uri : NULL);
         LY_CHECK_GOTO(ret, cleanup);
 
         if (!*attr) {
             *attr = attr2;
         }
+
+        /* next attribute */
+        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
     }
 
 cleanup:
-    for (unsigned int u = 0; u < attrs_data->count; ++u) {
-        if (((struct attr_data_s *)attrs_data->objs[u])->dynamic) {
-            free(((struct attr_data_s *)attrs_data->objs[u])->value);
-        }
+    if (ret) {
+        ly_free_attr(xmlctx->ctx, *attr, 1);
+        *attr = NULL;
     }
-    ly_set_erase(attrs_data, free);
     return ret;
 }
 
 static LY_ERR
-lydxml_check_list(struct lyxml_context *xmlctx, const struct lysc_node *list, const char **data)
+lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
 {
-    LY_ERR ret;
+    LY_ERR ret = LY_SUCCESS, r;
+    enum LYXML_PARSER_STATUS next;
     struct ly_set key_set = {0};
     const struct lysc_node *snode;
-    const char *name;
-    char *buffer = NULL, *value;
-    size_t name_len, buffer_size = 0, value_len;
-    int dynamic = 0;
-    uint32_t i, parents_count = xmlctx->elements.count;
+    uint32_t i, parents_count;
 
     assert(list && (list->nodetype == LYS_LIST));
 
@@ -279,64 +225,53 @@
         ly_set_add(&key_set, (void *)snode, LY_SET_OPT_USEASLIST);
     }
 
-    while ((xmlctx->status == LYXML_ELEMENT) && key_set.count) {
-        /* keys must be from the same module */
-        LY_CHECK_GOTO(ret = lyxml_get_element(xmlctx, data, NULL, NULL, &name, &name_len), cleanup);
-        if (!name) {
-            /* closing previous element */
-            if (xmlctx->elements.count < parents_count) {
-                /* all siblings parsed */
-                break;
-            } else {
-                continue;
-            }
-        }
-
+    while (xmlctx->status == LYXML_ELEMENT) {
         /* find key definition */
         for (i = 0; i < key_set.count; ++i) {
             snode = (const struct lysc_node *)key_set.objs[i];
-            if (!ly_strncmp(snode->name, name, name_len)) {
+            if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
                 break;
             }
         }
-        if (i == key_set.count) {
-            /* uninteresting, skip it */
-            LY_CHECK_GOTO(ret = lyxml_skip_element(xmlctx, data), cleanup);
-            continue;
-        }
+        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
 
         /* skip attributes */
         while (xmlctx->status == LYXML_ATTRIBUTE) {
-            LY_CHECK_GOTO(ret = lyxml_get_attribute(xmlctx, data, NULL, NULL, NULL, NULL), cleanup);
+            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
+            assert(xmlctx->status == LYXML_ATTR_CONTENT);
+            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
         }
 
-        /* get the value, if any */
-        if (dynamic) {
-            free(value);
-        }
-        value = "";
-        value_len = 0;
-        dynamic = 0;
-        if (xmlctx->status == LYXML_ELEM_CONTENT) {
-            ret = lyxml_get_string(xmlctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
-            if (ret && (ret != LY_EINVAL)) {
-                goto cleanup;
+        assert(xmlctx->status == LYXML_ELEM_CONTENT);
+        if (i < key_set.count) {
+            /* validate the value */
+            r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, lydxml_resolve_prefix, xmlctx, LYD_XML);
+            if (!r) {
+                /* key with a valid value, remove from the set */
+                ly_set_rm_index(&key_set, i, NULL);
             }
         }
 
-        /* validate it */
-        LY_CHECK_GOTO(ret = lys_value_validate(NULL, snode, value, value_len, lydxml_resolve_prefix, xmlctx->ctx, LYD_XML), cleanup);
+        /* parser next */
+        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
 
-        /* key with a valid value, remove from the set */
-        ly_set_rm_index(&key_set, i, NULL);
+        /* skip any children, resursively */
+        parents_count = xmlctx->elements.count;
+        while ((parents_count < xmlctx->elements.count) || (xmlctx->status == LYXML_ELEMENT)) {
+            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
+        }
+
+        /* parser next, but do not parse closing element of the list because it would remove its namespaces */
+        assert(xmlctx->status == LYXML_ELEM_CLOSE);
+        LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
+        if (next != LYXML_ELEM_CLOSE) {
+            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
+        }
     }
 
     if (key_set.count) {
-        /* some keys missing */
+        /* some keys are missing/did not validate */
         ret = LY_ENOT;
-    } else {
-        /* all keys found and validated */
-        ret = LY_SUCCESS;
     }
 
 cleanup:
@@ -347,83 +282,95 @@
 /**
  * @brief Parse XML elements as YANG data node children the specified parent node.
  *
- * @param[in] ctx XML YANG data parser context.
+ * @param[in] lydctx XML YANG data parser context.
  * @param[in] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
  * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
  * @param[out] node Resulting list of the parsed nodes.
  * @return LY_ERR value.
  */
 static LY_ERR
-lydxml_data_r(struct lyd_xml_ctx *ctx, struct lyd_node_inner *parent, const char **data, struct lyd_node **first)
+lydxml_data_r(struct lyd_xml_ctx *lydctx, struct lyd_node_inner *parent, const char **data, struct lyd_node **first)
 {
-    LY_ERR ret = LY_SUCCESS, content_ret;
-    const char *prefix, *name, *backup_data;
-    char *buffer = NULL, *value;
-    size_t prefix_len, name_len, buffer_size = 0, value_len;
-    struct ly_set attrs_data = {0};
-    struct lyxml_context backup_ctx;
+    LY_ERR ret = LY_SUCCESS;
+    enum LYXML_PARSER_STATUS prev_status;
+    const char *prefix, *name, *prev_input, *pname, *pprefix;
+    size_t prefix_len, name_len, pprefix_len, pname_len;
+    struct lyxml_ctx *xmlctx;
+    const struct ly_ctx *ctx;
     const struct lyxml_ns *ns;
     struct lyd_meta *meta = NULL, *meta2, *prev_meta;
     struct ly_attr *attr = NULL;
     const struct lysc_node *snode;
     struct lys_module *mod;
-    uint32_t prev_opts, parents_count = ctx->elements.count;
+    uint32_t prev_opts, parents_count;
     struct lyd_node *cur = NULL, *anchor;
     struct ly_prefix *val_prefs;
-    int dynamic = 0;
 
-    while (ctx->status == LYXML_ELEMENT) {
-        ret = lyxml_get_element((struct lyxml_context *)ctx, data, &prefix, &prefix_len, &name, &name_len);
-        LY_CHECK_GOTO(ret, cleanup);
-        if (!name) {
-            /* closing previous element */
-            if (ctx->elements.count < parents_count) {
-                /* all siblings parsed */
-                break;
-            } else {
-                continue;
-            }
-        }
+    xmlctx = lydctx->xmlctx;
+    ctx = xmlctx->ctx;
 
-        if (ctx->status == LYXML_ATTRIBUTE) {
-            /* first parse all attributes so we have all the namespaces available */
-            if (lydxml_attributes_parse((struct lyxml_context *)ctx, data, &attrs_data) != LY_SUCCESS) {
-                ret = LY_EVALID;
-                goto cleanup;
-            }
-        }
+    while (xmlctx->status == LYXML_ELEMENT) {
+        /* remember element prefix and name */
+        prefix = xmlctx->prefix;
+        prefix_len = xmlctx->prefix_len;
+        name = xmlctx->name;
+        name_len = xmlctx->name_len;
 
-        ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
+        /* get the element module */
+        ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
         if (!ns) {
-            LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
+            LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
+                   prefix_len, prefix);
             ret = LY_EVALID;
             goto cleanup;
         }
-        mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
-        if (!mod && (ctx->options & LYD_OPT_STRICT)) {
-            LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
+        mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
+        if (!mod && (lydctx->options & LYD_OPT_STRICT)) {
+            LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
             ret = LY_EVALID;
             goto cleanup;
         }
 
+        /* get the schema node */
         snode = NULL;
         if (mod && (!parent || parent->schema)) {
             /* leave if-feature check for validation */
             snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
-            if (!snode && (ctx->options & LYD_OPT_STRICT)) {
-                LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
-                       name_len, name, mod->name);
-                ret = LY_EVALID;
-                goto cleanup;
+            if (!snode) {
+                if (lydctx->options & LYD_OPT_STRICT) {
+                    LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
+                        name_len, name, mod->name);
+                    ret = LY_EVALID;
+                    goto cleanup;
+                } else if (!(lydctx->options & LYD_OPT_OPAQ)) {
+                    /* remember current number of parents */
+                    parents_count = xmlctx->elements.count;
+
+                    /* skip after the content */
+                    while (xmlctx->status != LYXML_ELEM_CONTENT) {
+                        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
+                    }
+                    LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
+
+                    /* skip all children elements, recursively, if any */
+                    while (parents_count < xmlctx->elements.count) {
+                        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
+                    }
+
+                    /* close element */
+                    assert(xmlctx->status == LYXML_ELEM_CLOSE);
+                    LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
+                    continue;
+                }
             }
             if (snode) {
-                if ((ctx->options & LYD_OPT_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
-                    LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LY_VCODE_INSTATE, snode->name);
+                if ((lydctx->options & LYD_OPT_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
+                    LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_INSTATE, snode->name);
                     ret = LY_EVALID;
                     goto cleanup;
                 }
                 if (snode->nodetype & (LYS_ACTION | LYS_NOTIF)) {
-                    LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Unexpected %s element \"%.*s\".",
+                    LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%.*s\".",
                            snode->nodetype == LYS_ACTION ? "RPC/action" : "notification", name_len, name);
                     ret = LY_EVALID;
                     goto cleanup;
@@ -431,108 +378,101 @@
             }
         }
 
-        /* get the value, if any */
-        value = "";
-        value_len = 0;
-        dynamic = 0;
-        content_ret = LY_SUCCESS;
-        if (ctx->status == LYXML_ELEM_CONTENT) {
-            content_ret = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
-            if (content_ret && (content_ret != LY_EINVAL)) {
-                LOGINT(ctx->ctx);
-                ret = LY_EINT;
-                goto cleanup;
-            }
-        }
+        /* parser next */
+        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
 
-        if (snode && (ctx->options & LYD_OPT_OPAQ)) {
+        if (snode && (lydctx->options & LYD_OPT_OPAQ) && (snode->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
+            /* backup parser */
+            prev_status = xmlctx->status;
+            pprefix = xmlctx->prefix;
+            pprefix_len = xmlctx->prefix_len;
+            pname = xmlctx->name;
+            pname_len = xmlctx->name_len;
+            prev_input = xmlctx->input;
+            if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
+                /* it was backed up, do not free */
+                xmlctx->dynamic = 0;
+            }
+
+            /* skip attributes */
+            while (xmlctx->status == LYXML_ATTRIBUTE) {
+                LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
+                LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
+            }
+
             if (snode->nodetype & LYD_NODE_TERM) {
                 /* value may not be valid in which case we parse it as an opaque node */
-                if (lys_value_validate(NULL, snode, value, value_len, lydxml_resolve_prefix, ctx, LYD_XML)) {
+                if (lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, lydxml_resolve_prefix, xmlctx, LYD_XML)) {
                     snode = NULL;
                 }
-            } else if (snode->nodetype == LYS_LIST) {
-                /* use backup context and data pointer */
-                backup_ctx.ctx = ctx->ctx;
-                backup_ctx.line = ctx->line;
-                backup_ctx.status = ctx->status;
-                memset(&backup_ctx.elements, 0, sizeof backup_ctx.elements);
-                for (uint32_t i = 0; i < ctx->elements.count; ++i) {
-                    ly_set_add(&backup_ctx.elements, lyxml_elem_dup(ctx->elements.objs[i]), LY_SET_OPT_USEASLIST);
-                }
-                memset(&backup_ctx.ns, 0, sizeof backup_ctx.ns);
-                for (uint32_t i = 0; i < ctx->ns.count; ++i) {
-                    ly_set_add(&backup_ctx.ns, lyxml_ns_dup(ctx->ns.objs[i]), LY_SET_OPT_USEASLIST);
-                }
-                backup_data = *data;
+            } else {
+                /* skip content */
+                LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
 
-                /* list may be missing some keys, parse as opaque if it does */
-                if (lydxml_check_list(&backup_ctx, snode, &backup_data)) {
+                if (lydxml_check_list(xmlctx, snode)) {
+                    /* invalid list, parse as opaque if it does */
                     snode = NULL;
                 }
-
-                lyxml_context_clear(&backup_ctx);
             }
+
+            /* restore parser */
+            if (xmlctx->dynamic) {
+                free((char *)xmlctx->value);
+            }
+            xmlctx->status = prev_status;
+            xmlctx->prefix = pprefix;
+            xmlctx->prefix_len = pprefix_len;
+            xmlctx->name = pname;
+            xmlctx->name_len = pname_len;
+            xmlctx->input = prev_input;
         }
 
-        /* create actual metadata so that prefixes are available in the context */
-        if (attrs_data.count) {
+        /* create metadata/attributes */
+        if (xmlctx->status == LYXML_ATTRIBUTE) {
             if (snode) {
-                ret = lydxml_metadata((struct lyxml_context *)ctx, &attrs_data, snode, ctx->options & LYD_OPT_STRICT,
-                                    &ctx->unres_meta_type, &meta);
-                LY_CHECK_GOTO(ret, cleanup);
-            } else if (ctx->options & LYD_OPT_OPAQ) {
-                ret = lydxml_attrs((struct lyxml_context *)ctx, &attrs_data, &attr);
+                ret = lydxml_metadata(xmlctx, snode, lydctx->options & LYD_OPT_STRICT, &lydctx->unres_meta_type, &meta);
                 LY_CHECK_GOTO(ret, cleanup);
             } else {
-                /* free attr data */
-                for (uint32_t u = 0; u < attrs_data.count; ++u) {
-                    if (((struct attr_data_s*)attrs_data.objs[u])->dynamic) {
-                        free(((struct attr_data_s*)attrs_data.objs[u])->value);
-                    }
-                }
-                ly_set_erase(&attrs_data, free);
+                assert(lydctx->options & LYD_OPT_OPAQ);
+                ret = lydxml_attrs(xmlctx, &attr);
+                LY_CHECK_GOTO(ret, cleanup);
             }
         }
 
+        assert(xmlctx->status == LYXML_ELEM_CONTENT);
         if (!snode) {
-            if (ctx->options & LYD_OPT_OPAQ) {
-                /* get value prefixes */
-                ret = lyxml_get_prefixes((struct lyxml_context *)ctx, value, value_len, &val_prefs);
-                LY_CHECK_GOTO(ret, cleanup);
+            assert(lydctx->options & LYD_OPT_OPAQ);
 
-                /* create node */
-                ret = lyd_create_opaq(ctx->ctx, name, name_len, value, value_len, &dynamic, LYD_XML, val_prefs, prefix,
-                                      prefix_len, ns->uri, &cur);
-                LY_CHECK_GOTO(ret, cleanup);
-
-                /* process children */
-                if (ctx->status == LYXML_ELEMENT && parents_count != ctx->elements.count) {
-                    ret = lydxml_data_r(ctx, (struct lyd_node_inner *)cur, data, lyd_node_children_p(cur));
-                    LY_CHECK_GOTO(ret, cleanup);
-                }
+            if (xmlctx->ws_only) {
+                /* ignore WS-only value */
+                xmlctx->value_len = 0;
+                val_prefs = NULL;
             } else {
-                /* skip element */
-                ret = lyxml_skip_element((struct lyxml_context *)ctx, data);
+                /* get value prefixes */
+                ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs);
                 LY_CHECK_GOTO(ret, cleanup);
-                break;
-            }
-        } else if (snode->nodetype & LYD_NODE_TERM) {
-            if (content_ret == LY_EINVAL) {
-                /* just indentation of a child element found */
-                LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX, "Child element inside a terminal node \"%s\" found.",
-                       snode->name);
-                ret = LY_EVALID;
-                goto cleanup;
             }
 
             /* create node */
-            ret = lyd_create_term(snode, value, value_len, &dynamic, lydxml_resolve_prefix, ctx, LYD_XML, &cur);
-            /* buffer spent */
-            buffer = NULL;
+            ret = lyd_create_opaq(ctx, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, LYD_XML,
+                                  val_prefs, prefix, prefix_len, ns->uri, &cur);
+            LY_CHECK_GOTO(ret, cleanup);
+
+            /* parser next */
+            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
+
+            /* process children */
+            if (xmlctx->status == LYXML_ELEMENT) {
+                ret = lydxml_data_r(lydctx, (struct lyd_node_inner *)cur, data, lyd_node_children_p(cur));
+                LY_CHECK_GOTO(ret, cleanup);
+            }
+        } else if (snode->nodetype & LYD_NODE_TERM) {
+            /* create node */
+            ret = lyd_create_term(snode, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, lydxml_resolve_prefix,
+                                  xmlctx, LYD_XML, &cur);
             if (ret == LY_EINCOMPLETE) {
-                if (!(ctx->options & LYD_OPT_PARSE_ONLY)) {
-                    ly_set_add(&ctx->unres_node_type, cur, LY_SET_OPT_USEASLIST);
+                if (!(lydctx->options & LYD_OPT_PARSE_ONLY)) {
+                    ly_set_add(&lydctx->unres_node_type, cur, LY_SET_OPT_USEASLIST);
                 }
             } else if (ret) {
                 goto cleanup;
@@ -542,33 +482,46 @@
                 /* check the key order, the anchor must always be the last child */
                 anchor = lyd_get_prev_key_anchor(parent->child, cur->schema);
                 if ((!anchor && parent->child) || (anchor && anchor->next)) {
-                    if (ctx->options & LYD_OPT_STRICT) {
-                        LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
+                    if (lydctx->options & LYD_OPT_STRICT) {
+                        LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
                                 cur->schema->name);
                         ret = LY_EVALID;
                         goto cleanup;
                     } else {
-                        LOGWRN(ctx->ctx, "Invalid position of the key \"%s\" in a list.", cur->schema->name);
+                        LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", cur->schema->name);
                     }
                 }
             }
-        } else if (snode->nodetype & LYD_NODE_INNER) {
-            if (value_len) {
-                /* value in inner node */
-                LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX, "Text value inside an inner node \"%s\" found.",
+
+            /* parser next */
+            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
+
+            /* no children expected */
+            if (xmlctx->status == LYXML_ELEMENT) {
+                LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Child element inside a terminal node \"%s\" found.",
                        snode->name);
                 ret = LY_EVALID;
                 goto cleanup;
-
+            }
+        } else if (snode->nodetype & LYD_NODE_INNER) {
+            if (!xmlctx->ws_only) {
+                /* value in inner node */
+                LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value inside an inner node \"%s\" found.",
+                       snode->name);
+                ret = LY_EVALID;
+                goto cleanup;
             }
 
             /* create node */
             ret = lyd_create_inner(snode, &cur);
             LY_CHECK_GOTO(ret, cleanup);
 
+            /* parser next */
+            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
+
             /* process children */
-            if (ctx->status == LYXML_ELEMENT && parents_count != ctx->elements.count) {
-                ret = lydxml_data_r(ctx, (struct lyd_node_inner *)cur, data, lyd_node_children_p(cur));
+            if (xmlctx->status == LYXML_ELEMENT) {
+                ret = lydxml_data_r(lydctx, (struct lyd_node_inner *)cur, data, lyd_node_children_p(cur));
                 LY_CHECK_GOTO(ret, cleanup);
             }
 
@@ -577,14 +530,14 @@
                 LY_CHECK_GOTO(ret = lyd_parse_check_keys(cur), cleanup);
             }
 
-            if (!(ctx->options & LYD_OPT_PARSE_ONLY)) {
+            if (!(lydctx->options & LYD_OPT_PARSE_ONLY)) {
                 /* new node validation, autodelete CANNOT occur, all nodes are new */
                 ret = lyd_validate_new(lyd_node_children_p(cur), snode, NULL);
                 LY_CHECK_GOTO(ret, cleanup);
 
                 /* add any missing default children */
                 ret = lyd_validate_defaults_r((struct lyd_node_inner *)cur, lyd_node_children_p(cur), NULL, NULL,
-                                              &ctx->unres_node_type, &ctx->when_check, ctx->options);
+                                              &lydctx->unres_node_type, &lydctx->when_check, lydctx->options);
                 LY_CHECK_GOTO(ret, cleanup);
             }
 
@@ -593,23 +546,24 @@
                 lyd_hash(cur);
             }
         } else if (snode->nodetype & LYD_NODE_ANY) {
-            /* just incorrect status */
-            if (ctx->status == LYXML_ELEM_CONTENT) {
-                LY_ERR r = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
-                if (r != LY_EINVAL && (r != LY_SUCCESS || value_len != 0)) {
-                    LOGINT(ctx->ctx);
-                    ret = LY_EINT;
-                    goto cleanup;
-                }
+            if (!xmlctx->ws_only) {
+                /* value in inner node */
+                LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value inside an any node \"%s\" found.",
+                       snode->name);
+                ret = LY_EVALID;
+                goto cleanup;
             }
 
+            /* parser next */
+            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
+
             /* parse any data tree with correct options */
-            prev_opts = ctx->options;
-            ctx->options &= ~LYD_OPT_STRICT;
-            ctx->options |= LYD_OPT_OPAQ;
+            prev_opts = lydctx->options;
+            lydctx->options &= ~LYD_OPT_STRICT;
+            lydctx->options |= LYD_OPT_OPAQ;
             anchor = NULL;
-            ret = lydxml_data_r(ctx, NULL, data, &anchor);
-            ctx->options = prev_opts;
+            ret = lydxml_data_r(lydctx, NULL, data, &anchor);
+            lydctx->options = prev_opts;
             LY_CHECK_GOTO(ret, cleanup);
 
             /* create node */
@@ -620,15 +574,15 @@
         /* correct flags */
         if (snode) {
             if (!(snode->nodetype & (LYS_ACTION | LYS_NOTIF)) && snode->when) {
-                if (ctx->options & LYD_OPT_TRUSTED) {
+                if (lydctx->options & LYD_OPT_TRUSTED) {
                     /* just set it to true */
                     cur->flags |= LYD_WHEN_TRUE;
                 } else {
                     /* remember we need to evaluate this node's when */
-                    ly_set_add(&ctx->when_check, cur, LY_SET_OPT_USEASLIST);
+                    ly_set_add(&lydctx->when_check, cur, LY_SET_OPT_USEASLIST);
                 }
             }
-            if (ctx->options & LYD_OPT_TRUSTED) {
+            if (lydctx->options & LYD_OPT_TRUSTED) {
                 /* node is valid */
                 cur->flags &= ~LYD_NEW;
             }
@@ -645,7 +599,7 @@
                     } else {
                         meta = meta->next;
                     }
-                    lyd_free_meta(ctx->ctx, meta2, 0);
+                    lyd_free_meta(ctx, meta2, 0);
                     break;
                 }
 
@@ -665,24 +619,20 @@
 
         /* insert */
         lyd_insert_node((struct lyd_node *)parent, first, cur);
-
         cur = NULL;
+
+        /* parser next */
+        assert(xmlctx->status == LYXML_ELEM_CLOSE);
+        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
     }
 
     /* success */
     ret = LY_SUCCESS;
 
 cleanup:
-    free(buffer);
-    lyd_free_meta(ctx->ctx, meta, 1);
-    ly_free_attr(ctx->ctx, attr, 1);
+    lyd_free_meta(ctx, meta, 1);
+    ly_free_attr(ctx, attr, 1);
     lyd_free_tree(cur);
-    for (uint32_t u = 0; u < attrs_data.count; ++u) {
-        if (((struct attr_data_s *)attrs_data.objs[u])->dynamic) {
-            free(((struct attr_data_s *)attrs_data.objs[u])->value);
-        }
-    }
-    ly_set_erase(&attrs_data, free);
     if (ret && *first) {
         lyd_free_siblings(*first);
         *first = NULL;
@@ -694,20 +644,18 @@
 lyd_parse_xml_data(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **tree)
 {
     LY_ERR ret = LY_SUCCESS;
-    struct lyd_xml_ctx xmlctx = {0};
+    struct lyd_xml_ctx lydctx = {0};
     uint32_t i = 0;
     const struct lys_module *mod;
     struct lyd_node *first, *next, **first2;
 
-    xmlctx.options = options;
-    xmlctx.ctx = ctx;
-    xmlctx.line = 1;
-
-    /* init */
+    /* init context and tree */
+    LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, data, &lydctx.xmlctx), cleanup);
+    lydctx.options = options;
     *tree = NULL;
 
     /* parse XML data */
-    ret = lydxml_data_r(&xmlctx, NULL, &data, tree);
+    ret = lydxml_data_r(&lydctx, NULL, &data, tree);
     LY_CHECK_GOTO(ret, cleanup);
 
     if (!(options & LYD_OPT_PARSE_ONLY)) {
@@ -733,13 +681,13 @@
             LY_CHECK_GOTO(ret, cleanup);
 
             /* add all top-level defaults for this module */
-            ret = lyd_validate_defaults_r(NULL, first2, NULL, mod, &xmlctx.unres_node_type, &xmlctx.when_check,
+            ret = lyd_validate_defaults_r(NULL, first2, NULL, mod, &lydctx.unres_node_type, &lydctx.when_check,
                                           options & LYD_VALOPT_MASK);
             LY_CHECK_GOTO(ret, cleanup);
 
             /* finish incompletely validated terminal values/attributes and when conditions */
-            ret = lyd_validate_unres(tree, &xmlctx.when_check, &xmlctx.unres_node_type, &xmlctx.unres_meta_type, LYD_XML,
-                                     lydxml_resolve_prefix, ctx);
+            ret = lyd_validate_unres(tree, &lydctx.when_check, &lydctx.unres_node_type, &lydctx.unres_meta_type, LYD_XML,
+                                     lydxml_resolve_prefix, lydctx.xmlctx);
             LY_CHECK_GOTO(ret, cleanup);
 
             /* perform final validation that assumes the data tree is final */
@@ -750,100 +698,13 @@
 
 cleanup:
     /* there should be no unresolved types stored */
-    assert(!(options & LYD_OPT_PARSE_ONLY) || (!xmlctx.unres_node_type.count && !xmlctx.unres_meta_type.count
-           && !xmlctx.when_check.count));
+    assert(!(options & LYD_OPT_PARSE_ONLY) || (!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count
+           && !lydctx.when_check.count));
 
-    ly_set_erase(&xmlctx.unres_node_type, NULL);
-    ly_set_erase(&xmlctx.unres_meta_type, NULL);
-    ly_set_erase(&xmlctx.when_check, NULL);
-    lyxml_context_clear((struct lyxml_context *)&xmlctx);
-    if (ret) {
-        lyd_free_all(*tree);
-        *tree = NULL;
-    }
-    return ret;
-}
-
-static LY_ERR
-lydxml_rpc(struct lyd_xml_ctx *ctx, const char **data, struct ly_attr **attr)
-{
-    const char *prefix, *name;
-    size_t prefix_len, name_len;
-    struct ly_set attrs_data = {0};
-    const struct lyxml_ns *ns;
-
-    LY_CHECK_RET(lyxml_get_element((struct lyxml_context *)ctx, data, &prefix, &prefix_len, &name, &name_len));
-    if (ly_strncmp("rpc", name, name_len)) {
-        /* not an rpc */
-        return LY_ENOT;
-    }
-
-    if (ctx->status == LYXML_ATTRIBUTE) {
-        LY_CHECK_RET(lydxml_attributes_parse((struct lyxml_context *)ctx, data, &attrs_data));
-    }
-
-    ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
-    if (!ns || strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
-        /* wrong namespace */
-        return LY_ENOT;
-    }
-
-    /* all fine, just parse the rest of the attributes */
-    if (attrs_data.count) {
-        /* TODO parse into generic attribute structure, that will also be returned */
-        //LY_CHECK_RET(lydxml_attributes(ctx, &attrs_data, NULL, meta));
-    }
-
-    return LY_SUCCESS;
-}
-
-static LY_ERR
-lydxml_action(struct lyd_xml_ctx *ctx, const char **data)
-{
-    /* TODO */
-    return LY_ENOT;
-}
-
-LY_ERR
-lyd_parse_xml_rpc(struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct ly_attr **attr,
-                  struct lyd_node **op)
-{
-    LY_ERR ret = LY_SUCCESS;
-    const char *data_p;
-    struct lyd_xml_ctx xmlctx = {0};
-
-    xmlctx.ctx = ctx;
-    xmlctx.line = 1;
-
-    /* init */
-    *tree = NULL;
-    data_p = data;
-
-    /* parse optional "rpc" element */
-    ret = lydxml_rpc(&xmlctx, &data_p, attr);
-    if (ret == LY_ENOT) {
-        /* reset data, nothing parsed */
-        data_p = data;
-    } else if (ret) {
-        goto cleanup;
-    } else {
-        /* successfully parsed */
-        data = data_p;
-
-        /* parse optional "action" element */
-        ret = lydxml_action(&xmlctx, &data_p);
-        if (ret == LY_ENOT) {
-            data_p = data;
-        } else if (ret) {
-            goto cleanup;
-        }
-    }
-
-    /* parse the rest of data tree normally */
-    ret = lydxml_data_r(&xmlctx, NULL, &data_p, tree);
-    LY_CHECK_GOTO(ret, cleanup);
-
-cleanup:
+    ly_set_erase(&lydctx.unres_node_type, NULL);
+    ly_set_erase(&lydctx.unres_meta_type, NULL);
+    ly_set_erase(&lydctx.when_check, NULL);
+    lyxml_ctx_free(lydctx.xmlctx);
     if (ret) {
         lyd_free_all(*tree);
         *tree = NULL;
diff --git a/src/parser_yang.c b/src/parser_yang.c
index f72dd2f..d831ee4 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -77,12 +77,12 @@
             !ERR && (KW != LY_STMT_SYNTAX_RIGHT_BRACE); \
             ERR = get_keyword(CTX, DATA, &KW, &WORD, &WORD_LEN))
 
-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);
-LY_ERR parse_choice(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
-LY_ERR parse_case(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
-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);
+LY_ERR parse_container(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
+LY_ERR parse_uses(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
+LY_ERR parse_choice(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
+LY_ERR parse_case(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
+LY_ERR parse_list(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
+LY_ERR parse_grouping(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_grp **groupings);
 
 /**
  * @brief Add another character to dynamic buffer, a low-level function.
@@ -139,7 +139,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-buf_store_char(struct lys_parser_ctx *ctx, const char **input, enum yang_arg arg, char **word_p,
+buf_store_char(struct lys_yang_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)
 {
     unsigned int c;
@@ -162,14 +162,14 @@
     /* check character validity */
     switch (arg) {
     case Y_IDENTIF_ARG:
-        LY_CHECK_RET(lysp_check_identifierchar(ctx, c, !(*word_len), NULL));
+        LY_CHECK_RET(lysp_check_identifierchar((struct lys_parser_ctx *)ctx, c, !(*word_len), NULL));
         break;
     case Y_PREF_IDENTIF_ARG:
-        LY_CHECK_RET(lysp_check_identifierchar(ctx, c, !(*word_len), prefix));
+        LY_CHECK_RET(lysp_check_identifierchar((struct lys_parser_ctx *)ctx, c, !(*word_len), prefix));
         break;
     case Y_STR_ARG:
     case Y_MAYBE_STR_ARG:
-        LY_CHECK_RET(lysp_check_stringchar(ctx, c));
+        LY_CHECK_RET(lysp_check_stringchar((struct lys_parser_ctx *)ctx, c));
         break;
     }
 
@@ -222,7 +222,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-skip_comment(struct lys_parser_ctx *ctx, const char **data, int comment)
+skip_comment(struct lys_yang_parser_ctx *ctx, const char **data, int comment)
 {
     /* internal statuses: 0 - comment ended,
      *                    1 - in line comment,
@@ -291,8 +291,8 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-read_qstring(struct lys_parser_ctx *ctx, const char **data, enum yang_arg arg, char **word_p, char **word_b, size_t *word_len,
-             size_t *buf_len)
+read_qstring(struct lys_yang_parser_ctx *ctx, const char **data, enum yang_arg arg, char **word_p, char **word_b,
+             size_t *word_len, size_t *buf_len)
 {
     /* string: 0 - string ended, 1 - string with ', 2 - string with ", 3 - string with " with last character \,
      *         4 - string finished, now skipping whitespaces looking for +,
@@ -510,7 +510,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-get_argument(struct lys_parser_ctx *ctx, const char **data, enum yang_arg arg,
+get_argument(struct lys_yang_parser_ctx *ctx, const char **data, enum yang_arg arg,
              uint16_t *flags, char **word_p, char **word_b, size_t *word_len)
 {
     size_t buf_len = 0;
@@ -629,7 +629,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-get_keyword(struct lys_parser_ctx *ctx, const char **data, enum ly_stmt *kw, char **word_p, size_t *word_len)
+get_keyword(struct lys_yang_parser_ctx *ctx, const char **data, enum ly_stmt *kw, char **word_p, size_t *word_len)
 {
     int prefix;
     const char *word_start;
@@ -724,7 +724,7 @@
                              LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, (*data)[-len]), LY_EVALID);
             ++ctx->indent;
             /* check character validity */
-            LY_CHECK_RET(lysp_check_identifierchar(ctx, c, *data - len == word_start ? 1 : 0, &prefix));
+            LY_CHECK_RET(lysp_check_identifierchar((struct lys_parser_ctx *)ctx, c, *data - len == word_start ? 1 : 0, &prefix));
         }
         if (!**data) {
             LOGVAL_PARSER(ctx, LY_VCODE_EOF);
@@ -761,7 +761,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_ext_substmt(struct lys_parser_ctx *ctx, const char **data, enum ly_stmt kw, char *word, size_t word_len,
+parse_ext_substmt(struct lys_yang_parser_ctx *ctx, const char **data, enum ly_stmt kw, char *word, size_t word_len,
                   struct lysp_stmt **child)
 {
     char *buf;
@@ -814,7 +814,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_ext(struct lys_parser_ctx *ctx, const char **data, const char *ext_name, int ext_name_len, LYEXT_SUBSTMT insubstmt,
+parse_ext(struct lys_yang_parser_ctx *ctx, const char **data, const char *ext_name, int ext_name_len, LYEXT_SUBSTMT insubstmt,
           uint32_t insubstmt_index, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -858,7 +858,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_text_field(struct lys_parser_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, uint32_t substmt_index,
+parse_text_field(struct lys_yang_parser_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, uint32_t substmt_index,
                  const char **value, enum yang_arg arg, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -901,7 +901,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_yangversion(struct lys_parser_ctx *ctx, const char **data, uint8_t *version, struct lysp_ext_instance **exts)
+parse_yangversion(struct lys_yang_parser_ctx *ctx, const char **data, uint8_t *version, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -952,7 +952,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_belongsto(struct lys_parser_ctx *ctx, const char **data, const char **belongsto, const char **prefix, struct lysp_ext_instance **exts)
+parse_belongsto(struct lys_yang_parser_ctx *ctx, const char **data, const char **belongsto, const char **prefix, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1003,7 +1003,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_revisiondate(struct lys_parser_ctx *ctx, const char **data, char *rev, struct lysp_ext_instance **exts)
+parse_revisiondate(struct lys_yang_parser_ctx *ctx, const char **data, char *rev, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1019,7 +1019,7 @@
     LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
 
     /* check value */
-    if (lysp_check_date(ctx, word, word_len, "revision-date")) {
+    if (lysp_check_date((struct lys_parser_ctx *)ctx, word, word_len, "revision-date")) {
         free(buf);
         return LY_EVALID;
     }
@@ -1052,7 +1052,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_include(struct lys_parser_ctx *ctx, const char *module_name, const char **data, struct lysp_include **includes)
+parse_include(struct lys_yang_parser_ctx *ctx, const char *module_name, const char **data, struct lysp_include **includes)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1109,7 +1109,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_import(struct lys_parser_ctx *ctx, const char *module_prefix, const char **data, struct lysp_import **imports)
+parse_import(struct lys_yang_parser_ctx *ctx, const char *module_prefix, const char **data, struct lysp_import **imports)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1127,7 +1127,7 @@
         switch (kw) {
         case LY_STMT_PREFIX:
             LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_PREFIX, 0, &imp->prefix, Y_IDENTIF_ARG, &imp->exts));
-            LY_CHECK_RET(lysp_check_prefix(ctx, *imports, module_prefix, &imp->prefix), LY_EVALID);
+            LY_CHECK_RET(lysp_check_prefix((struct lys_parser_ctx *)ctx, *imports, module_prefix, &imp->prefix), LY_EVALID);
             break;
         case LY_STMT_DESCRIPTION:
             PARSER_CHECK_STMTVER2_RET(ctx, "description", "import");
@@ -1166,7 +1166,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_revision(struct lys_parser_ctx *ctx, const char **data, struct lysp_revision **revs)
+parse_revision(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_revision **revs)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1180,7 +1180,7 @@
     LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
 
     /* check value */
-    if (lysp_check_date(ctx, word, word_len, "revision")) {
+    if (lysp_check_date((struct lys_parser_ctx *)ctx, word, word_len, "revision")) {
         free(buf);
         return LY_EVALID;
     }
@@ -1220,7 +1220,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_text_fields(struct lys_parser_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, const char ***texts, enum yang_arg arg,
+parse_text_fields(struct lys_yang_parser_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, const char ***texts, enum yang_arg arg,
                   struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -1260,7 +1260,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_config(struct lys_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_config(struct lys_yang_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1310,7 +1310,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_mandatory(struct lys_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_mandatory(struct lys_yang_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1360,7 +1360,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_restr(struct lys_parser_ctx *ctx, const char **data, enum ly_stmt restr_kw, struct lysp_restr *restr)
+parse_restr(struct lys_yang_parser_ctx *ctx, const char **data, enum ly_stmt restr_kw, struct lysp_restr *restr)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1370,7 +1370,7 @@
     /* get value */
     LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
 
-    YANG_CHECK_NONEMPTY(ctx, word_len, ly_stmt2str(restr_kw));
+    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) {
@@ -1408,7 +1408,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_restrs(struct lys_parser_ctx *ctx, const char **data, enum ly_stmt restr_kw, struct lysp_restr **restrs)
+parse_restrs(struct lys_yang_parser_ctx *ctx, const char **data, enum ly_stmt restr_kw, struct lysp_restr **restrs)
 {
     struct lysp_restr *restr;
 
@@ -1427,7 +1427,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_status(struct lys_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_status(struct lys_yang_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1478,7 +1478,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_when(struct lys_parser_ctx *ctx, const char **data, struct lysp_when **when_p)
+parse_when(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_when **when_p)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1496,7 +1496,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, word_len, "when");
+    CHECK_NONEMPTY(ctx, word_len, "when");
     INSERT_WORD(ctx, buf, when->cond, word, word_len);
 
     *when_p = when;
@@ -1531,7 +1531,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_any(struct lys_parser_ctx *ctx, const char **data, enum ly_stmt kw, struct lysp_node *parent, struct lysp_node **siblings)
+parse_any(struct lys_yang_parser_ctx *ctx, const char **data, enum ly_stmt kw, struct lysp_node *parent, struct lysp_node **siblings)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1600,7 +1600,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_type_enum_value_pos(struct lys_parser_ctx *ctx, const char **data, enum ly_stmt val_kw, int64_t *value, uint16_t *flags,
+parse_type_enum_value_pos(struct lys_yang_parser_ctx *ctx, const char **data, enum ly_stmt val_kw, int64_t *value, uint16_t *flags,
                           struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -1682,7 +1682,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_type_enum(struct lys_parser_ctx *ctx, const char **data, enum ly_stmt enum_kw, struct lysp_type_enum **enums)
+parse_type_enum(struct lys_yang_parser_ctx *ctx, const char **data, enum ly_stmt enum_kw, struct lysp_type_enum **enums)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1695,7 +1695,7 @@
     /* get value */
     LY_CHECK_RET(get_argument(ctx, data, enum_kw == LY_STMT_ENUM ? Y_STR_ARG : Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     if (enum_kw == LY_STMT_ENUM) {
-        ret = lysp_check_enum_name(ctx, (const char *)word, word_len);
+        ret = lysp_check_enum_name((struct lys_parser_ctx *)ctx, (const char *)word, word_len);
         LY_CHECK_ERR_RET(ret, free(buf), ret);
     } /* else nothing specific for YANG_BIT */
 
@@ -1749,7 +1749,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_type_fracdigits(struct lys_parser_ctx *ctx, const char **data, uint8_t *fracdig, struct lysp_ext_instance **exts)
+parse_type_fracdigits(struct lys_yang_parser_ctx *ctx, const char **data, uint8_t *fracdig, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word, *ptr;
@@ -1812,7 +1812,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_type_reqinstance(struct lys_parser_ctx *ctx, const char **data, uint8_t *reqinst, uint16_t *flags,
+parse_type_reqinstance(struct lys_yang_parser_ctx *ctx, const char **data, uint8_t *reqinst, uint16_t *flags,
                        struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -1862,7 +1862,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_type_pattern_modifier(struct lys_parser_ctx *ctx, const char **data, const char **pat, struct lysp_ext_instance **exts)
+parse_type_pattern_modifier(struct lys_yang_parser_ctx *ctx, const char **data, const char **pat, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1917,7 +1917,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_type_pattern(struct lys_parser_ctx *ctx, const char **data, struct lysp_restr **patterns)
+parse_type_pattern(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_restr **patterns)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -1982,7 +1982,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_type(struct lys_parser_ctx *ctx, const char **data, struct lysp_type *type)
+parse_type(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_type *type)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2077,7 +2077,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_leaf(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_leaf(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2165,7 +2165,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_maxelements(struct lys_parser_ctx *ctx, const char **data, uint32_t *max, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_maxelements(struct lys_yang_parser_ctx *ctx, const char **data, uint32_t *max, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word, *ptr;
@@ -2232,7 +2232,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_minelements(struct lys_parser_ctx *ctx, const char **data, uint32_t *min, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_minelements(struct lys_yang_parser_ctx *ctx, const char **data, uint32_t *min, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word, *ptr;
@@ -2295,7 +2295,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_orderedby(struct lys_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_orderedby(struct lys_yang_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2344,7 +2344,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_leaflist(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_leaflist(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2443,7 +2443,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_refine(struct lys_parser_ctx *ctx, const char **data, struct lysp_refine **refines)
+parse_refine(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_refine **refines)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2455,7 +2455,7 @@
 
     /* get value */
     LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
-    YANG_CHECK_NONEMPTY(ctx, word_len, "refine");
+    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,) {
@@ -2512,7 +2512,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_typedef(struct lys_parser_ctx *ctx, struct lysp_node *parent, const char **data, struct lysp_tpdf **typedefs)
+parse_typedef(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, const char **data, struct lysp_tpdf **typedefs)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2582,7 +2582,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_inout(struct lys_parser_ctx *ctx, const char **data, enum ly_stmt inout_kw, struct lysp_node *parent, struct lysp_action_inout *inout_p)
+parse_inout(struct lys_yang_parser_ctx *ctx, const char **data, enum ly_stmt inout_kw, struct lysp_node *parent, struct lysp_action_inout *inout_p)
 {
     LY_ERR ret = LY_SUCCESS;
     char *word;
@@ -2647,7 +2647,7 @@
 
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, inout_p->groupings, NULL, NULL, NULL));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, inout_p->groupings, NULL, NULL, NULL));
 
     if (!inout_p->data) {
         LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "data-def-stmt", ly_stmt2str(inout_kw));
@@ -2667,7 +2667,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_action(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_action **actions)
+parse_action(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_action **actions)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2722,7 +2722,7 @@
     LY_CHECK_RET(ret);
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, act->groupings, NULL, NULL, NULL));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, act->groupings, NULL, NULL, NULL));
 
     return ret;
 }
@@ -2737,7 +2737,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_notif(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_notif **notifs)
+parse_notif(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_notif **notifs)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2814,7 +2814,7 @@
     LY_CHECK_RET(ret);
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, notif->groupings, NULL, NULL, NULL));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, notif->groupings, NULL, NULL, NULL));
 
     return ret;
 }
@@ -2829,7 +2829,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_grouping(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_grp **groupings)
+parse_grouping(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_grp **groupings)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2907,7 +2907,7 @@
     LY_CHECK_RET(ret);
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, grp->groupings, NULL, grp->actions, grp->notifs));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, grp->groupings, NULL, grp->actions, grp->notifs));
 
     return ret;
 }
@@ -2922,7 +2922,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_augment(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_augment **augments)
+parse_augment(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_augment **augments)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -2934,7 +2934,7 @@
 
     /* get value */
     LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
-    YANG_CHECK_NONEMPTY(ctx, word_len, "augment");
+    CHECK_NONEMPTY(ctx, word_len, "augment");
     INSERT_WORD(ctx, buf, aug->nodeid, word, word_len);
     aug->nodetype = LYS_AUGMENT;
     aug->parent = parent;
@@ -3004,7 +3004,7 @@
     LY_CHECK_RET(ret);
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, NULL, NULL, aug->actions, aug->notifs));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, NULL, NULL, aug->actions, aug->notifs));
 
     return ret;
 }
@@ -3019,7 +3019,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_uses(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_uses(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3071,7 +3071,7 @@
     }
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, NULL, uses->augments, NULL, NULL));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, NULL, uses->augments, NULL, NULL));
 
     return ret;
 }
@@ -3086,7 +3086,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_case(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_case(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3167,7 +3167,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_choice(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_choice(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3264,7 +3264,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_container(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_container(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
 {
     LY_ERR ret = 0;
     char *buf, *word;
@@ -3358,7 +3358,7 @@
     }
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, cont->groupings, NULL, cont->actions, cont->notifs));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, cont->groupings, NULL, cont->actions, cont->notifs));
     return ret;
 }
 
@@ -3372,7 +3372,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_list(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_list(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3479,7 +3479,7 @@
     LY_CHECK_RET(ret);
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, list->groupings, NULL, list->actions, list->notifs));
+    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(ctx, LYVE_SEMANTICS,
@@ -3502,7 +3502,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_yinelement(struct lys_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_yinelement(struct lys_yang_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3553,7 +3553,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_argument(struct lys_parser_ctx *ctx, const char **data, const char **argument, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_argument(struct lys_yang_parser_ctx *ctx, const char **data, const char **argument, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3595,7 +3595,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_extension(struct lys_parser_ctx *ctx, const char **data, struct lysp_ext **extensions)
+parse_extension(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_ext **extensions)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3644,7 +3644,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_deviate(struct lys_parser_ctx *ctx, const char **data, struct lysp_deviate **deviates)
+parse_deviate(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_deviate **deviates)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3852,7 +3852,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_deviation(struct lys_parser_ctx *ctx, const char **data, struct lysp_deviation **deviations)
+parse_deviation(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_deviation **deviations)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3864,7 +3864,7 @@
 
     /* get value */
     LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
-    YANG_CHECK_NONEMPTY(ctx, word_len, "deviation");
+    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) {
@@ -3907,7 +3907,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_feature(struct lys_parser_ctx *ctx, const char **data, struct lysp_feature **features)
+parse_feature(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_feature **features)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -3956,7 +3956,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_identity(struct lys_parser_ctx *ctx, const char **data, struct lysp_ident **identities)
+parse_identity(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_ident **identities)
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
@@ -4013,7 +4013,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_module(struct lys_parser_ctx *ctx, const char **data, struct lysp_module *mod)
+parse_module(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_module *mod)
 {
     LY_ERR ret = 0;
     char *buf, *word;
@@ -4191,7 +4191,7 @@
 
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, mod->groupings, mod->augments, mod->rpcs, mod->notifs));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, mod->groupings, mod->augments, mod->rpcs, mod->notifs));
 
     /* mandatory substatements */
     if (!mod->mod->ns) {
@@ -4223,7 +4223,7 @@
  * @return LY_ERR values.
  */
 LY_ERR
-parse_submodule(struct lys_parser_ctx *ctx, const char **data, struct lysp_submodule *submod)
+parse_submodule(struct lys_yang_parser_ctx *ctx, const char **data, struct lysp_submodule *submod)
 {
     LY_ERR ret = 0;
     char *buf, *word;
@@ -4397,7 +4397,8 @@
 
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, submod->groupings, submod->augments, submod->rpcs, submod->notifs));
+    LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, submod->groupings, submod->augments,
+                                                 submod->rpcs, submod->notifs));
 
     /* mandatory substatements */
     if (!submod->belongsto) {
@@ -4417,7 +4418,8 @@
 }
 
 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)
+yang_parse_submodule(struct lys_yang_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;
@@ -4428,6 +4430,7 @@
     /* create context */
     *context = calloc(1, sizeof **context);
     LY_CHECK_ERR_RET(!(*context), LOGMEM(ly_ctx), LY_EMEM);
+    (*context)->format = LYS_IN_YANG;
     (*context)->ctx = ly_ctx;
     (*context)->pos_type = LY_VLOG_LINE;
     (*context)->line = 1;
@@ -4474,7 +4477,7 @@
 cleanup:
     if (ret) {
         lysp_submodule_free((*context)->ctx, mod_p);
-        lys_parser_ctx_free(*context);
+        yang_parser_ctx_free(*context);
         *context = NULL;
     }
 
@@ -4482,7 +4485,7 @@
 }
 
 LY_ERR
-yang_parse_module(struct lys_parser_ctx **context, const char *data, struct lys_module *mod)
+yang_parse_module(struct lys_yang_parser_ctx **context, const char *data, struct lys_module *mod)
 {
     LY_ERR ret = LY_SUCCESS;
     char *word;
@@ -4493,6 +4496,7 @@
     /* create context */
     *context = calloc(1, sizeof **context);
     LY_CHECK_ERR_RET(!(*context), LOGMEM(mod->ctx), LY_EMEM);
+    (*context)->format = LYS_IN_YANG;
     (*context)->ctx = mod->ctx;
     (*context)->pos_type = LY_VLOG_LINE;
     (*context)->line = 1;
@@ -4536,7 +4540,7 @@
 cleanup:
     if (ret) {
         lysp_module_free(mod_p);
-        lys_parser_ctx_free(*context);
+        yang_parser_ctx_free(*context);
         *context = NULL;
     }
 
diff --git a/src/parser_yin.c b/src/parser_yin.c
index 997be07..28016a5 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -54,7 +54,7 @@
 };
 
 enum ly_stmt
-yin_match_keyword(struct yin_parser_ctx *ctx, const char *name, size_t name_len,
+yin_match_keyword(struct lys_yin_parser_ctx *ctx, const char *name, size_t name_len,
                   const char *prefix, size_t prefix_len, enum ly_stmt parrent)
 {
     const char *start = NULL;
@@ -65,7 +65,7 @@
         return LY_STMT_NONE;
     }
 
-    ns = lyxml_ns_get(&ctx->xml_ctx, prefix, prefix_len);
+    ns = lyxml_ns_get(ctx->xmlctx, prefix, prefix_len);
     if (ns) {
         if (!IS_YIN_NS(ns->uri)) {
             return LY_STMT_EXTENSION_INSTANCE;
@@ -157,13 +157,6 @@
     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 == LY_STMT_ANYXML || kw == LY_STMT_ANYDATA || kw == LY_STMT_LEAF || kw == LY_STMT_LEAF_LIST || \
                           kw == LY_STMT_TYPEDEF || kw == LY_STMT_USES || kw == LY_STMT_LIST || kw == LY_STMT_NOTIFICATION || \
                           kw == LY_STMT_GROUPING || kw == LY_STMT_CONTAINER || kw == LY_STMT_CASE || kw == LY_STMT_CHOICE || \
@@ -200,7 +193,7 @@
  * @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,
+subelems_allocator(struct lys_yin_parser_ctx *ctx, size_t count, struct lysp_node *parent,
                    struct yin_subelement **result, ...)
 {
     va_list ap;
@@ -253,55 +246,26 @@
 
 mem_err:
     subelems_deallocator(count, *result);
-    LOGMEM(ctx->xml_ctx.ctx);
+    LOGMEM(ctx->xmlctx->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)
+yin_validate_value(struct lys_yin_parser_ctx *ctx, enum yang_arg val_type)
 {
     int prefix = 0;
     unsigned int c;
-    size_t utf8_char_len;
-    size_t already_read = 0;
-    while (already_read < len) {
+    size_t utf8_char_len, already_read = 0;
+    const char *val;
+
+    assert((ctx->xmlctx->status == LYXML_ELEM_CONTENT) || (ctx->xmlctx->status == LYXML_ATTR_CONTENT));
+
+    val = ctx->xmlctx->value;
+    while (already_read < ctx->xmlctx->value_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);
+        LY_CHECK_ERR_RET(already_read > ctx->xmlctx->value_len, LOGINT(ctx->xmlctx->ctx), LY_EINT);
 
         switch (val_type) {
         case Y_IDENTIF_ARG:
@@ -321,10 +285,9 @@
 }
 
 /**
- * @brief Parse yin attribute.
+ * @brief Parse yin attributes.
  *
  * @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.
@@ -334,38 +297,48 @@
  * @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 ly_stmt current_element)
+yin_parse_attribute(struct lys_yin_parser_ctx *ctx, enum yin_argument arg_type, const char **arg_val, enum yang_arg val_type,
+                    enum ly_stmt 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) {
+    while (ctx->xmlctx->status == LYXML_ATTRIBUTE) {
         /* 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 (!ctx->xmlctx->prefix) {
+            arg = yin_match_argument_name(ctx->xmlctx->name, ctx->xmlctx->name_len);
             if (arg == YIN_ARG_NONE) {
-                continue;
+                /* skip it */
+                LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
             } 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;
+
+                /* go to value */
+                LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+                LY_CHECK_RET(yin_validate_value(ctx, val_type));
+                *arg_val = INSERT_STRING(ctx->xmlctx->ctx, ctx->xmlctx->value, ctx->xmlctx->value_len, ctx->xmlctx->dynamic);
                 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));
+                LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_UNEXP_ATTR, ctx->xmlctx->name_len,
+                              ctx->xmlctx->name, ly_stmt2str(current_element));
                 return LY_EVALID;
             }
+        } else {
+            /* skip it */
+            LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
         }
+
+        /* next attribute */
+        LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
     }
 
     /* 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));
+        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;
     }
 
@@ -403,7 +376,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_check_subelem_mandatory_constraint(struct yin_parser_ctx *ctx, struct yin_subelement *subelem_info,
+yin_check_subelem_mandatory_constraint(struct lys_yin_parser_ctx *ctx, struct yin_subelement *subelem_info,
                                        signed char subelem_info_size, enum ly_stmt current_element)
 {
     for (signed char i = 0; i < subelem_info_size; ++i) {
@@ -430,7 +403,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_check_subelem_first_constraint(struct yin_parser_ctx *ctx, struct yin_subelement *subelem_info,
+yin_check_subelem_first_constraint(struct lys_yin_parser_ctx *ctx, struct yin_subelement *subelem_info,
                                    signed char subelem_info_size, enum ly_stmt current_element,
                                    struct yin_subelement *exp_first)
 {
@@ -450,45 +423,38 @@
  * 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 ly_stmt kw,
-                         const char **value, enum yin_argument arg_type, enum yang_arg arg_val_type, struct lysp_ext_instance **exts)
+yin_parse_simple_element(struct lys_yin_parser_ctx *ctx, enum ly_stmt 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));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, arg_type, value, arg_val_type, kw));
     struct yin_subelement subelems[1] = {
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                         };
 
-    return yin_parse_content(ctx, subelems, 1, data, kw, NULL, exts);
+    return yin_parse_content(ctx, subelems, 1, 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 ly_stmt kw,
-               struct lysp_type *type)
+yin_parse_path(struct lys_yin_parser_ctx *ctx, enum ly_stmt 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));
+    LY_CHECK_RET(yin_parse_simple_element(ctx, kw, &type->path, YIN_ARG_VALUE, Y_STR_ARG, &type->exts));
     type->flags |= LYS_SET_PATH;
 
     return LY_SUCCESS;
@@ -498,32 +464,29 @@
  * @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)
+yin_parse_pattern(struct lys_yin_parser_ctx *ctx, 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, LY_STMT_PATTERN));
+    LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, type->patterns, restr, LY_EMEM);
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, &real_value, Y_STR_ARG, LY_STMT_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);
+    LY_CHECK_ERR_RET(!saved_value, LOGMEM(ctx->xmlctx->ctx), LY_EMEM);
     memmove(saved_value + 1, real_value, len);
-    FREE_STRING(ctx->xml_ctx.ctx, real_value);
+    FREE_STRING(ctx->xmlctx->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);
+    restr->arg = lydict_insert_zc(ctx->xmlctx->ctx, saved_value);
+    LY_CHECK_ERR_RET(!restr->arg, LOGMEM(ctx->xmlctx->ctx), LY_EMEM);
     type->flags |= LYS_SET_PATTERN;
 
     struct yin_subelement subelems[6] = {
@@ -534,32 +497,29 @@
                                             {LY_STMT_REFERENCE, &restr->ref, YIN_SUBELEM_UNIQUE},
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                         };
-    return yin_parse_content(ctx, subelems, 6, data, LY_STMT_PATTERN, NULL, &restr->exts);
+    return yin_parse_content(ctx, subelems, 6, LY_STMT_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)
+yin_parse_fracdigits(struct lys_yin_parser_ctx *ctx, 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, LY_STMT_FRACTION_DIGITS));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_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);
+        FREE_STRING(ctx->xmlctx->ctx, temp_val);
         return LY_EVALID;
     }
 
@@ -567,43 +527,41 @@
     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);
+        FREE_STRING(ctx->xmlctx->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);
+        FREE_STRING(ctx->xmlctx->ctx, temp_val);
         return LY_EVALID;
     }
-    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+    FREE_STRING(ctx->xmlctx->ctx, temp_val);
     type->fraction_digits = num;
     type->flags |= LYS_SET_FRDIGITS;
     struct yin_subelement subelems[1] = {
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                         };
-    return yin_parse_content(ctx, subelems, 1, data, LY_STMT_FRACTION_DIGITS, NULL, &type->exts);
+    return yin_parse_content(ctx, subelems, 1, LY_STMT_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)
+yin_parse_enum(struct lys_yin_parser_ctx *ctx, struct lysp_type *type)
 {
     struct lysp_type_enum *en;
 
-    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, type->enums, en, LY_EMEM);
+    LY_ARRAY_NEW_RET(ctx->xmlctx->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_STR_ARG, LY_STMT_ENUM));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &en->name, Y_STR_ARG, LY_STMT_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_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] = {
@@ -614,28 +572,25 @@
                                             {LY_STMT_VALUE, en, YIN_SUBELEM_UNIQUE},
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                         };
-    return yin_parse_content(ctx, subelems, 6, data, LY_STMT_ENUM, NULL, &en->exts);
+    return yin_parse_content(ctx, subelems, 6, LY_STMT_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)
+yin_parse_bit(struct lys_yin_parser_ctx *ctx, struct lysp_type *type)
 {
     struct lysp_type_enum *en;
 
-    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, type->bits, en, LY_EMEM);
+    LY_ARRAY_NEW_RET(ctx->xmlctx->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, LY_STMT_BIT));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &en->name, Y_IDENTIF_ARG, LY_STMT_BIT));
     CHECK_UNIQUENESS((struct lys_parser_ctx *)ctx, type->enums, name, "bit", en->name);
 
     struct yin_subelement subelems[6] = {
@@ -646,7 +601,7 @@
                                             {LY_STMT_STATUS, &en->flags, YIN_SUBELEM_UNIQUE},
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                         };
-    return yin_parse_content(ctx, subelems, 6, data, LY_STMT_BIT, NULL, &en->exts);
+    return yin_parse_content(ctx, subelems, 6, LY_STMT_BIT, NULL, &en->exts);
 }
 
 /**
@@ -654,55 +609,50 @@
  * 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 ly_stmt kw,
-                          const char ***values, enum yin_argument arg_type, enum yang_arg arg_val_type, struct lysp_ext_instance **exts)
+yin_parse_simple_elements(struct lys_yin_parser_ctx *ctx, enum ly_stmt 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);
+    LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *values, value, LY_EMEM);
     uint32_t index = LY_ARRAY_SIZE(*values) - 1;
     struct yin_subelement subelems[1] = {
                                             {LY_STMT_EXTENSION_INSTANCE, &index, 0}
                                         };
 
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, arg_type, value, arg_val_type, kw));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, arg_type, value, arg_val_type, kw));
 
-    return yin_parse_content(ctx, subelems, 1, data, kw, NULL, exts);
+    return yin_parse_content(ctx, subelems, 1, 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 ly_stmt kw,
-                      struct yin_subelement *subinfo, enum yin_argument arg_type, enum yang_arg arg_val_type, struct lysp_ext_instance **exts)
+yin_parse_simple_elem(struct lys_yin_parser_ctx *ctx, enum ly_stmt 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,
+        LY_CHECK_RET(yin_parse_simple_element(ctx, 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,
+        LY_CHECK_RET(yin_parse_simple_elements(ctx, kw, (const char ***)subinfo->dest,
                                                arg_type, arg_val_type, exts));
     }
 
@@ -713,30 +663,26 @@
  * @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 ly_stmt parent,
-               void *dest, struct lysp_ext_instance **exts)
+yin_parse_base(struct lys_yin_parser_ctx *ctx, enum ly_stmt parent, void *dest, struct lysp_ext_instance **exts)
 {
     struct lysp_type *type = NULL;
 
     if (parent == LY_STMT_TYPE) {
         type = (struct lysp_type *)dest;
-        LY_CHECK_RET(yin_parse_simple_elements(ctx, attrs, data, LY_STMT_BASE, &type->bases, YIN_ARG_NAME,
+        LY_CHECK_RET(yin_parse_simple_elements(ctx, LY_STMT_BASE, &type->bases, YIN_ARG_NAME,
                                                Y_PREF_IDENTIF_ARG, exts));
         type->flags |= LYS_SET_BASE;
     } else if (parent == LY_STMT_IDENTITY) {
-        LY_CHECK_RET(yin_parse_simple_elements(ctx, attrs, data, LY_STMT_BASE, (const char ***)dest,
+        LY_CHECK_RET(yin_parse_simple_elements(ctx, LY_STMT_BASE, (const char ***)dest,
                                                YIN_ARG_NAME, Y_PREF_IDENTIF_ARG, exts));
     } else {
-        LOGINT(ctx->xml_ctx.ctx);
+        LOGINT(ctx->xmlctx->ctx);
         return LY_EINT;
     }
 
@@ -747,15 +693,11 @@
  * @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.
- *
+ * @param[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)
+yin_pasrse_reqinstance(struct lys_yin_parser_ctx *ctx, struct lysp_type *type)
 {
     const char *temp_val = NULL;
     struct yin_subelement subelems[1] = {
@@ -763,34 +705,32 @@
                                         };
 
     type->flags |= LYS_SET_REQINST;
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_REQUIRE_INSTANCE));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_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);
+        FREE_STRING(ctx->xmlctx->ctx, temp_val);
         return LY_EVALID;
     }
-    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+    FREE_STRING(ctx->xmlctx->ctx, temp_val);
 
-    return yin_parse_content(ctx, subelems, 1, data, LY_STMT_REQUIRE_INSTANCE, NULL, &type->exts);
+    return yin_parse_content(ctx, subelems, 1, LY_STMT_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)
+yin_parse_modifier(struct lys_yin_parser_ctx *ctx, const char **pat, struct lysp_ext_instance **exts)
 {
     assert(**pat == 0x06);
     const char *temp_val;
@@ -799,40 +739,38 @@
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                         };
 
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_MODIFIER));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_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);
+        FREE_STRING(ctx->xmlctx->ctx, temp_val);
         return LY_EVALID;
     }
-    lydict_remove(ctx->xml_ctx.ctx, temp_val);
+    lydict_remove(ctx->xmlctx->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);
+    LY_CHECK_ERR_RET(!modified_val, LOGMEM(ctx->xmlctx->ctx), LY_EMEM);
     strcpy(modified_val, *pat);
-    lydict_remove(ctx->xml_ctx.ctx, *pat);
+    lydict_remove(ctx->xmlctx->ctx, *pat);
 
     /* modify the new value */
     modified_val[0] = 0x15;
-    *pat = lydict_insert_zc(ctx->xml_ctx.ctx, modified_val);
+    *pat = lydict_insert_zc(ctx->xmlctx->ctx, modified_val);
 
-    return yin_parse_content(ctx, subelems, 1, data, LY_STMT_MODIFIER, NULL, exts);
+    return yin_parse_content(ctx, subelems, 1, LY_STMT_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 LY_STMT_MUST, LY_STMT_LENGTH or LY_STMT_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 ly_stmt restr_kw, struct lysp_restr *restr)
+yin_parse_restriction(struct lys_yin_parser_ctx *ctx, enum ly_stmt restr_kw, struct lysp_restr *restr)
 {
     assert(restr_kw == LY_STMT_MUST || restr_kw == LY_STMT_LENGTH || restr_kw == LY_STMT_RANGE);
     struct yin_subelement subelems[5] = {
@@ -844,28 +782,27 @@
                                         };
     /* argument of must is called condition, but argument of length and range is called value */
     enum yin_argument arg_type = (restr_kw == LY_STMT_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);
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, arg_type, &restr->arg, Y_STR_ARG, restr_kw));
+
+    return yin_parse_content(ctx, subelems, 5, 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)
+yin_parse_range(struct lys_yin_parser_ctx *ctx, 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, LY_STMT_RANGE, type->range));
+    LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx->xmlctx->ctx), LY_EMEM);
+    LY_CHECK_RET(yin_parse_restriction(ctx, LY_STMT_RANGE, type->range));
     type->flags |=  LYS_SET_RANGE;
 
     return LY_SUCCESS;
@@ -875,19 +812,16 @@
  * @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)
+yin_parse_length(struct lys_yin_parser_ctx *ctx, 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, LY_STMT_LENGTH, type->length));
+    LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx->xmlctx->ctx), LY_EMEM);
+    LY_CHECK_RET(yin_parse_restriction(ctx, LY_STMT_LENGTH, type->length));
     type->flags |= LYS_SET_LENGTH;
 
     return LY_SUCCESS;
@@ -897,35 +831,30 @@
  * @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)
+yin_parse_must(struct lys_yin_parser_ctx *ctx, 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, LY_STMT_MUST, restr);
+    LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *restrs, restr, LY_EMEM);
+    return yin_parse_restriction(ctx, LY_STMT_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 LY_STMT_POSITION or LY_STMT_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 ly_stmt kw, struct lysp_type_enum *enm)
+yin_parse_value_pos(struct lys_yin_parser_ctx *ctx, enum ly_stmt kw, struct lysp_type_enum *enm)
 {
     assert(kw == LY_STMT_POSITION || kw == LY_STMT_VALUE);
     const char *temp_val = NULL;
@@ -937,7 +866,8 @@
     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));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, 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 == LY_STMT_POSITION) && !strcmp(temp_val, "-0"))) {
         LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", ly_stmt2str(kw));
@@ -974,42 +904,40 @@
     } else {
         enm->value = unum;
     }
-    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+    FREE_STRING(ctx->xmlctx->ctx, temp_val);
 
     /* parse subelements */
     struct yin_subelement subelems[1] = {
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                         };
-    return yin_parse_content(ctx, subelems, 1, data, kw, NULL, &enm->exts);
+    return yin_parse_content(ctx, subelems, 1, kw, NULL, &enm->exts);
 
 error:
-        FREE_STRING(ctx->xml_ctx.ctx, temp_val);
-        return LY_EVALID;
+    FREE_STRING(ctx->xmlctx->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)
+yin_parse_belongs_to(struct lys_yin_parser_ctx *ctx, struct lysp_submodule *submod, struct lysp_ext_instance **exts)
 {
     struct yin_subelement subelems[2] = {
                                             {LY_STMT_PREFIX, &submod->prefix, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE},
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                         };
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_MODULE, &submod->belongsto, Y_IDENTIF_ARG, LY_STMT_BELONGS_TO));
 
-    return yin_parse_content(ctx, subelems, 2, data, LY_STMT_BELONGS_TO, NULL, exts);
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_MODULE, &submod->belongsto, Y_IDENTIF_ARG, LY_STMT_BELONGS_TO));
+
+    return yin_parse_content(ctx, subelems, 2, LY_STMT_BELONGS_TO, NULL, exts);
 }
 
 /**
@@ -1017,8 +945,6 @@
  * 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 LY_STMT_ORGANIZATION or LY_STMT_CONTACT or LY_STMT_DESCRIPTION or LY_STMT_REFERENCE.
  * @param[out] value Where the content of meta element should be stored.
  * @param[in,out] exts Extension instances to add to.
@@ -1026,8 +952,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_meta(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
-                       enum ly_stmt elem_type, const char **value, struct lysp_ext_instance **exts)
+yin_parse_meta(struct lys_yin_parser_ctx *ctx, enum ly_stmt elem_type, const char **value, struct lysp_ext_instance **exts)
 {
     assert(elem_type == LY_STMT_ORGANIZATION || elem_type == LY_STMT_CONTACT || elem_type == LY_STMT_DESCRIPTION || elem_type == LY_STMT_REFERENCE);
 
@@ -1036,26 +961,24 @@
                                             {LY_STMT_ARG_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));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NONE, NULL, Y_MAYBE_STR_ARG, elem_type));
 
     /* parse content */
-    return yin_parse_content(ctx, subelems, 2, data, elem_type, NULL, exts);
+    return yin_parse_content(ctx, subelems, 2, 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)
+yin_parse_err_msg(struct lys_yin_parser_ctx *ctx, const char **value, struct lysp_ext_instance **exts)
 {
     struct yin_subelement subelems[2] = {
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
@@ -1063,30 +986,28 @@
                                         };
 
     /* check attributes */
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NONE, NULL, Y_MAYBE_STR_ARG, LY_STMT_ERROR_MESSAGE));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NONE, NULL, Y_MAYBE_STR_ARG, LY_STMT_ERROR_MESSAGE));
 
-    return yin_parse_content(ctx, subelems, 2, data, LY_STMT_ERROR_MESSAGE, NULL, exts);
+    return yin_parse_content(ctx, subelems, 2, LY_STMT_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 ly_stmt parent, struct yin_subelement *subinfo)
+yin_parse_type(struct lys_yin_parser_ctx *ctx, enum ly_stmt parent, struct yin_subelement *subinfo)
 {
     struct lysp_type *type = NULL;
     if (parent == LY_STMT_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);
+        LY_CHECK_ERR_RET(!(*(struct lysp_type **)subinfo->dest), LOGMEM(ctx->xmlctx->ctx), LY_EMEM);
         type = *((struct lysp_type **)subinfo->dest);
     } else  {
         type = (struct lysp_type *)subinfo->dest;
@@ -1094,7 +1015,7 @@
     /* type as child of another type */
     if (parent == LY_STMT_TYPE) {
         struct lysp_type *nested_type = NULL;
-        LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, type->types, nested_type, LY_EMEM);
+        LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, type->types, nested_type, LY_EMEM);
         type->flags |= LYS_SET_TYPE;
         type = nested_type;
     }
@@ -1111,16 +1032,16 @@
                                             {LY_STMT_TYPE, type},
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
                                         };
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &type->name, Y_PREF_IDENTIF_ARG, LY_STMT_TYPE));
-    return yin_parse_content(ctx, subelems, 11, data, LY_STMT_TYPE, NULL, &type->exts);
+
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &type->name, Y_PREF_IDENTIF_ARG, LY_STMT_TYPE));
+    return yin_parse_content(ctx, subelems, 11, LY_STMT_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.
@@ -1128,8 +1049,7 @@
  * @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)
+yin_parse_maxelements(struct lys_yin_parser_ctx *ctx, uint32_t *max, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     const char *temp_val = NULL;
     char *ptr;
@@ -1139,10 +1059,11 @@
                                         };
 
     *flags |= LYS_SET_MAX;
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_MAX_ELEMENTS));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_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);
+        FREE_STRING(ctx->xmlctx->ctx, temp_val);
         return LY_EVALID;
     }
 
@@ -1151,26 +1072,24 @@
         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);
+            FREE_STRING(ctx->xmlctx->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);
+            FREE_STRING(ctx->xmlctx->ctx, temp_val);
             return LY_EVALID;
         }
         *max = num;
     }
-    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
-    return yin_parse_content(ctx, subelems, 1, data, LY_STMT_MAX_ELEMENTS, NULL, exts);
+    FREE_STRING(ctx->xmlctx->ctx, temp_val);
+    return yin_parse_content(ctx, subelems, 1, LY_STMT_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.
@@ -1178,8 +1097,7 @@
  * @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)
+yin_parse_minelements(struct lys_yin_parser_ctx *ctx, uint32_t *min, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     const char *temp_val = NULL;
     char *ptr;
@@ -1189,11 +1107,12 @@
                                         };
 
     *flags |= LYS_SET_MIN;
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_MIN_ELEMENTS));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_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);
+        FREE_STRING(ctx->xmlctx->ctx, temp_val);
         return LY_EVALID;
     }
 
@@ -1201,25 +1120,23 @@
     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);
+        FREE_STRING(ctx->xmlctx->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);
+        FREE_STRING(ctx->xmlctx->ctx, temp_val);
         return LY_EVALID;
     }
     *min = num;
-    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
-    return yin_parse_content(ctx, subelems, 1, data, LY_STMT_MIN_ELEMENTS, NULL, exts);
+    FREE_STRING(ctx->xmlctx->ctx, temp_val);
+    return yin_parse_content(ctx, subelems, 1, LY_STMT_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.
@@ -1227,8 +1144,7 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_minmax(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
-                 enum ly_stmt parent, enum ly_stmt current, void *dest)
+yin_parse_minmax(struct lys_yin_parser_ctx *ctx, enum ly_stmt parent, enum ly_stmt current, void *dest)
 {
     assert(current == LY_STMT_MAX_ELEMENTS || current == LY_STMT_MIN_ELEMENTS);
     assert(parent == LY_STMT_LEAF_LIST || parent == LY_STMT_REFINE || parent == LY_STMT_LIST || parent == LY_STMT_DEVIATE);
@@ -1255,9 +1171,9 @@
     }
 
     if (current == LY_STMT_MAX_ELEMENTS) {
-        LY_CHECK_RET(yin_parse_maxelements(ctx, attrs, data, lim, flags, exts));
+        LY_CHECK_RET(yin_parse_maxelements(ctx, lim, flags, exts));
     } else {
-        LY_CHECK_RET(yin_parse_minelements(ctx, attrs, data, lim, flags, exts));
+        LY_CHECK_RET(yin_parse_minelements(ctx, lim, flags, exts));
     }
 
     return LY_SUCCESS;
@@ -1267,23 +1183,21 @@
  * @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)
+yin_parse_orderedby(struct lys_yin_parser_ctx *ctx, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     const char *temp_val;
     struct yin_subelement subelems[1] = {
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
                                         };
 
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_ORDERED_BY));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_ORDERED_BY));
     if (strcmp(temp_val, "system") == 0) {
         *flags |= LYS_ORDBY_SYSTEM;
     } else if (strcmp(temp_val, "user") == 0) {
@@ -1291,38 +1205,36 @@
     } 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);
+        FREE_STRING(ctx->xmlctx->ctx, temp_val);
         return LY_EVALID;
     }
-    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+    FREE_STRING(ctx->xmlctx->ctx, temp_val);
 
-    return yin_parse_content(ctx, subelems, 1, data, LY_STMT_ORDERED_BY, NULL, exts);
+    return yin_parse_content(ctx, subelems, 1, LY_STMT_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 LY_STMT_ANYDATA or LY_STMT_ANYXML
  * @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 ly_stmt any_kw, struct tree_node_meta *node_meta)
+yin_parse_any(struct lys_yin_parser_ctx *ctx, enum ly_stmt 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, LY_EMEM);
+    LY_LIST_NEW_RET(ctx->xmlctx->ctx, node_meta->nodes, any, next, LY_EMEM);
     any->nodetype = (any_kw == LY_STMT_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));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &any->name, Y_IDENTIF_ARG, any_kw));
 
     struct yin_subelement subelems[9] = {
                                             {LY_STMT_CONFIG, &any->flags, YIN_SUBELEM_UNIQUE},
@@ -1335,32 +1247,30 @@
                                             {LY_STMT_WHEN, &any->when, YIN_SUBELEM_UNIQUE},
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
                                         };
-    return yin_parse_content(ctx, subelems, 9, data, any_kw, NULL, &any->exts);
+    return yin_parse_content(ctx, subelems, 9, 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)
+yin_parse_leaf(struct lys_yin_parser_ctx *ctx, 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, LY_EMEM);
+    LY_LIST_NEW_RET(ctx->xmlctx->ctx, node_meta->nodes, leaf, next, LY_EMEM);
     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, LY_STMT_LEAF));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &leaf->name, Y_IDENTIF_ARG, LY_STMT_LEAF));
 
     /* parse content */
     struct yin_subelement subelems[12] = {
@@ -1377,32 +1287,30 @@
                                             {LY_STMT_WHEN, &leaf->when, YIN_SUBELEM_UNIQUE},
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
                                          };
-    return yin_parse_content(ctx, subelems, 12, data, LY_STMT_LEAF, NULL, &leaf->exts);
+    return yin_parse_content(ctx, subelems, 12, LY_STMT_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)
+yin_parse_leaflist(struct lys_yin_parser_ctx *ctx, struct tree_node_meta *node_meta)
 {
     struct lysp_node_leaflist *llist;
 
-    LY_LIST_NEW_RET(ctx->xml_ctx.ctx, node_meta->nodes, llist, next, LY_EMEM);
+    LY_LIST_NEW_RET(ctx->xmlctx->ctx, node_meta->nodes, llist, next, LY_EMEM);
 
     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, LY_STMT_LEAF_LIST));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &llist->name, Y_IDENTIF_ARG, LY_STMT_LEAF_LIST));
 
     /* parse content */
     struct yin_subelement subelems[14] = {
@@ -1421,7 +1329,7 @@
                                             {LY_STMT_WHEN, &llist->when, YIN_SUBELEM_UNIQUE},
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
                                         };
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, 14, data, LY_STMT_LEAF_LIST, NULL, &llist->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, 14, LY_STMT_LEAF_LIST, NULL, &llist->exts));
 
     /* check invalid combination of subelements */
     if ((llist->min) && (llist->dflts)) {
@@ -1440,22 +1348,20 @@
  * @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)
+yin_parse_typedef(struct lys_yin_parser_ctx *ctx, 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);
+    LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *tpdfs, tpdf, LY_EMEM);
 
     /* parse argument */
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &tpdf->name, Y_IDENTIF_ARG, LY_STMT_TYPEDEF));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &tpdf->name, Y_IDENTIF_ARG, LY_STMT_TYPEDEF));
 
     /* parse content */
     struct yin_subelement subelems[7] = {
@@ -1467,7 +1373,7 @@
                                             {LY_STMT_UNITS, &tpdf->units, YIN_SUBELEM_UNIQUE},
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
                                         };
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, 7, data, LY_STMT_TYPEDEF, NULL, &tpdf->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, 7, LY_STMT_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))) {
@@ -1481,24 +1387,22 @@
  * @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)
+yin_parse_refine(struct lys_yin_parser_ctx *ctx, struct lysp_refine **refines)
 {
     struct lysp_refine *rf;
 
     /* allocate new refine */
-    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *refines, rf, LY_EMEM);
+    LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *refines, rf, LY_EMEM);
 
     /* parse attribute */
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_TARGET_NODE, &rf->nodeid, Y_STR_ARG, LY_STMT_REFINE));
-    YANG_CHECK_NONEMPTY((struct lys_parser_ctx *)ctx, strlen(rf->nodeid), "refine");
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_TARGET_NODE, &rf->nodeid, Y_STR_ARG, LY_STMT_REFINE));
+    CHECK_NONEMPTY(ctx, strlen(rf->nodeid), "refine");
 
     /* parse content */
     struct yin_subelement subelems[11] = {
@@ -1514,32 +1418,30 @@
                                             {LY_STMT_REFERENCE, &rf->ref, YIN_SUBELEM_UNIQUE},
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
                                         };
-    return yin_parse_content(ctx, subelems, 11, data, LY_STMT_REFINE, NULL, &rf->exts);
+    return yin_parse_content(ctx, subelems, 11, LY_STMT_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)
+yin_parse_uses(struct lys_yin_parser_ctx *ctx, 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, LY_EMEM);
+    LY_LIST_NEW_RET(ctx->xmlctx->ctx, node_meta->nodes, uses, next, LY_EMEM);
     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, LY_STMT_USES));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &uses->name, Y_PREF_IDENTIF_ARG, LY_STMT_USES));
 
     /* parse content */
     struct tree_node_meta augments = {(struct lysp_node *)uses, (struct lysp_node **)&uses->augments};
@@ -1553,7 +1455,7 @@
                                             {LY_STMT_WHEN, &uses->when, YIN_SUBELEM_UNIQUE},
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
                                         };
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, 8, data, LY_STMT_USES, NULL, &uses->exts));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, 8, LY_STMT_USES, NULL, &uses->exts));
     LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, NULL, uses->augments, NULL, NULL));
 
     return LY_SUCCESS;
@@ -1563,31 +1465,29 @@
  * @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)
+yin_parse_revision(struct lys_yin_parser_ctx *ctx, 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);
+    LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *revs, rev, LY_EMEM);
 
     /* parse argument */
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_DATE, &temp_date, Y_STR_ARG, LY_STMT_REVISION));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_DATE, &temp_date, Y_STR_ARG, LY_STMT_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);
+        FREE_STRING(ctx->xmlctx->ctx, temp_date);
         return LY_EVALID;
     }
     strcpy(rev->date, temp_date);
-    FREE_STRING(ctx->xml_ctx.ctx, temp_date);
+    FREE_STRING(ctx->xmlctx->ctx, temp_date);
 
     /* parse content */
     struct yin_subelement subelems[3] = {
@@ -1595,34 +1495,32 @@
                                             {LY_STMT_REFERENCE, &rev->ref, YIN_SUBELEM_UNIQUE},
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
                                         };
-    return yin_parse_content(ctx, subelems, 3, data, LY_STMT_REVISION, NULL, &rev->exts);
+    return yin_parse_content(ctx, subelems, 3, LY_STMT_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)
+yin_parse_include(struct lys_yin_parser_ctx *ctx, 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);
+    LY_ARRAY_NEW_RET(ctx->xmlctx->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, LY_STMT_INCLUDE));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_MODULE, &inc->name, Y_IDENTIF_ARG, LY_STMT_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)) {
+    if (!strcmp(inc_meta->name, inc->name) || ly_ctx_get_module_latest(ctx->xmlctx->ctx, inc->name)) {
         LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_NAME_COL, inc->name);
         return LY_EVALID;
     }
@@ -1634,60 +1532,56 @@
                                             {LY_STMT_REVISION_DATE, &inc->rev, YIN_SUBELEM_UNIQUE},
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
                                         };
-    return yin_parse_content(ctx, subelems, 4, data, LY_STMT_INCLUDE, NULL, &inc->exts);
+    return yin_parse_content(ctx, subelems, 4, LY_STMT_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)
+yin_parse_revision_date(struct lys_yin_parser_ctx *ctx, char *rev, struct lysp_ext_instance **exts)
 {
     const char *temp_rev;
     struct yin_subelement subelems[1] = {
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                         };
 
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_DATE, &temp_rev, Y_STR_ARG, LY_STMT_REVISION_DATE));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_DATE, &temp_rev, Y_STR_ARG, LY_STMT_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);
+                     FREE_STRING(ctx->xmlctx->ctx, temp_rev), LY_EVALID);
 
     strcpy(rev, temp_rev);
-    FREE_STRING(ctx->xml_ctx.ctx, temp_rev);
+    FREE_STRING(ctx->xmlctx->ctx, temp_rev);
 
-    return yin_parse_content(ctx, subelems, 1, data, LY_STMT_REVISION_DATE, NULL, exts);
+    return yin_parse_content(ctx, subelems, 1, LY_STMT_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)
+yin_parse_config(struct lys_yin_parser_ctx *ctx, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     const char *temp_val = NULL;
     struct yin_subelement subelems[1] = {
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                         };
 
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_CONFIG));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_CONFIG));
     if (strcmp(temp_val, "true") == 0) {
         *flags |= LYS_CONFIG_W;
     } else if (strcmp(temp_val, "false") == 0) {
@@ -1695,35 +1589,33 @@
     } 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);
+        FREE_STRING(ctx->xmlctx->ctx, temp_val);
         return LY_EVALID;
     }
-    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+    FREE_STRING(ctx->xmlctx->ctx, temp_val);
 
-    return yin_parse_content(ctx, subelems, 1, data, LY_STMT_CONFIG, NULL, exts);
+    return yin_parse_content(ctx, subelems, 1, LY_STMT_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)
+yin_parse_yangversion(struct lys_yin_parser_ctx *ctx, uint8_t *version, struct lysp_ext_instance **exts)
 {
     const char *temp_version = NULL;
     struct yin_subelement subelems[1] = {
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                         };
 
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_version, Y_STR_ARG, LY_STMT_YANG_VERSION));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_version, Y_STR_ARG, LY_STMT_YANG_VERSION));
     if (strcmp(temp_version, "1.0") == 0) {
         *version = LYS_VERSION_1_0;
     } else if (strcmp(temp_version, "1.1") == 0) {
@@ -1731,31 +1623,29 @@
     } 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);
+        FREE_STRING(ctx->xmlctx->ctx, temp_version);
         return LY_EVALID;
     }
-    FREE_STRING(ctx->xml_ctx.ctx, temp_version);
+    FREE_STRING(ctx->xmlctx->ctx, temp_version);
     ctx->mod_version = *version;
 
-    return yin_parse_content(ctx, subelems, 1, data, LY_STMT_YANG_VERSION, NULL, exts);
+    return yin_parse_content(ctx, subelems, 1, LY_STMT_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)
+yin_parse_import(struct lys_yin_parser_ctx *ctx, 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);
+    LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *imp_meta->imports, imp, LY_EMEM);
 
     struct yin_subelement subelems[5] = {
                                             {LY_STMT_DESCRIPTION, &imp->dsc, YIN_SUBELEM_UNIQUE},
@@ -1766,8 +1656,9 @@
                                         };
 
     /* parse import attributes */
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_MODULE, &imp->name, Y_IDENTIF_ARG, LY_STMT_IMPORT));
-    LY_CHECK_RET(yin_parse_content(ctx, subelems, 5, data, LY_STMT_IMPORT, NULL, &imp->exts));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_MODULE, &imp->name, Y_IDENTIF_ARG, LY_STMT_IMPORT));
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, 5, LY_STMT_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);
 
@@ -1778,23 +1669,21 @@
  * @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)
+yin_parse_mandatory(struct lys_yin_parser_ctx *ctx, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     const char *temp_val = NULL;
     struct yin_subelement subelems[1] = {
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                         };
 
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_MANDATORY));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_MANDATORY));
     if (strcmp(temp_val, "true") == 0) {
         *flags |= LYS_MAND_TRUE;
     } else if (strcmp(temp_val, "false") == 0) {
@@ -1802,35 +1691,33 @@
     } 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);
+        FREE_STRING(ctx->xmlctx->ctx, temp_val);
         return LY_EVALID;
     }
-    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+    FREE_STRING(ctx->xmlctx->ctx, temp_val);
 
-    return yin_parse_content(ctx, subelems, 1, data, LY_STMT_MANDATORY, NULL, exts);
+    return yin_parse_content(ctx, subelems, 1, LY_STMT_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)
+yin_parse_status(struct lys_yin_parser_ctx *ctx, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     const char *value = NULL;
     struct yin_subelement subelems[1] = {
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                         };
 
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &value, Y_STR_ARG, LY_STMT_STATUS));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, &value, Y_STR_ARG, LY_STMT_STATUS));
     if (strcmp(value, "current") == 0) {
         *flags |= LYS_STATUS_CURR;
     } else if (strcmp(value, "deprecated") == 0) {
@@ -1840,31 +1727,30 @@
     } 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);
+        FREE_STRING(ctx->xmlctx->ctx, value);
         return LY_EVALID;
     }
-    FREE_STRING(ctx->xml_ctx.ctx, value);
+    FREE_STRING(ctx->xmlctx->ctx, value);
 
-    return yin_parse_content(ctx, subelems, 1, data, LY_STMT_STATUS, NULL, exts);
+    return yin_parse_content(ctx, subelems, 1, LY_STMT_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)
+yin_parse_when(struct lys_yin_parser_ctx *ctx, 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, LY_STMT_WHEN);
+    LY_CHECK_ERR_RET(!when, LOGMEM(ctx->xmlctx->ctx), LY_EMEM);
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    ret = yin_parse_attribute(ctx, YIN_ARG_CONDITION, &when->cond, Y_STR_ARG, LY_STMT_WHEN);
     LY_CHECK_ERR_RET(ret, free(when), ret);
 
     *when_p = when;
@@ -1874,14 +1760,13 @@
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                         };
 
-    return yin_parse_content(ctx, subelems, 3, data, LY_STMT_WHEN, NULL, &when->exts);
+    return yin_parse_content(ctx, subelems, 3, LY_STMT_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.
@@ -1889,15 +1774,15 @@
  * @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)
+yin_parse_yin_element(struct lys_yin_parser_ctx *ctx, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     const char *temp_val = NULL;
     struct yin_subelement subelems[1] = {
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                         };
 
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_YIN_ELEMENT));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_YIN_ELEMENT));
     if (strcmp(temp_val, "true") == 0) {
         *flags |= LYS_YINELEM_TRUE;
     } else if (strcmp(temp_val, "false") == 0) {
@@ -1905,55 +1790,52 @@
     } 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);
+        FREE_STRING(ctx->xmlctx->ctx, temp_val);
         return LY_EVALID;
     }
-    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+    FREE_STRING(ctx->xmlctx->ctx, temp_val);
 
-    return yin_parse_content(ctx, subelems, 1, data, LY_STMT_YIN_ELEMENT, NULL, exts);
+    return yin_parse_content(ctx, subelems, 1, LY_STMT_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] xmlctx Xml context.
  * @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)
+yin_parse_argument(struct lys_yin_parser_ctx *ctx, struct yin_argument_meta *arg_meta, struct lysp_ext_instance **exts)
 {
     struct yin_subelement subelems[2] = {
                                             {LY_STMT_YIN_ELEMENT, arg_meta->flags, YIN_SUBELEM_UNIQUE},
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                         };
 
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, arg_meta->argument, Y_IDENTIF_ARG, LY_STMT_ARGUMENT));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, arg_meta->argument, Y_IDENTIF_ARG, LY_STMT_ARGUMENT));
 
-    return yin_parse_content(ctx, subelems, 2, data, LY_STMT_ARGUMENT, NULL, exts);
+    return yin_parse_content(ctx, subelems, 2, LY_STMT_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)
+yin_parse_extension(struct lys_yin_parser_ctx *ctx, 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, LY_STMT_EXTENSION));
+    LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *extensions, ex, LY_EMEM);
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &ex->name, Y_IDENTIF_ARG, LY_STMT_EXTENSION));
 
     struct yin_argument_meta arg_info = {&ex->flags, &ex->argument};
     struct yin_subelement subelems[5] = {
@@ -1964,30 +1846,28 @@
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                         };
 
-    return yin_parse_content(ctx, subelems, 5, data, LY_STMT_EXTENSION, NULL, &ex->exts);
+    return yin_parse_content(ctx, subelems, 5, LY_STMT_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)
+yin_parse_feature(struct lys_yin_parser_ctx *ctx, struct lysp_feature **features)
 {
     struct lysp_feature *feat;
 
     /* allocate new feature */
-    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *features, feat, LY_EMEM);
+    LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *features, feat, LY_EMEM);
 
     /* parse argument */
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &feat->name, Y_IDENTIF_ARG, LY_STMT_FEATURE));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &feat->name, Y_IDENTIF_ARG, LY_STMT_FEATURE));
 
     /* parse content */
     struct yin_subelement subelems[5] = {
@@ -1997,30 +1877,28 @@
                                             {LY_STMT_STATUS, &feat->flags, YIN_SUBELEM_UNIQUE},
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
                                         };
-    return yin_parse_content(ctx, subelems, 5, data, LY_STMT_FEATURE, NULL, &feat->exts);
+    return yin_parse_content(ctx, subelems, 5, LY_STMT_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)
+yin_parse_identity(struct lys_yin_parser_ctx *ctx, struct lysp_ident **identities)
 {
     struct lysp_ident *ident;
 
     /* allocate new identity */
-    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *identities, ident, LY_EMEM);
+    LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *identities, ident, LY_EMEM);
 
     /* parse argument */
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &ident->name, Y_IDENTIF_ARG, LY_STMT_IDENTITY));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &ident->name, Y_IDENTIF_ARG, LY_STMT_IDENTITY));
 
     /* parse content */
     struct yin_subelement subelems[6] = {
@@ -2031,33 +1909,31 @@
                                             {LY_STMT_STATUS, &ident->flags, YIN_SUBELEM_UNIQUE},
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
                                         };
-    return yin_parse_content(ctx, subelems, 6, data, LY_STMT_IDENTITY, NULL, &ident->exts);
+    return yin_parse_content(ctx, subelems, 6, LY_STMT_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)
+yin_parse_list(struct lys_yin_parser_ctx *ctx, 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, LY_EMEM);
+    LY_LIST_NEW_RET(ctx->xmlctx->ctx, node_meta->nodes, list, next, LY_EMEM);
     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, LY_STMT_LIST));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &list->name, Y_IDENTIF_ARG, LY_STMT_LIST));
 
     /* parse list content */
     LY_CHECK_RET(subelems_allocator(ctx, 25, (struct lysp_node *)list, &subelems,
@@ -2087,7 +1963,7 @@
                                         LY_STMT_WHEN, &list->when, YIN_SUBELEM_UNIQUE,
                                         LY_STMT_EXTENSION_INSTANCE, NULL, 0
                                    ));
-    ret = yin_parse_content(ctx, subelems, 25, data, LY_STMT_LIST, NULL, &list->exts);
+    ret = yin_parse_content(ctx, subelems, 25, LY_STMT_LIST, NULL, &list->exts);
     subelems_deallocator(25, subelems);
     LY_CHECK_RET(ret);
 
@@ -2106,15 +1982,12 @@
  * @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)
+yin_parse_notification(struct lys_yin_parser_ctx *ctx, struct tree_node_meta *notif_meta)
 {
     struct lysp_notif *notif;
     struct lysp_notif **notifs = (struct lysp_notif **)notif_meta->nodes;
@@ -2122,12 +1995,13 @@
     struct yin_subelement *subelems = NULL;
 
     /* allocate new notification */
-    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *notifs, notif, LY_EMEM);
+    LY_ARRAY_NEW_RET(ctx->xmlctx->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, LY_STMT_NOTIFICATION));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &notif->name, Y_IDENTIF_ARG, LY_STMT_NOTIFICATION));
 
     /* parse notification content */
     LY_CHECK_RET(subelems_allocator(ctx, 16, (struct lysp_node *)notif, &subelems,
@@ -2149,7 +2023,7 @@
                                         LY_STMT_EXTENSION_INSTANCE, NULL, 0
                                    ));
 
-    ret = yin_parse_content(ctx, subelems, 16, data, LY_STMT_NOTIFICATION, NULL, &notif->exts);
+    ret = yin_parse_content(ctx, subelems, 16, LY_STMT_NOTIFICATION, NULL, &notif->exts);
     subelems_deallocator(16, subelems);
     LY_CHECK_RET(ret);
 
@@ -2163,15 +2037,12 @@
  * @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)
+yin_parse_grouping(struct lys_yin_parser_ctx *ctx, struct tree_node_meta *gr_meta)
 {
     struct lysp_grp *grp;
     struct lysp_grp **grps = (struct lysp_grp **)gr_meta->nodes;
@@ -2179,12 +2050,13 @@
     struct yin_subelement *subelems = NULL;
 
     /* create new grouping */
-    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *grps, grp, LY_EMEM);
+    LY_ARRAY_NEW_RET(ctx->xmlctx->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, LY_STMT_GROUPING));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &grp->name, Y_IDENTIF_ARG, LY_STMT_GROUPING));
 
     /* parse grouping content */
     LY_CHECK_RET(subelems_allocator(ctx, 16, (struct lysp_node *)grp, &subelems,
@@ -2205,7 +2077,7 @@
                                         LY_STMT_USES, &grp->data, 0,
                                         LY_STMT_EXTENSION_INSTANCE, NULL, 0
                                    ));
-    ret = yin_parse_content(ctx, subelems, 16, data, LY_STMT_GROUPING, NULL, &grp->exts);
+    ret = yin_parse_content(ctx, subelems, 16, LY_STMT_GROUPING, NULL, &grp->exts);
     subelems_deallocator(16, subelems);
     LY_CHECK_RET(ret);
 
@@ -2219,27 +2091,25 @@
  * @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)
+yin_parse_container(struct lys_yin_parser_ctx *ctx, 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, LY_EMEM);
+    LY_LIST_NEW_RET(ctx->xmlctx->ctx, node_meta->nodes, cont, next, LY_EMEM);
     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, LY_STMT_CONTAINER));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME,  &cont->name, Y_IDENTIF_ARG, LY_STMT_CONTAINER));
 
     /* parse container content */
     LY_CHECK_RET(subelems_allocator(ctx, 21, (struct lysp_node *)cont, &subelems,
@@ -2265,7 +2135,7 @@
                                         LY_STMT_WHEN, &cont->when, YIN_SUBELEM_UNIQUE,
                                         LY_STMT_EXTENSION_INSTANCE, NULL, 0
                                    ));
-    ret = yin_parse_content(ctx, subelems, 21, data, LY_STMT_CONTAINER, NULL, &cont->exts);
+    ret = yin_parse_content(ctx, subelems, 21, LY_STMT_CONTAINER, NULL, &cont->exts);
     subelems_deallocator(21, subelems);
     LY_CHECK_RET(ret);
 
@@ -2278,27 +2148,25 @@
  * @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)
+yin_parse_case(struct lys_yin_parser_ctx *ctx, 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, LY_EMEM);
+    LY_LIST_NEW_RET(ctx->xmlctx->ctx, node_meta->nodes, cas, next, LY_EMEM);
     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, LY_STMT_CASE));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &cas->name, Y_IDENTIF_ARG, LY_STMT_CASE));
 
     /* parse case content */
     LY_CHECK_RET(subelems_allocator(ctx, 14, (struct lysp_node *)cas, &subelems,
@@ -2317,7 +2185,7 @@
                                         LY_STMT_WHEN, &cas->when, YIN_SUBELEM_UNIQUE,
                                         LY_STMT_EXTENSION_INSTANCE, NULL, 0
                                    ));
-    ret = yin_parse_content(ctx, subelems, 14, data, LY_STMT_CASE, NULL, &cas->exts);
+    ret = yin_parse_content(ctx, subelems, 14, LY_STMT_CASE, NULL, &cas->exts);
     subelems_deallocator(14, subelems);
 
     return ret;
@@ -2327,28 +2195,26 @@
  * @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)
+yin_parse_choice(struct lys_yin_parser_ctx *ctx, 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, LY_EMEM);
+    LY_LIST_NEW_RET(ctx->xmlctx->ctx, node_meta->nodes, choice, next, LY_EMEM);
 
     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, LY_STMT_CHOICE));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &choice->name, Y_IDENTIF_ARG, LY_STMT_CHOICE));
 
     /* parse choice content */
     LY_CHECK_RET(subelems_allocator(ctx, 17, (struct lysp_node *)choice, &subelems,
@@ -2370,7 +2236,7 @@
                                         LY_STMT_WHEN, &choice->when, YIN_SUBELEM_UNIQUE,
                                         LY_STMT_EXTENSION_INSTANCE, NULL, 0
                                    ));
-    ret = yin_parse_content(ctx, subelems, 17, data, LY_STMT_CHOICE, NULL, &choice->exts);
+    ret = yin_parse_content(ctx, subelems, 17, LY_STMT_CHOICE, NULL, &choice->exts);
     subelems_deallocator(17, subelems);
     return ret;
 }
@@ -2379,16 +2245,13 @@
  * @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 ly_stmt inout_kw,
-                struct inout_meta *inout_meta)
+yin_parse_inout(struct lys_yin_parser_ctx *ctx, enum ly_stmt inout_kw, struct inout_meta *inout_meta)
 {
     LY_ERR ret = LY_SUCCESS;
     struct yin_subelement *subelems = NULL;
@@ -2398,7 +2261,8 @@
     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));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, 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,
@@ -2415,7 +2279,7 @@
                                         LY_STMT_USES, &inout_meta->inout_p->data, 0,
                                         LY_STMT_EXTENSION_INSTANCE, NULL, 0
                                    ));
-    ret = yin_parse_content(ctx, subelems, 12, data, inout_kw, NULL, &inout_meta->inout_p->exts);
+    ret = yin_parse_content(ctx, subelems, 12, inout_kw, NULL, &inout_meta->inout_p->exts);
     subelems_deallocator(12, subelems);
     LY_CHECK_RET(ret);
 
@@ -2434,27 +2298,25 @@
  * @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)
+yin_parse_action(struct lys_yin_parser_ctx *ctx, 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);
+    LY_ARRAY_NEW_RET(ctx->xmlctx->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, LY_STMT_ACTION));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &act->name, Y_IDENTIF_ARG, LY_STMT_ACTION));
 
     /* parse content */
     LY_CHECK_RET(subelems_allocator(ctx, 9, (struct lysp_node *)act, &subelems,
@@ -2468,7 +2330,7 @@
                                         LY_STMT_TYPEDEF, &act->typedefs, 0,
                                         LY_STMT_EXTENSION_INSTANCE, NULL, 0
                                    ));
-    ret = (yin_parse_content(ctx, subelems, 9, data, LY_STMT_ACTION, NULL, &act->exts));
+    ret = (yin_parse_content(ctx, subelems, 9, LY_STMT_ACTION, NULL, &act->exts));
     subelems_deallocator(9, subelems);
     LY_CHECK_RET(ret);
 
@@ -2481,15 +2343,12 @@
  * @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)
+yin_parse_augment(struct lys_yin_parser_ctx *ctx, struct tree_node_meta *aug_meta)
 {
     struct lysp_augment *aug;
     struct lysp_augment **augs = (struct lysp_augment **)aug_meta->nodes;
@@ -2497,13 +2356,14 @@
     struct yin_subelement *subelems = NULL;
 
     /* create new augment */
-    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *augs, aug, LY_EMEM);
+    LY_ARRAY_NEW_RET(ctx->xmlctx->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, LY_STMT_AUGMENT));
-    YANG_CHECK_NONEMPTY((struct lys_parser_ctx *)ctx, strlen(aug->nodeid), "augment");
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_TARGET_NODE, &aug->nodeid, Y_STR_ARG, LY_STMT_AUGMENT));
+    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,
@@ -2525,7 +2385,7 @@
                                         LY_STMT_WHEN, &aug->when, YIN_SUBELEM_UNIQUE,
                                         LY_STMT_EXTENSION_INSTANCE, NULL, 0
                                    ));
-    ret = yin_parse_content(ctx, subelems, 17, data, LY_STMT_AUGMENT, NULL, &aug->exts);
+    ret = yin_parse_content(ctx, subelems, 17, LY_STMT_AUGMENT, NULL, &aug->exts);
     subelems_deallocator(17, subelems);
     LY_CHECK_RET(ret);
 
@@ -2538,15 +2398,12 @@
  * @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)
+yin_parse_deviate(struct lys_yin_parser_ctx *ctx, struct lysp_deviate **deviates)
 {
     LY_ERR ret = LY_SUCCESS;
     uint8_t dev_mod;
@@ -2557,7 +2414,8 @@
     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, LY_STMT_DEVIATE));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_DEVIATE));
 
     if (strcmp(temp_val, "not-supported") == 0) {
         dev_mod = LYS_DEV_NOT_SUPPORTED;
@@ -2570,22 +2428,22 @@
     } 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);
+        FREE_STRING(ctx->xmlctx->ctx, temp_val);
         return LY_EVALID;
     }
-    FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+    FREE_STRING(ctx->xmlctx->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);
+        LY_CHECK_ERR_RET(!d, LOGMEM(ctx->xmlctx->ctx), LY_EMEM);
         struct yin_subelement subelems[1] = {
                                                 {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
                                             };
-        ret = yin_parse_content(ctx, subelems, 1, data, LY_STMT_DEVIATE, NULL, &d->exts);
+        ret = yin_parse_content(ctx, subelems, 1, LY_STMT_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);
+        LY_CHECK_ERR_RET(!d_add, LOGMEM(ctx->xmlctx->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};
@@ -2600,11 +2458,11 @@
                                                 {LY_STMT_UNITS, &d_add->units, YIN_SUBELEM_UNIQUE},
                                                 {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
                                             };
-        ret = yin_parse_content(ctx, subelems, 9, data, LY_STMT_DEVIATE, NULL, &d_add->exts);
+        ret = yin_parse_content(ctx, subelems, 9, LY_STMT_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);
+        LY_CHECK_ERR_RET(!d_rpl, LOGMEM(ctx->xmlctx->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};
@@ -2618,11 +2476,11 @@
                                                 {LY_STMT_UNITS, &d_rpl->units, YIN_SUBELEM_UNIQUE},
                                                 {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
                                             };
-        ret = yin_parse_content(ctx, subelems, 8, data, LY_STMT_DEVIATE, NULL, &d_rpl->exts);
+        ret = yin_parse_content(ctx, subelems, 8,  LY_STMT_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);
+        LY_CHECK_ERR_RET(!d_del, LOGMEM(ctx->xmlctx->ctx), LY_EMEM);
         d = (struct lysp_deviate *)d_del;
         struct yin_subelement subelems[5] = {
                                                 {LY_STMT_DEFAULT, &d_del->dflts, 0},
@@ -2631,7 +2489,7 @@
                                                 {LY_STMT_UNITS, &d_del->units, YIN_SUBELEM_UNIQUE},
                                                 {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
                                             };
-        ret = yin_parse_content(ctx, subelems, 5, data, LY_STMT_DEVIATE, NULL, &d_del->exts);
+        ret = yin_parse_content(ctx, subelems, 5, LY_STMT_DEVIATE, NULL, &d_del->exts);
     }
     LY_CHECK_GOTO(ret, cleanup);
 
@@ -2650,31 +2508,29 @@
  * @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)
+yin_parse_deviation(struct lys_yin_parser_ctx *ctx, struct lysp_deviation **deviations)
 {
     struct lysp_deviation *dev;
 
     /* create new deviation */
-    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *deviations, dev, LY_EMEM);
+    LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *deviations, dev, LY_EMEM);
 
     /* parse argument */
-    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_TARGET_NODE, &dev->nodeid, Y_STR_ARG, LY_STMT_DEVIATION));
-    YANG_CHECK_NONEMPTY((struct lys_parser_ctx *)ctx, strlen(dev->nodeid), "deviation");
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_TARGET_NODE, &dev->nodeid, Y_STR_ARG, LY_STMT_DEVIATION));
+    CHECK_NONEMPTY((struct lys_parser_ctx *)ctx, strlen(dev->nodeid), "deviation");
     struct yin_subelement subelems[4] = {
                                             {LY_STMT_DESCRIPTION, &dev->dsc, YIN_SUBELEM_UNIQUE},
                                             {LY_STMT_DEVIATE, &dev->deviates, YIN_SUBELEM_MANDATORY},
                                             {LY_STMT_REFERENCE, &dev->ref, YIN_SUBELEM_UNIQUE},
                                             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
                                         };
-    return yin_parse_content(ctx, subelems, 4, data, LY_STMT_DEVIATION, NULL, &dev->exts);
+    return yin_parse_content(ctx, subelems, 4, LY_STMT_DEVIATION, NULL, &dev->exts);
 }
 
 /**
@@ -2767,7 +2623,7 @@
  * @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 ly_stmt kw, enum yang_module_stmt *group)
+kw2kw_group(struct lys_yin_parser_ctx *ctx, enum ly_stmt kw, enum yang_module_stmt *group)
 {
     switch (kw) {
         /* module header */
@@ -2816,7 +2672,7 @@
             *group = Y_MOD_BODY;
             break;
         default:
-            LOGINT(ctx->xml_ctx.ctx);
+            LOGINT(ctx->xmlctx->ctx);
             return LY_EINT;
     }
 
@@ -2835,7 +2691,7 @@
  * @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 ly_stmt kw, enum ly_stmt next_kw, enum ly_stmt parrent)
+yin_check_relative_order(struct lys_yin_parser_ctx *ctx, enum ly_stmt kw, enum ly_stmt next_kw, enum ly_stmt parrent)
 {
     assert(parrent == LY_STMT_MODULE || parrent == LY_STMT_SUBMODULE);
     enum yang_module_stmt gr, next_gr;
@@ -2863,14 +2719,14 @@
  * @return Element name prefixed by URI on success, NULL on failure.
  */
 static const char *
-name2nsname(struct yin_parser_ctx *ctx, const char *name, size_t name_len, const char *prefix, size_t prefix_len)
+name2nsname(struct lys_yin_parser_ctx *ctx, const char *name, size_t name_len, const char *prefix, size_t prefix_len)
 {
-    const struct lyxml_ns *ns = lyxml_ns_get(&ctx->xml_ctx, prefix, prefix_len);
-    LY_CHECK_ERR_RET(!ns, LOGINT(ctx->xml_ctx.ctx), NULL);
+    const struct lyxml_ns *ns = lyxml_ns_get(ctx->xmlctx, prefix, prefix_len);
+    LY_CHECK_ERR_RET(!ns, LOGINT(ctx->xmlctx->ctx), NULL);
 
     if (!strcmp(ns->uri, YIN_NS_URI)) {
         /* standard YANG statement in YIN namespace - keep it unprefixed as in case of YANG */
-        return lydict_insert(ctx->xml_ctx.ctx, name, name_len);
+        return lydict_insert(ctx->xmlctx->ctx, name, name_len);
     }
     /* some statement in special namespace (extension instance) */
     size_t ns_len = strlen(ns->uri);
@@ -2879,7 +2735,7 @@
     char *result;
     char *temp;
     temp = result = malloc(sizeof(*temp) * (len + 1)); /* +1 for '\0' terminator */
-    LY_CHECK_ERR_RET(!temp, LOGMEM(ctx->xml_ctx.ctx), NULL);
+    LY_CHECK_ERR_RET(!temp, LOGMEM(ctx->xmlctx->ctx), NULL);
 
     strcpy(result, ns->uri);
     result[ns_len] = ':';
@@ -2887,321 +2743,322 @@
     strncpy(temp, name, name_len);
     result[len] = '\0';
 
-    return lydict_insert_zc(ctx->xml_ctx.ctx, result);
+    return lydict_insert_zc(ctx->xmlctx->ctx, result);
 }
 
 LY_ERR
-yin_parse_content(struct yin_parser_ctx *ctx, struct yin_subelement *subelem_info, size_t subelem_info_size,
-                  const char **data, enum ly_stmt current_element, const char **text_content, struct lysp_ext_instance **exts)
+yin_parse_content(struct lys_yin_parser_ctx *ctx, struct yin_subelement *subelem_info, size_t subelem_info_size,
+                  enum ly_stmt 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 LYXML_PARSER_STATUS next_status;
     enum ly_stmt kw = LY_STMT_NONE, last_kw = LY_STMT_NONE;
     struct yin_subelement *subelem = NULL;
 
-    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);
+    assert(ctx->xmlctx->status == LYXML_ELEM_CONTENT);
 
-                /* check if this element can be child of current element */
-                subelem = get_record(kw, subelem_info_size, subelem_info);
-                if (!subelem) {
-                    if (current_element == LY_STMT_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));
-                    }
+    if (ctx->xmlctx->ws_only) {
+        /* check whether there are any children */
+        LY_CHECK_GOTO(ret = lyxml_ctx_peek(ctx->xmlctx, &next_status), cleanup);
+    } else {
+        /* we want to parse the value */
+        next_status = LYXML_ELEM_CLOSE;
+    }
+
+    if (next_status == LYXML_ELEMENT) {
+        LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
+
+        /* current element has subelements as content */
+        while (ctx->xmlctx->status == LYXML_ELEMENT) {
+            /* match keyword */
+            last_kw = kw;
+            kw = yin_match_keyword(ctx, ctx->xmlctx->name, ctx->xmlctx->name_len, ctx->xmlctx->prefix,
+                                   ctx->xmlctx->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 == LY_STMT_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, ctx->xmlctx->name_len,
+                                  ctx->xmlctx->name, ly_stmt2str(current_element));
+                }
+                ret = LY_EVALID;
+                goto cleanup;
+            }
+
+            /* relative order is required only in module and submodule sub-elements */
+            if (current_element == LY_STMT_MODULE || current_element == LY_STMT_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;
                 }
-
-                /* relative order is required only in module and submodule sub-elements */
-                if (current_element == LY_STMT_MODULE || current_element == LY_STMT_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 LY_STMT_EXTENSION_INSTANCE:
-                    ret = yin_parse_extension_instance(ctx, attrs, data, name, name_len, prefix, prefix_len,
-                                                      kw2lyext_substmt(current_element),
-                                                      (subelem->dest) ? *((uint32_t*)subelem->dest) : 0, exts);
-                    break;
-                case LY_STMT_ACTION:
-                case LY_STMT_RPC:
-                    ret = yin_parse_action(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
-                    break;
-                case LY_STMT_ANYDATA:
-                case LY_STMT_ANYXML:
-                    ret = yin_parse_any(ctx, attrs, data, kw, (struct tree_node_meta *)subelem->dest);
-                    break;
-                case LY_STMT_ARGUMENT:
-                    ret = yin_parse_argument(ctx, attrs, data, (struct yin_argument_meta *)subelem->dest, exts);
-                    break;
-                case LY_STMT_AUGMENT:
-                    ret = yin_parse_augment(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
-                    break;
-                case LY_STMT_BASE:
-                    ret = yin_parse_base(ctx, attrs, data, current_element, subelem->dest, exts);
-                    break;
-                case LY_STMT_BELONGS_TO:
-                    ret = yin_parse_belongs_to(ctx, attrs, data, (struct lysp_submodule *)subelem->dest, exts);
-                    break;
-                case LY_STMT_BIT:
-                    ret = yin_parse_bit(ctx, attrs, data, (struct lysp_type *)subelem->dest);
-                    break;
-                case LY_STMT_CASE:
-                    ret = yin_parse_case(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
-                    break;
-                case LY_STMT_CHOICE:
-                    ret = yin_parse_choice(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
-                    break;
-                case LY_STMT_CONFIG:
-                    ret = yin_parse_config(ctx, attrs, data, (uint16_t *)subelem->dest, exts);
-                    break;
-                case LY_STMT_CONTACT:
-                case LY_STMT_DESCRIPTION:
-                case LY_STMT_ORGANIZATION:
-                case LY_STMT_REFERENCE:
-                    ret = yin_parse_meta(ctx, attrs, data, kw, (const char **)subelem->dest, exts);
-                    break;
-                case LY_STMT_CONTAINER:
-                    ret = yin_parse_container(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
-                    break;
-                case LY_STMT_DEFAULT:
-                case LY_STMT_ERROR_APP_TAG:
-                case LY_STMT_KEY:
-                case LY_STMT_PRESENCE:
-                    ret = yin_parse_simple_elem(ctx, attrs, data, kw, subelem, YIN_ARG_VALUE, Y_STR_ARG, exts);
-                    break;
-                case LY_STMT_DEVIATE:
-                    ret = yin_parse_deviate(ctx, attrs, data, (struct lysp_deviate **)subelem->dest);
-                    break;
-                case LY_STMT_DEVIATION:
-                    ret = yin_parse_deviation(ctx, attrs, data, (struct lysp_deviation **)subelem->dest);
-                    break;
-                case LY_STMT_ENUM:
-                    ret = yin_parse_enum(ctx, attrs, data, (struct lysp_type *)subelem->dest);
-                    break;
-                case LY_STMT_ERROR_MESSAGE:
-                    ret = yin_parse_err_msg(ctx, attrs, data, (const char **)subelem->dest, exts);
-                    break;
-                case LY_STMT_EXTENSION:
-                    ret = yin_parse_extension(ctx, attrs, data, (struct lysp_ext **)subelem->dest);
-                    break;
-                case LY_STMT_FEATURE:
-                    ret = yin_parse_feature(ctx, attrs, data, (struct lysp_feature **)subelem->dest);
-                    break;
-                case LY_STMT_FRACTION_DIGITS:
-                    ret = yin_parse_fracdigits(ctx, attrs, data, (struct lysp_type *)subelem->dest);
-                    break;
-                case LY_STMT_GROUPING:
-                    ret = yin_parse_grouping(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
-                    break;
-                case LY_STMT_IDENTITY:
-                    ret = yin_parse_identity(ctx, attrs, data, (struct lysp_ident **)subelem->dest);
-                    break;
-                case LY_STMT_IF_FEATURE:
-                case LY_STMT_UNITS:
-                    ret = yin_parse_simple_elem(ctx, attrs, data, kw, subelem, YIN_ARG_NAME, Y_STR_ARG, exts);
-                    break;
-                case LY_STMT_IMPORT:
-                    ret = yin_parse_import(ctx, attrs, data, (struct import_meta *)subelem->dest);
-                    break;
-                case LY_STMT_INCLUDE:
-                    ret = yin_parse_include(ctx, attrs, data, (struct include_meta *)subelem->dest);
-                    break;
-                case LY_STMT_INPUT:
-                case LY_STMT_OUTPUT:
-                    ret = yin_parse_inout(ctx, attrs, data, kw, (struct inout_meta *)subelem->dest);
-                    break;
-                case LY_STMT_LEAF:
-                    ret = yin_parse_leaf(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
-                    break;
-                case LY_STMT_LEAF_LIST:
-                    ret = yin_parse_leaflist(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
-                    break;
-                case LY_STMT_LENGTH:
-                    ret = yin_parse_length(ctx, attrs, data, (struct lysp_type *)subelem->dest);
-                    break;
-                case LY_STMT_LIST:
-                    ret = yin_parse_list(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
-                    break;
-                case LY_STMT_MANDATORY:
-                    ret = yin_parse_mandatory(ctx, attrs, data, (uint16_t *)subelem->dest, exts);
-                    break;
-                case LY_STMT_MAX_ELEMENTS:
-                case LY_STMT_MIN_ELEMENTS:
-                    ret = yin_parse_minmax(ctx, attrs, data, current_element, kw, subelem->dest);
-                    break;
-                case LY_STMT_MODIFIER:
-                    ret = yin_parse_modifier(ctx, attrs, data, (const char **)subelem->dest, exts);
-                    break;
-                case LY_STMT_MUST:
-                    ret = yin_parse_must(ctx, attrs, data, (struct lysp_restr **)subelem->dest);
-                    break;
-                case LY_STMT_NAMESPACE:
-                    ret = yin_parse_simple_elem(ctx, attrs, data, kw, subelem, YIN_ARG_URI, Y_STR_ARG, exts);
-                    break;
-                case LY_STMT_NOTIFICATION:
-                    ret = yin_parse_notification(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
-                    break;
-                case LY_STMT_ORDERED_BY:
-                    ret = yin_parse_orderedby(ctx, attrs, data, (uint16_t *)subelem->dest, exts);
-                    break;
-                case LY_STMT_PATH:
-                    ret = yin_parse_path(ctx, attrs, data, kw, (struct lysp_type *)subelem->dest);
-                    break;
-                case LY_STMT_PATTERN:
-                    ret = yin_parse_pattern(ctx, attrs, data, (struct lysp_type *)subelem->dest);
-                    break;
-                case LY_STMT_VALUE:
-                case LY_STMT_POSITION:
-                    ret = yin_parse_value_pos(ctx, attrs, data, kw, (struct lysp_type_enum *)subelem->dest);
-                    break;
-                case LY_STMT_PREFIX:
-                    ret = yin_parse_simple_elem(ctx, attrs, data, kw, subelem, YIN_ARG_VALUE, Y_IDENTIF_ARG, exts);
-                    break;
-                case LY_STMT_RANGE:
-                    ret = yin_parse_range(ctx, attrs, data, (struct lysp_type *)subelem->dest);
-                    break;
-                case LY_STMT_REFINE:
-                    ret = yin_parse_refine(ctx, attrs, data, (struct lysp_refine **)subelem->dest);
-                    break;
-                case LY_STMT_REQUIRE_INSTANCE:
-                    ret = yin_pasrse_reqinstance(ctx, attrs, data, (struct lysp_type *)subelem->dest);
-                    break;
-                case LY_STMT_REVISION:
-                    ret = yin_parse_revision(ctx, attrs, data, (struct lysp_revision **)subelem->dest);
-                    break;
-                case LY_STMT_REVISION_DATE:
-                    ret = yin_parse_revision_date(ctx, attrs, data, (char *)subelem->dest, exts);
-                    break;
-                case LY_STMT_STATUS:
-                    ret = yin_parse_status(ctx, attrs, data, (uint16_t *)subelem->dest, exts);
-                    break;
-                case LY_STMT_TYPE:
-                    ret = yin_parse_type(ctx, attrs, data, current_element, subelem);
-                    break;
-                case LY_STMT_TYPEDEF:
-                    ret = yin_parse_typedef(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
-                    break;
-                case LY_STMT_UNIQUE:
-                    ret = yin_parse_simple_elem(ctx, attrs, data, kw, subelem, YIN_ARG_TAG, Y_STR_ARG, exts);
-                    break;
-                case LY_STMT_USES:
-                    ret = yin_parse_uses(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
-                    break;
-                case LY_STMT_WHEN:
-                    ret = yin_parse_when(ctx, attrs, data, (struct lysp_when **)subelem->dest);
-                    break;
-                case LY_STMT_YANG_VERSION:
-                    ret = yin_parse_yangversion(ctx, attrs, data, (uint8_t *)subelem->dest, exts);
-                    break;
-                case LY_STMT_YIN_ELEMENT:
-                    ret = yin_parse_yin_element(ctx, attrs, data, (uint16_t *)subelem->dest, exts);
-                    break;
-                case LY_STMT_ARG_TEXT:
-                case LY_STMT_ARG_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);
+            /* note that element was parsed for easy uniqueness check in next iterations */
+            subelem->flags |= YIN_SUBELEM_PARSED;
+
+            switch (kw) {
+            /* call responsible function */
+            case LY_STMT_EXTENSION_INSTANCE:
+                ret = yin_parse_extension_instance(ctx, kw2lyext_substmt(current_element),
+                                                   (subelem->dest) ? *((uint32_t*)subelem->dest) : 0, exts);
+                break;
+            case LY_STMT_ACTION:
+            case LY_STMT_RPC:
+                ret = yin_parse_action(ctx, (struct tree_node_meta *)subelem->dest);
+                break;
+            case LY_STMT_ANYDATA:
+            case LY_STMT_ANYXML:
+                ret = yin_parse_any(ctx, kw, (struct tree_node_meta *)subelem->dest);
+                break;
+            case LY_STMT_ARGUMENT:
+                ret = yin_parse_argument(ctx, (struct yin_argument_meta *)subelem->dest, exts);
+                break;
+            case LY_STMT_AUGMENT:
+                ret = yin_parse_augment(ctx, (struct tree_node_meta *)subelem->dest);
+                break;
+            case LY_STMT_BASE:
+                ret = yin_parse_base(ctx, current_element, subelem->dest, exts);
+                break;
+            case LY_STMT_BELONGS_TO:
+                ret = yin_parse_belongs_to(ctx, (struct lysp_submodule *)subelem->dest, exts);
+                break;
+            case LY_STMT_BIT:
+                ret = yin_parse_bit(ctx, (struct lysp_type *)subelem->dest);
+                break;
+            case LY_STMT_CASE:
+                ret = yin_parse_case(ctx, (struct tree_node_meta *)subelem->dest);
+                break;
+            case LY_STMT_CHOICE:
+                ret = yin_parse_choice(ctx, (struct tree_node_meta *)subelem->dest);
+                break;
+            case LY_STMT_CONFIG:
+                ret = yin_parse_config(ctx, (uint16_t *)subelem->dest, exts);
+                break;
+            case LY_STMT_CONTACT:
+            case LY_STMT_DESCRIPTION:
+            case LY_STMT_ORGANIZATION:
+            case LY_STMT_REFERENCE:
+                ret = yin_parse_meta(ctx, kw, (const char **)subelem->dest, exts);
+                break;
+            case LY_STMT_CONTAINER:
+                ret = yin_parse_container(ctx, (struct tree_node_meta *)subelem->dest);
+                break;
+            case LY_STMT_DEFAULT:
+            case LY_STMT_ERROR_APP_TAG:
+            case LY_STMT_KEY:
+            case LY_STMT_PRESENCE:
+                ret = yin_parse_simple_elem(ctx, kw, subelem, YIN_ARG_VALUE, Y_STR_ARG, exts);
+                break;
+            case LY_STMT_DEVIATE:
+                ret = yin_parse_deviate(ctx, (struct lysp_deviate **)subelem->dest);
+                break;
+            case LY_STMT_DEVIATION:
+                ret = yin_parse_deviation(ctx, (struct lysp_deviation **)subelem->dest);
+                break;
+            case LY_STMT_ENUM:
+                ret = yin_parse_enum(ctx, (struct lysp_type *)subelem->dest);
+                break;
+            case LY_STMT_ERROR_MESSAGE:
+                ret = yin_parse_err_msg(ctx, (const char **)subelem->dest, exts);
+                break;
+            case LY_STMT_EXTENSION:
+                ret = yin_parse_extension(ctx, (struct lysp_ext **)subelem->dest);
+                break;
+            case LY_STMT_FEATURE:
+                ret = yin_parse_feature(ctx, (struct lysp_feature **)subelem->dest);
+                break;
+            case LY_STMT_FRACTION_DIGITS:
+                ret = yin_parse_fracdigits(ctx, (struct lysp_type *)subelem->dest);
+                break;
+            case LY_STMT_GROUPING:
+                ret = yin_parse_grouping(ctx, (struct tree_node_meta *)subelem->dest);
+                break;
+            case LY_STMT_IDENTITY:
+                ret = yin_parse_identity(ctx, (struct lysp_ident **)subelem->dest);
+                break;
+            case LY_STMT_IF_FEATURE:
+            case LY_STMT_UNITS:
+                ret = yin_parse_simple_elem(ctx, kw, subelem, YIN_ARG_NAME, Y_STR_ARG, exts);
+                break;
+            case LY_STMT_IMPORT:
+                ret = yin_parse_import(ctx, (struct import_meta *)subelem->dest);
+                break;
+            case LY_STMT_INCLUDE:
+                ret = yin_parse_include(ctx, (struct include_meta *)subelem->dest);
+                break;
+            case LY_STMT_INPUT:
+            case LY_STMT_OUTPUT:
+                ret = yin_parse_inout(ctx, kw, (struct inout_meta *)subelem->dest);
+                break;
+            case LY_STMT_LEAF:
+                ret = yin_parse_leaf(ctx, (struct tree_node_meta *)subelem->dest);
+                break;
+            case LY_STMT_LEAF_LIST:
+                ret = yin_parse_leaflist(ctx, (struct tree_node_meta *)subelem->dest);
+                break;
+            case LY_STMT_LENGTH:
+                ret = yin_parse_length(ctx, (struct lysp_type *)subelem->dest);
+                break;
+            case LY_STMT_LIST:
+                ret = yin_parse_list(ctx, (struct tree_node_meta *)subelem->dest);
+                break;
+            case LY_STMT_MANDATORY:
+                ret = yin_parse_mandatory(ctx, (uint16_t *)subelem->dest, exts);
+                break;
+            case LY_STMT_MAX_ELEMENTS:
+            case LY_STMT_MIN_ELEMENTS:
+                ret = yin_parse_minmax(ctx, current_element, kw, subelem->dest);
+                break;
+            case LY_STMT_MODIFIER:
+                ret = yin_parse_modifier(ctx, (const char **)subelem->dest, exts);
+                break;
+            case LY_STMT_MUST:
+                ret = yin_parse_must(ctx, (struct lysp_restr **)subelem->dest);
+                break;
+            case LY_STMT_NAMESPACE:
+                ret = yin_parse_simple_elem(ctx, kw, subelem, YIN_ARG_URI, Y_STR_ARG, exts);
+                break;
+            case LY_STMT_NOTIFICATION:
+                ret = yin_parse_notification(ctx, (struct tree_node_meta *)subelem->dest);
+                break;
+            case LY_STMT_ORDERED_BY:
+                ret = yin_parse_orderedby(ctx, (uint16_t *)subelem->dest, exts);
+                break;
+            case LY_STMT_PATH:
+                ret = yin_parse_path(ctx, kw, (struct lysp_type *)subelem->dest);
+                break;
+            case LY_STMT_PATTERN:
+                ret = yin_parse_pattern(ctx, (struct lysp_type *)subelem->dest);
+                break;
+            case LY_STMT_VALUE:
+            case LY_STMT_POSITION:
+                ret = yin_parse_value_pos(ctx, kw, (struct lysp_type_enum *)subelem->dest);
+                break;
+            case LY_STMT_PREFIX:
+                ret = yin_parse_simple_elem(ctx, kw, subelem, YIN_ARG_VALUE, Y_IDENTIF_ARG, exts);
+                break;
+            case LY_STMT_RANGE:
+                ret = yin_parse_range(ctx, (struct lysp_type *)subelem->dest);
+                break;
+            case LY_STMT_REFINE:
+                ret = yin_parse_refine(ctx, (struct lysp_refine **)subelem->dest);
+                break;
+            case LY_STMT_REQUIRE_INSTANCE:
+                ret = yin_pasrse_reqinstance(ctx, (struct lysp_type *)subelem->dest);
+                break;
+            case LY_STMT_REVISION:
+                ret = yin_parse_revision(ctx, (struct lysp_revision **)subelem->dest);
+                break;
+            case LY_STMT_REVISION_DATE:
+                ret = yin_parse_revision_date(ctx, (char *)subelem->dest, exts);
+                break;
+            case LY_STMT_STATUS:
+                ret = yin_parse_status(ctx, (uint16_t *)subelem->dest, exts);
+                break;
+            case LY_STMT_TYPE:
+                ret = yin_parse_type(ctx, current_element, subelem);
+                break;
+            case LY_STMT_TYPEDEF:
+                ret = yin_parse_typedef(ctx, (struct tree_node_meta *)subelem->dest);
+                break;
+            case LY_STMT_UNIQUE:
+                ret = yin_parse_simple_elem(ctx, kw, subelem, YIN_ARG_TAG, Y_STR_ARG, exts);
+                break;
+            case LY_STMT_USES:
+                ret = yin_parse_uses(ctx, (struct tree_node_meta *)subelem->dest);
+                break;
+            case LY_STMT_WHEN:
+                ret = yin_parse_when(ctx, (struct lysp_when **)subelem->dest);
+                break;
+            case LY_STMT_YANG_VERSION:
+                ret = yin_parse_yangversion(ctx, (uint8_t *)subelem->dest, exts);
+                break;
+            case LY_STMT_YIN_ELEMENT:
+                ret = yin_parse_yin_element(ctx, (uint16_t *)subelem->dest, exts);
+                break;
+            case LY_STMT_ARG_TEXT:
+            case LY_STMT_ARG_VALUE:
+                /* TODO what to do with content/attributes? */
+                LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
+                while (ctx->xmlctx->status == LYXML_ATTRIBUTE) {
+                    LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
+                    LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
+                }
+                ret = yin_parse_content(ctx, NULL, 0, kw, (const char **)subelem->dest, NULL);
+                break;
+            default:
+                LOGINT(ctx->xmlctx->ctx);
+                ret = LY_EINT;
             }
-            /* load closing element */
-            LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len));
+            LY_CHECK_GOTO(ret, cleanup);
+            subelem = NULL;
+
+            LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
         }
+    } 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));
+        if (text_content) {
+            *text_content = INSERT_STRING(ctx->xmlctx->ctx, ctx->xmlctx->value, ctx->xmlctx->value_len, ctx->xmlctx->dynamic);
+            LY_CHECK_RET(!*text_content, LY_EMEM);
+        }
+
+        LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
     }
+
     /* 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, size_t ext_name_len, const char *ext_prefix, size_t ext_prefix_len,
-                             LYEXT_SUBSTMT subelem, uint32_t subelem_index, struct lysp_ext_instance **exts)
+yin_parse_extension_instance(struct lys_yin_parser_ctx *ctx, 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);
+    assert(ctx->xmlctx->status == LYXML_ELEMENT);
+
+    LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *exts, e, LY_EMEM);
 
     e->yin = 0;
     /* store name and insubstmt info */
-    e->name = name2nsname(ctx, ext_name, ext_name_len, ext_prefix, ext_prefix_len);
+    e->name = name2nsname(ctx, ctx->xmlctx->name, ctx->xmlctx->name_len, ctx->xmlctx->prefix, ctx->xmlctx->prefix_len);
     LY_CHECK_RET(!e->name, LY_EMEM);
     e->insubstmt = subelem;
     e->insubstmt_index = subelem_index;
     e->yin |= LYS_YIN;
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
 
     /* store attributes as subelements */
-    LY_ARRAY_FOR_ITER(attrs, struct yin_arg_record, iter) {
-        if (!iter->prefix) {
+    while (ctx->xmlctx->status == LYXML_ATTRIBUTE) {
+        if (!ctx->xmlctx->prefix) {
             new_subelem = calloc(1, sizeof(*new_subelem));
             if (!e->child) {
                 e->child = new_subelem;
@@ -3211,45 +3068,42 @@
             last_subelem = new_subelem;
 
             last_subelem->flags |= LYS_YIN_ATTR;
-            last_subelem->stmt = lydict_insert(ctx->xml_ctx.ctx, iter->name, iter->name_len);
+            last_subelem->stmt = lydict_insert(ctx->xmlctx->ctx, ctx->xmlctx->name, ctx->xmlctx->name_len);
             LY_CHECK_RET(!last_subelem->stmt, LY_EMEM);
+            LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
 
-            INSERT_STRING(ctx->xml_ctx.ctx, last_subelem->arg, iter->dynamic_content, iter->content, iter->content_len);
+            last_subelem->arg = INSERT_STRING(ctx->xmlctx->ctx, ctx->xmlctx->value, ctx->xmlctx->value_len, ctx->xmlctx->dynamic);
             LY_CHECK_RET(!last_subelem->arg, LY_EMEM);
+        } else {
+            LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
         }
+
+        LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
     }
 
     /* 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, name, name_len, prefix, prefix_len, LY_STMT_EXTENSION_INSTANCE, data, &new_subelem));
-                if (!e->child) {
-                    e->child = new_subelem;
-                } else {
-                    last_subelem->next = new_subelem;
-                }
-                last_subelem = new_subelem;
+    assert(ctx->xmlctx->status == LYXML_ELEM_CONTENT);
+    if (ctx->xmlctx->ws_only) {
+        LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+        while (ctx->xmlctx->status == LYXML_ELEMENT) {
+            LY_CHECK_RET(yin_parse_element_generic(ctx, LY_STMT_EXTENSION_INSTANCE, &new_subelem));
+            if (!e->child) {
+                e->child = new_subelem;
+            } else {
+                last_subelem->next = new_subelem;
             }
-        } else {
-            if (out_len != 0) {
-                /* save text content */
-                LY_CHECK_RET(ret);
+            last_subelem = new_subelem;
 
-                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);
-            }
+            assert(ctx->xmlctx->status == LYXML_ELEM_CLOSE);
+            LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
         }
+    } else if (ctx->xmlctx->value_len) {
+        /* save text content */
+        e->argument = INSERT_STRING(ctx->xmlctx->ctx, ctx->xmlctx->value, ctx->xmlctx->value_len, ctx->xmlctx->dynamic);
+        LY_CHECK_RET(!e->argument, LY_EMEM);
+
+        /* parser next */
+        LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
     }
 
     return LY_SUCCESS;
@@ -3259,24 +3113,18 @@
  * @brief Parse argument of extension subelement that is classic yang keyword and not another 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] elem_type Type of element that is currently being parsed.
  * @param[out] arg Value to write to.
  *
  * @return LY_ERR values.
  */
 static LY_ERR
-yin_parse_extension_instance_arg(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, enum ly_stmt elem_type,
-                           const char **arg)
+yin_parse_extension_instance_arg(struct lys_yin_parser_ctx *ctx, enum ly_stmt elem_type, const char **arg)
 {
-    LY_ERR ret = LY_SUCCESS;
-    char *out = NULL;
-    const char *name, *prefix;
-    size_t out_len, name_len, prefix_len;
-    int dynamic;
     enum ly_stmt child;
 
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+
     switch (elem_type) {
     case LY_STMT_ACTION:
     case LY_STMT_ANYDATA:
@@ -3304,12 +3152,12 @@
     case LY_STMT_TYPEDEF:
     case LY_STMT_UNITS:
     case LY_STMT_USES:
-        LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, arg, Y_MAYBE_STR_ARG, elem_type));
         break;
     case LY_STMT_AUGMENT:
     case LY_STMT_DEVIATION:
     case LY_STMT_REFINE:
-        LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_TARGET_NODE, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_TARGET_NODE, arg, Y_MAYBE_STR_ARG, elem_type));
         break;
     case LY_STMT_CONFIG:
     case LY_STMT_DEFAULT:
@@ -3334,30 +3182,30 @@
     case LY_STMT_VALUE:
     case LY_STMT_YANG_VERSION:
     case LY_STMT_YIN_ELEMENT:
-        LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, arg, Y_MAYBE_STR_ARG, elem_type));
         break;
     case LY_STMT_IMPORT:
     case LY_STMT_INCLUDE:
     case LY_STMT_BELONGS_TO:
-        LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_MODULE, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_MODULE, arg, Y_MAYBE_STR_ARG, elem_type));
         break;
     case LY_STMT_INPUT:
     case LY_STMT_OUTPUT:
-        LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NONE, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NONE, arg, Y_MAYBE_STR_ARG, elem_type));
         break;
     case LY_STMT_MUST:
     case LY_STMT_WHEN:
-        LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_CONDITION, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_CONDITION, arg, Y_MAYBE_STR_ARG, elem_type));
         break;
     case LY_STMT_NAMESPACE:
-        LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_URI, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_URI, arg, Y_MAYBE_STR_ARG, elem_type));
         break;
     case LY_STMT_REVISION:
     case LY_STMT_REVISION_DATE:
-        LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_DATE, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_DATE, arg, Y_MAYBE_STR_ARG, elem_type));
         break;
     case LY_STMT_UNIQUE:
-        LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_TAG, arg, Y_MAYBE_STR_ARG, elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_TAG, arg, Y_MAYBE_STR_ARG, elem_type));
         break;
     /* argument is mapped to yin element */
     case LY_STMT_CONTACT:
@@ -3366,31 +3214,49 @@
     case LY_STMT_REFERENCE:
     case LY_STMT_ERROR_MESSAGE:
         /* there shouldn't be any attribute, argument is supposed to be first subelement */
-        LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NONE, arg, Y_MAYBE_STR_ARG, elem_type));
-        ret = lyxml_get_string(&ctx->xml_ctx, data, &out, &out_len, &out, &out_len, &dynamic);
-        LY_CHECK_ERR_RET(ret != LY_EINVAL, LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_FIRT_SUBELEM,
-                                                         elem_type == LY_STMT_ERROR_MESSAGE ? "value" : "text", ly_stmt2str(elem_type)),
-                        LY_EVALID);
-        LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len));
-        child = yin_match_keyword(ctx, name, name_len, prefix, prefix_len, elem_type);
-        if ((elem_type == LY_STMT_ERROR_MESSAGE && child != LY_STMT_ARG_VALUE) ||
-            (elem_type != LY_STMT_ERROR_MESSAGE && child != LY_STMT_ARG_TEXT)) {
-            LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_UNEXP_SUBELEM, name_len, name, ly_stmt2str(elem_type));
+        LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NONE, arg, Y_MAYBE_STR_ARG, elem_type));
+
+        /* no content */
+        assert(ctx->xmlctx->status == LYXML_ELEM_CONTENT);
+        if (ctx->xmlctx->ws_only) {
+            LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+        }
+        if (((ctx->xmlctx->status == LYXML_ELEM_CONTENT) && !ctx->xmlctx->ws_only) || (ctx->xmlctx->status != LYXML_ELEMENT)) {
+            LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_FIRT_SUBELEM,
+                          elem_type == LY_STMT_ERROR_MESSAGE ? "value" : "text", ly_stmt2str(elem_type));
             return LY_EVALID;
         }
-        /* load and save content */
-        LY_CHECK_RET(lyxml_get_string(&ctx->xml_ctx, data, &out, &out_len, &out, &out_len, &dynamic));
-        INSERT_STRING(ctx->xml_ctx.ctx, *arg, dynamic, out, out_len);
-        LY_CHECK_RET(!*arg, LY_EMEM);
-        /* load closing tag of subelement */
-        LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len));
-        /* if only subelement was parsed as argument, load also closing tag */
-        if (ctx->xml_ctx.status == LYXML_ELEMENT) {
-            LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len));
+
+        /* parse child element */
+        child = yin_match_keyword(ctx, ctx->xmlctx->name, ctx->xmlctx->name_len, ctx->xmlctx->prefix, ctx->xmlctx->prefix_len, elem_type);
+        if ((elem_type == LY_STMT_ERROR_MESSAGE && child != LY_STMT_ARG_VALUE) ||
+            (elem_type != LY_STMT_ERROR_MESSAGE && child != LY_STMT_ARG_TEXT)) {
+            LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_UNEXP_SUBELEM, ctx->xmlctx->name_len, ctx->xmlctx->name,
+                          ly_stmt2str(elem_type));
+            return LY_EVALID;
         }
+        LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+
+        /* no attributes expected? TODO */
+        while (ctx->xmlctx->status == LYXML_ATTRIBUTE) {
+            LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+            LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+        }
+
+        /* load and save content */
+        *arg = INSERT_STRING(ctx->xmlctx->ctx, ctx->xmlctx->value, ctx->xmlctx->value_len, ctx->xmlctx->dynamic);
+        LY_CHECK_RET(!*arg, LY_EMEM);
+
+        /* load closing tag of subelement */
+        LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+
+        /* if only subelement was parsed as argument, load also closing tag TODO what? */
+        /*if (ctx->xmlctx->status == LYXML_ELEMENT) {
+            LY_CHECK_RET(lyxml_get_element(&ctx->xmlctx, data, &prefix, &prefix_len, &name, &name_len));
+        }*/
         break;
     default:
-        LOGINT(ctx->xml_ctx.ctx);
+        LOGINT(ctx->xmlctx->ctx);
         return LY_EINT;
     }
 
@@ -3398,45 +3264,40 @@
 }
 
 LY_ERR
-yin_parse_element_generic(struct yin_parser_ctx *ctx, const char *name, size_t name_len, const char *prefix, size_t prefix_len, enum ly_stmt parent,
-                          const char **data, struct lysp_stmt **element)
+yin_parse_element_generic(struct lys_yin_parser_ctx *ctx, enum ly_stmt parent, 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;
-    int dynamic;
     struct lysp_stmt *last = NULL, *new = NULL;
-    struct yin_arg_record *attrs = NULL;
-    struct yin_arg_record *iter = NULL;
 
-    /* load all attributes for correct namespace evaluation */
-    ret = yin_load_attributes(ctx, data, &attrs);
-    LY_CHECK_GOTO(ret, cleanup);
+    assert(ctx->xmlctx->status == LYXML_ELEMENT);
 
     /* allocate new structure for element */
     *element = calloc(1, sizeof(**element));
-    LY_CHECK_ERR_GOTO(!(*element), LOGMEM(ctx->xml_ctx.ctx); ret = LY_EMEM, cleanup);
-    (*element)->stmt = name2nsname(ctx, name, name_len, prefix, prefix_len);
+    LY_CHECK_ERR_GOTO(!(*element), LOGMEM(ctx->xmlctx->ctx); ret = LY_EMEM, cleanup);
+    (*element)->stmt = name2nsname(ctx, ctx->xmlctx->name, ctx->xmlctx->name_len, ctx->xmlctx->prefix, ctx->xmlctx->prefix_len);
     LY_CHECK_ERR_GOTO(!(*element)->stmt, ret = LY_EMEM, cleanup);
 
-    (*element)->kw = yin_match_keyword(ctx, name, name_len, prefix, prefix_len, parent);
+    (*element)->kw = yin_match_keyword(ctx, ctx->xmlctx->name, ctx->xmlctx->name_len, ctx->xmlctx->prefix,
+                                       ctx->xmlctx->prefix_len, parent);
 
     last = (*element)->child;
     if ((*element)->kw == LY_STMT_NONE) {
         /* unrecognized element */
-        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_UNEXP_SUBELEM, name_len, name, ly_stmt2str(parent));
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_UNEXP_SUBELEM, ctx->xmlctx->name_len, ctx->xmlctx->name,
+                      ly_stmt2str(parent));
         ret = LY_EVALID;
         goto cleanup;
     } else if ((*element)->kw != LY_STMT_EXTENSION_INSTANCE) {
         /* element is known yang keyword, which means argument can be parsed correctly. */
-        ret = yin_parse_extension_instance_arg(ctx, attrs, data, (*element)->kw, &(*element)->arg);
+        ret = yin_parse_extension_instance_arg(ctx, (*element)->kw, &(*element)->arg);
         LY_CHECK_GOTO(ret, cleanup);
     } else {
+        LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
+
         /* load attributes in generic way, save all attributes in linked list */
-        LY_ARRAY_FOR(attrs, struct yin_arg_record, iter) {
+        while (ctx->xmlctx->status == LYXML_ATTRIBUTE) {
             new = calloc(1, sizeof(*last));
-            LY_CHECK_ERR_GOTO(!new, LOGMEM(ctx->xml_ctx.ctx); ret = LY_EMEM, cleanup);
+            LY_CHECK_ERR_GOTO(!new, LOGMEM(ctx->xmlctx->ctx); ret = LY_EMEM, cleanup);
             if (!(*element)->child) {
                 /* save first */
                 (*element)->child = new;
@@ -3446,68 +3307,62 @@
             last = new;
 
             last->flags |= LYS_YIN_ATTR;
-            last->stmt = lydict_insert(ctx->xml_ctx.ctx, iter->name, iter->name_len);
+            last->stmt = lydict_insert(ctx->xmlctx->ctx, ctx->xmlctx->name, ctx->xmlctx->name_len);
             last->kw = LY_STMT_NONE;
             /* attributes with prefix are ignored */
-            if (!iter->prefix) {
-                INSERT_STRING(ctx->xml_ctx.ctx, last->arg, iter->dynamic_content, iter->content, iter->content_len);
+            if (!ctx->xmlctx->prefix) {
+                LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
+
+                last->arg = INSERT_STRING(ctx->xmlctx->ctx, ctx->xmlctx->value, ctx->xmlctx->value_len, ctx->xmlctx->dynamic);
                 LY_CHECK_ERR_GOTO(!last->arg, ret = LY_EMEM, cleanup);
-                /* string is no longer supposed to be freed when the array is freed */
-                iter->dynamic_content = 0;
+            } else {
+                LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
             }
+            LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
         }
     }
 
-    /* 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 */
-                ret = lyxml_get_element(&ctx->xml_ctx, data, &temp_prefix, &temp_prefix_len, &temp_name, &temp_name_len);
-                LY_CHECK_GOTO(ret , cleanup);
-                if (!temp_name) {
-                    /* end of element reached */
-                    break;
-                }
-                ret = yin_parse_element_generic(ctx, temp_name, temp_name_len, temp_prefix, temp_prefix_len, (*element)->kw, data, &new);
-                LY_CHECK_GOTO(ret, cleanup);
-                if (!(*element)->child) {
-                    /* save first */
-                    (*element)->child = new;
-                } else {
-                    last->next = new;
-                }
-                last = new;
-            }
-        ret = LY_SUCCESS;
-        } else {
+    if ((ctx->xmlctx->status != LYXML_ELEM_CONTENT) || ctx->xmlctx->ws_only) {
+        LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
+        while (ctx->xmlctx->status == LYXML_ELEMENT) {
+            /* parse subelements */
+            ret = yin_parse_element_generic(ctx, (*element)->kw, &new);
             LY_CHECK_GOTO(ret, cleanup);
-            /* save element content */
-            if (out_len != 0) {
-                INSERT_STRING(ctx->xml_ctx.ctx, (*element)->arg, dynamic, out, out_len);
-                LY_CHECK_ERR_GOTO(!(*element)->arg, ret = LY_EMEM, cleanup);
+            if (!(*element)->child) {
+                /* save first */
+                (*element)->child = new;
+            } else {
+                last->next = new;
             }
+            last = new;
 
-            /* read closing tag */
-            ret = lyxml_get_element(&ctx->xml_ctx, data, &temp_prefix, &temp_prefix_len, &temp_name, &temp_name_len);
-            LY_CHECK_GOTO(ret, cleanup);
+            assert(ctx->xmlctx->status == LYXML_ELEM_CLOSE);
+            LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
         }
+    } else {
+        /* save element content */
+        if (ctx->xmlctx->value_len) {
+            (*element)->arg = INSERT_STRING(ctx->xmlctx->ctx, ctx->xmlctx->value, ctx->xmlctx->value_len, ctx->xmlctx->dynamic);
+            LY_CHECK_ERR_GOTO(!(*element)->arg, ret = LY_EMEM, cleanup);
+        }
+
+        /* read closing tag */
+        LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
     }
 
 cleanup:
-    FREE_ARRAY(ctx, attrs, free_arg_rec);
     return ret;
 }
 
 LY_ERR
-yin_parse_mod(struct yin_parser_ctx *ctx, struct yin_arg_record *mod_attrs, const char **data, struct lysp_module *mod)
+yin_parse_mod(struct lys_yin_parser_ctx *ctx, struct lysp_module *mod)
 {
     LY_ERR ret = LY_SUCCESS;
     struct yin_subelement *subelems = NULL;
     struct lysp_submodule *dup;
 
-    LY_CHECK_RET(yin_parse_attribute(ctx, mod_attrs, YIN_ARG_NAME, &mod->mod->name, Y_IDENTIF_ARG, LY_STMT_MODULE));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &mod->mod->name, Y_IDENTIF_ARG, LY_STMT_MODULE));
     LY_CHECK_RET(subelems_allocator(ctx, 28, NULL, &subelems,
                                             LY_STMT_ANYDATA, &mod->data, YIN_SUBELEM_VER2,
                                             LY_STMT_ANYXML, &mod->data, 0,
@@ -3539,7 +3394,7 @@
                                             LY_STMT_EXTENSION_INSTANCE, NULL, 0
                                    ));
 
-    ret = yin_parse_content(ctx, subelems, 28, data, LY_STMT_MODULE, NULL, &mod->exts);
+    ret = yin_parse_content(ctx, subelems, 28, LY_STMT_MODULE, NULL, &mod->exts);
     subelems_deallocator(28, subelems);
     LY_CHECK_RET(ret);
 
@@ -3548,7 +3403,7 @@
 
     /* submodules share the namespace with the module names, so there must not be
      * a submodule of the same name in the context, no need for revision matching */
-    dup = ly_ctx_get_submodule(ctx->xml_ctx.ctx, NULL, mod->mod->name, NULL);
+    dup = ly_ctx_get_submodule(ctx->xmlctx->ctx, NULL, mod->mod->name, NULL);
     if (dup) {
         LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LYVE_SYNTAX_YANG, "Name collision between module and submodule of name \"%s\".", mod->mod->name);
         return LY_EVALID;
@@ -3558,13 +3413,14 @@
 }
 
 LY_ERR
-yin_parse_submod(struct yin_parser_ctx *ctx, struct yin_arg_record *mod_attrs, const char **data, struct lysp_submodule *submod)
+yin_parse_submod(struct lys_yin_parser_ctx *ctx, struct lysp_submodule *submod)
 {
     LY_ERR ret = LY_SUCCESS;
     struct yin_subelement *subelems = NULL;
     struct lysp_submodule *dup;
 
-    LY_CHECK_RET(yin_parse_attribute(ctx, mod_attrs, YIN_ARG_NAME, &submod->name, Y_IDENTIF_ARG, LY_STMT_SUBMODULE));
+    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
+    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &submod->name, Y_IDENTIF_ARG, LY_STMT_SUBMODULE));
     LY_CHECK_RET(subelems_allocator(ctx, 27, NULL, &subelems,
                                         LY_STMT_ANYDATA, &submod->data, YIN_SUBELEM_VER2,
                                         LY_STMT_ANYXML, &submod->data, 0,
@@ -3595,7 +3451,7 @@
                                         LY_STMT_EXTENSION_INSTANCE, NULL, 0
                                    ));
 
-    ret = yin_parse_content(ctx, subelems, 27, data, LY_STMT_SUBMODULE, NULL, &submod->exts);
+    ret = yin_parse_content(ctx, subelems, 27, LY_STMT_SUBMODULE, NULL, &submod->exts);
     subelems_deallocator(27, subelems);
     LY_CHECK_RET(ret);
 
@@ -3604,7 +3460,7 @@
 
     /* submodules share the namespace with the module names, so there must not be
      * a submodule of the same name in the context, no need for revision matching */
-    dup = ly_ctx_get_submodule(ctx->xml_ctx.ctx, NULL, submod->name, NULL);
+    dup = ly_ctx_get_submodule(ctx->xmlctx->ctx, NULL, submod->name, NULL);
     if (dup && strcmp(dup->belongsto, submod->belongsto)) {
         LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LYVE_SYNTAX_YANG, "Name collision between submodules of name \"%s\".", dup->name);
         return LY_EVALID;
@@ -3614,33 +3470,25 @@
 }
 
 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)
+yin_parse_submodule(struct lys_yin_parser_ctx **yin_ctx, struct ly_ctx *ctx, struct lys_parser_ctx *main_ctx, const char *data, struct lysp_submodule **submod)
 {
     enum ly_stmt kw = LY_STMT_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)->pos_type = LY_VLOG_LINE;
-    (*yin_ctx)->xml_ctx.line = 1;
+    (*yin_ctx)->format = LYS_IN_YIN;
+    LY_CHECK_RET(lyxml_ctx_new(ctx, data, &(*yin_ctx)->xmlctx));
 
     /* 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, LY_STMT_NONE);
-
+    kw = yin_match_keyword(*yin_ctx, (*yin_ctx)->xmlctx->name, (*yin_ctx)->xmlctx->name_len, (*yin_ctx)->xmlctx->prefix,
+                           (*yin_ctx)->xmlctx->prefix_len, LY_STMT_NONE);
     if (kw == LY_STMT_MODULE) {
         LOGERR(ctx, LY_EDENIED, "Input data contains module in situation when a submodule is expected.");
         ret = LY_EINVAL;
@@ -3655,12 +3503,12 @@
     LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(ctx), cleanup);
     mod_p->parsing = 1;
 
-    ret = yin_parse_submod(*yin_ctx, attrs, &data, mod_p);
+    ret = yin_parse_submod(*yin_ctx, mod_p);
     LY_CHECK_GOTO(ret, cleanup);
 
-    name = NULL;
     /* skip possible trailing whitespaces at end of the input */
-    while(*data && isspace(*data)) {
+    data = (*yin_ctx)->xmlctx->input;
+    while (*data && isspace(*data)) {
         data++;
     }
     if (*data) {
@@ -3678,34 +3526,25 @@
         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)
+yin_parse_module(struct lys_yin_parser_ctx **yin_ctx, const char *data, struct lys_module *mod)
 {
     LY_ERR ret = LY_SUCCESS;
     enum ly_stmt kw = LY_STMT_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)->pos_type = LY_VLOG_LINE;
-    (*yin_ctx)->xml_ctx.line = 1;
+    (*yin_ctx)->format = LYS_IN_YIN;
+    LY_CHECK_RET(lyxml_ctx_new(mod->ctx, data, &(*yin_ctx)->xmlctx));
 
     /* 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, LY_STMT_NONE);
+    kw = yin_match_keyword(*yin_ctx, (*yin_ctx)->xmlctx->name, (*yin_ctx)->xmlctx->name_len, (*yin_ctx)->xmlctx->prefix,
+                           (*yin_ctx)->xmlctx->prefix_len, LY_STMT_NONE);
     if (kw == LY_STMT_SUBMODULE) {
         LOGERR(mod->ctx, LY_EDENIED, "Input data contains submodule which cannot be parsed directly without its main module.");
         ret = LY_EINVAL;
@@ -3723,12 +3562,12 @@
     mod_p->parsing = 1;
 
     /* parse module substatements */
-    ret = yin_parse_mod(*yin_ctx, attrs, &data, mod_p);
+    ret = yin_parse_mod(*yin_ctx, mod_p);
     LY_CHECK_GOTO(ret, cleanup);
 
-    name = NULL;
     /* skip possible trailing whitespaces at end of the input */
-    while(*data && isspace(*data)) {
+    data = (*yin_ctx)->xmlctx->input;
+    while (*data && isspace(*data)) {
         data++;
     }
     if (*data) {
@@ -3746,6 +3585,5 @@
         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
index 7faf7e1..9905581 100644
--- a/src/parser_yin.h
+++ b/src/parser_yin.h
@@ -36,19 +36,6 @@
                       kw == LY_STMT_MUST || kw == LY_STMT_TYPE || kw == LY_STMT_UNIQUE ||         \
                       kw == LY_STMT_UNITS || kw == LY_STMT_EXTENSION_INSTANCE)
 
-/**
- * @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 */
@@ -63,19 +50,6 @@
     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 */
@@ -156,16 +130,14 @@
  * @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
  * @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, size_t subelem_info_size,
-                         const char **data, enum ly_stmt current_element, const char **text_content,
-                         struct lysp_ext_instance **exts);
+LY_ERR yin_parse_content(struct lys_yin_parser_ctx *ctx, struct yin_subelement *subelem_info, size_t subelem_info_size,
+                         enum ly_stmt current_element, const char **text_content, struct lysp_ext_instance **exts);
 
 /**
  * @brief Check that val is valid UTF8 character sequence of val_type.
@@ -173,12 +145,10 @@
  *
  * @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);
+LY_ERR yin_validate_value(struct lys_yin_parser_ctx *ctx, enum yang_arg val_type);
 
 /**
  * @brief Match yang keyword from yin data.
@@ -192,91 +162,52 @@
  *
  * @return yang_keyword values.
  */
-enum ly_stmt yin_match_keyword(struct yin_parser_ctx *ctx, const char *name, size_t name_len,
+enum ly_stmt yin_match_keyword(struct lys_yin_parser_ctx *ctx, const char *name, size_t name_len,
                                const char *prefix, size_t prefix_len, enum ly_stmt 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] name Name of the extension element.
- * @param[in] name_len Length of extension name.
- * @param[in] prefix Prefix of extension name.
- * @param[in] prefix_len Length of extension prefix.
  * @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, size_t ext_name_len, const char *ext_prefix, size_t ext_prefix_len,
-                                    LYEXT_SUBSTMT subelem, uint32_t subelem_index, struct lysp_ext_instance **exts);
+LY_ERR yin_parse_extension_instance(struct lys_yin_parser_ctx *ctx, 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] prefix Prefix of element.
- * @param[in] prefix_len Length of elements prefix.
+ * @param[in,out] ctx Yin parser context for XML context, logging, and to store current state.
  * @param[in] parent Identification of parent element.
- * @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 *prefix,
-                                 size_t prefix_len, enum ly_stmt parent, const char **data, struct lysp_stmt **element);
+LY_ERR yin_parse_element_generic(struct lys_yin_parser_ctx *ctx, enum ly_stmt parent, 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);
-
+LY_ERR yin_parse_mod(struct lys_yin_parser_ctx *ctx, 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);
+LY_ERR yin_parse_submod(struct lys_yin_parser_ctx *ctx, struct lysp_submodule *submod);
 
 #endif /* LY_PARSER_YIN_H_*/
diff --git a/src/tree_data.h b/src/tree_data.h
index c9a0a9d..aaeabf9 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -470,18 +470,6 @@
  * @{
  */
 
-#define LYD_OPT_DATA       0x0 /**< Default type of data - complete datastore content with configuration as well as
-                                    state data. */
-#define LYD_OPT_CONFIG     LYD_OPT_NO_STATE
-                                        /**< A configuration datastore - complete datastore without state data. */
-#define LYD_OPT_GET        LYD_OPT_PARSE_ONLY
-                                        /**< Data content from a NETCONF reply message to the NETCONF \<get\> operation. */
-#define LYD_OPT_GETCONFIG  LYD_OPT_PARSE_ONLY | LYD_OPT_NO_STATE
-                                        /**< Data content from a NETCONF reply message to the NETCONF \<get-config\> operation. */
-#define LYD_OPT_EDIT       LYD_OPT_OPAQ
-                                        /**< Data content of a NETCONF RPC \<edit-config\> operation. */
-
-
 #define LYD_OPT_PARSE_ONLY      0x0001  /**< Data will be only parsed and no validation will be performed. When statements
                                              are kept unevaluated, union types may not be fully resolved, if-feature
                                              statements are not checked, and default values are not added (only the ones
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index e319fb6..e064b06 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -271,13 +271,11 @@
  *
  * @param[in] ctx libyang context.
  * @param[in] data Pointer to the XML data to parse.
- * @param[out] tree Parsed RPC/action data tree.
- * @param[out] attr Any found attributes on the rpc envelope.
+ * @param[out] tree Parsed full RPC/action tree.
  * @param[out] op Pointer to the actual operation. Useful mainly for action.
  * @return LY_ERR value.
  */
-LY_ERR lyd_parse_xml_rpc(struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct ly_attr **attr,
-                         struct lyd_node **op);
+//LY_ERR lyd_parse_xml_rpc(struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **op);
 
 /**
  * @defgroup datahash Data nodes hash manipulation
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 6850e16..096de34 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -625,22 +625,24 @@
 
 struct lysp_submodule *
 lys_parse_mem_submodule(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, struct lys_parser_ctx *main_ctx,
-                        LY_ERR (*custom_check)(struct ly_ctx*, struct lysp_module*, struct lysp_submodule*, void*), void *check_data)
+                        LY_ERR (*custom_check)(const struct ly_ctx*, struct lysp_module*, struct lysp_submodule*, void*), void *check_data)
 {
     LY_ERR ret = LY_EINVAL;
     struct lysp_submodule *submod = NULL, *latest_sp;
-    struct lys_parser_ctx *context = NULL;
-    struct yin_parser_ctx *yin_context = NULL;
+    struct lys_yang_parser_ctx *yangctx = NULL;
+    struct lys_yin_parser_ctx *yinctx = NULL;
+    struct lys_parser_ctx *pctx;
 
     LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
 
     switch (format) {
     case LYS_IN_YIN:
-        ret = yin_parse_submodule(&yin_context, ctx, main_ctx, data, &submod);
-        context = (struct lys_parser_ctx *)yin_context;
+        ret = yin_parse_submodule(&yinctx, ctx, main_ctx, data, &submod);
+        pctx = (struct lys_parser_ctx *)yinctx;
         break;
     case LYS_IN_YANG:
-        ret = yang_parse_submodule(&context, ctx, main_ctx, data, &submod);
+        ret = yang_parse_submodule(&yangctx, ctx, main_ctx, data, &submod);
+        pctx = (struct lys_parser_ctx *)yangctx;
         break;
     default:
         LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
@@ -652,7 +654,7 @@
     lysp_sort_revisions(submod->revs);
 
     /* decide the latest revision */
-    latest_sp = ly_ctx_get_submodule((*context).ctx, submod->belongsto, submod->name, NULL);
+    latest_sp = ly_ctx_get_submodule(PARSER_CTX(pctx), submod->belongsto, submod->name, NULL);
     if (latest_sp) {
         if (submod->revs) {
             if (!latest_sp->revs) {
@@ -673,7 +675,7 @@
     }
 
     if (custom_check) {
-        LY_CHECK_GOTO(custom_check((*context).ctx, NULL, submod, check_data), error);
+        LY_CHECK_GOTO(custom_check(PARSER_CTX(pctx), NULL, submod, check_data), error);
     }
 
     if (latest_sp) {
@@ -681,29 +683,29 @@
     }
 
     /* 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, &pctx->tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
+    memcpy(&main_ctx->grps_nodes, &pctx->grps_nodes, sizeof main_ctx->grps_nodes);
 
     if (format == LYS_IN_YANG) {
-        lys_parser_ctx_free(context);
+        yang_parser_ctx_free(yangctx);
     } else {
-        yin_parser_ctx_free(yin_context);
+        yin_parser_ctx_free(yinctx);
     }
     return submod;
 
 error:
     lysp_submodule_free(ctx, submod);
     if (format == LYS_IN_YANG) {
-        lys_parser_ctx_free(context);
+        yang_parser_ctx_free(yangctx);
     } else {
-        yin_parser_ctx_free(yin_context);
+        yin_parser_ctx_free(yinctx);
     }
     return NULL;
 }
 
 struct lys_module *
 lys_parse_mem_module(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, int implement,
-                     LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
+                     LY_ERR (*custom_check)(const struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
                      void *check_data)
 {
     struct lys_module *mod = NULL, *latest, *mod_dup;
@@ -711,8 +713,9 @@
     struct lysp_include *inc;
     LY_ERR ret = LY_EINVAL;
     unsigned int u, i;
-    struct lys_parser_ctx *context = NULL;
-    struct yin_parser_ctx *yin_context = NULL;
+    struct lys_yang_parser_ctx *yangctx = NULL;
+    struct lys_yin_parser_ctx *yinctx = NULL;
+    struct lys_parser_ctx *pctx;
 
     LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
 
@@ -722,11 +725,12 @@
 
     switch (format) {
     case LYS_IN_YIN:
-        ret = yin_parse_module(&yin_context, data, mod);
-        context = (struct lys_parser_ctx *)yin_context;
+        ret = yin_parse_module(&yinctx, data, mod);
+        pctx = (struct lys_parser_ctx *)yinctx;
         break;
     case LYS_IN_YANG:
-        ret = yang_parse_module(&context, data, mod);
+        ret = yang_parse_module(&yangctx, data, mod);
+        pctx = (struct lys_parser_ctx *)yangctx;
         break;
     default:
         LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
@@ -828,7 +832,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(pctx, mod->parsed, inc)) {
             goto error_ctx;
         }
         if (!mod->implemented) {
@@ -839,12 +843,12 @@
     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(pctx, mod->parsed), error_ctx);
 
     if (format == LYS_IN_YANG) {
-        lys_parser_ctx_free(context);
+        yang_parser_ctx_free(yangctx);
     } else {
-        yin_parser_ctx_free(yin_context);
+        yin_parser_ctx_free(yinctx);
     }
     return mod;
 
@@ -852,11 +856,11 @@
     ly_set_rm(&ctx->list, mod, NULL);
 error:
     lys_module_free(mod, NULL);
-    ly_set_erase(&context->tpdfs_nodes, NULL);
+    ly_set_erase(&pctx->tpdfs_nodes, NULL);
     if (format == LYS_IN_YANG) {
-        lys_parser_ctx_free(context);
+        yang_parser_ctx_free(yangctx);
     } else {
-        yin_parser_ctx_free(yin_context);
+        yin_parser_ctx_free(yinctx);
     }
 
     return NULL;
@@ -901,8 +905,7 @@
 
 void *
 lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct lys_parser_ctx *main_ctx,
-                    LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
-                    void *check_data)
+              lys_custom_check custom_check, void *check_data)
 {
     void *result;
     struct lys_module *mod = NULL;
@@ -944,8 +947,7 @@
 }
 
 struct lys_module *
-lys_parse_fd_module(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement,
-                    LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
+lys_parse_fd_module(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, lys_custom_check custom_check,
                     void *check_data)
 {
     return (struct lys_module*)lys_parse_fd_(ctx, fd, format, implement, NULL, custom_check, check_data);
@@ -953,8 +955,7 @@
 
 struct lysp_submodule *
 lys_parse_fd_submodule(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, struct lys_parser_ctx *main_ctx,
-                       LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
-                       void *check_data)
+                       lys_custom_check custom_check, void *check_data)
 {
     assert(main_ctx);
     return (struct lysp_submodule*)lys_parse_fd_(ctx, fd, format, 0, main_ctx, custom_check, check_data);
@@ -968,7 +969,7 @@
 
 struct lys_module *
 lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, int implement,
-                LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data), void *check_data)
+                lys_custom_check custom_check, void *check_data)
 {
     int fd;
     struct lys_module *mod;
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index 171e5e4..4bb2bf5 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -953,7 +953,7 @@
 }
 
 void
-lys_parser_ctx_free(struct lys_parser_ctx *ctx)
+yang_parser_ctx_free(struct lys_yang_parser_ctx *ctx)
 {
     if (ctx) {
         free(ctx);
@@ -961,10 +961,10 @@
 }
 
 void
-yin_parser_ctx_free(struct yin_parser_ctx *ctx)
+yin_parser_ctx_free(struct lys_yin_parser_ctx *ctx)
 {
     if (ctx) {
-        lyxml_context_clear(&ctx->xml_ctx);
+        lyxml_ctx_free(ctx->xmlctx);
         free(ctx);
     }
 }
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 4c65540..b19990f 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -157,14 +157,12 @@
     struct lysp_import *i;
 
     if (module_prefix && &module_prefix != value && !strcmp(module_prefix, *value)) {
-        LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
-               "Prefix \"%s\" already used as module prefix.", *value);
+        LOGVAL_PARSER(ctx, LYVE_REFERENCE, "Prefix \"%s\" already used as module prefix.", *value);
         return LY_EEXIST;
     }
     LY_ARRAY_FOR(imports, struct lysp_import, i) {
         if (i->prefix && &i->prefix != value && !strcmp(i->prefix, *value)) {
-            LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Prefix \"%s\" already used to import \"%s\" module.",
-                   *value, i->name);
+            LOGVAL_PARSER(ctx, LYVE_REFERENCE, "Prefix \"%s\" already used to import \"%s\" module.", *value, i->name);
             return LY_EEXIST;
         }
     }
@@ -201,8 +199,8 @@
     struct tm tm, tm_;
     char *r;
 
-    LY_CHECK_ARG_RET(ctx ? ctx->ctx : NULL, date, LY_EINVAL);
-    LY_CHECK_ERR_RET(date_len != LY_REV_SIZE - 1, LOGARG(ctx ? ctx->ctx : NULL, date_len), LY_EINVAL);
+    LY_CHECK_ARG_RET(ctx ? PARSER_CTX(ctx) : NULL, date, LY_EINVAL);
+    LY_CHECK_ERR_RET(date_len != LY_REV_SIZE - 1, LOGARG(ctx ? PARSER_CTX(ctx) : NULL, date_len), LY_EINVAL);
 
     /* check format */
     for (i = 0; i < date_len; i++) {
@@ -234,7 +232,7 @@
 error:
     if (stmt) {
         if (ctx) {
-            LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LY_VCODE_INVAL, date_len, date, stmt);
+            LOGVAL_PARSER(ctx, LY_VCODE_INVAL, date_len, date, stmt);
         } else {
             LOGVAL(NULL, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, date_len, date, stmt);
         }
@@ -438,7 +436,7 @@
     } 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).",
+                LOGWRN(PARSER_CTX(ctx), "Control characters in enum name should be avoided (\"%.*s\", character number %d).",
                     name_len, name, u + 1);
                 break;
             }
@@ -448,7 +446,7 @@
     return LY_SUCCESS;
 }
 
-/*
+/**
  * @brief Check name of a new type to avoid name collisions.
  *
  * @param[in] ctx Parser context, module where the type is being defined is taken from here.
@@ -478,8 +476,7 @@
     name_len = strlen(name);
 
     if (lysp_type_str2builtin(name, name_len)) {
-        LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
-               "Invalid name \"%s\" of typedef - name collision with a built-in type.", name);
+        LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Invalid name \"%s\" of typedef - name collision with a built-in type.", name);
         return LY_EEXIST;
     }
 
@@ -491,16 +488,14 @@
                 break;
             }
             if (!strcmp(name, typedefs[u].name)) {
-                LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
-                       "Invalid name \"%s\" of typedef - name collision with sibling type.", name);
+                LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Invalid name \"%s\" of typedef - name collision with sibling type.", name);
                 return LY_EEXIST;
             }
         }
         /* search typedefs in parent's nodes */
         for (parent = node->parent; parent; parent = parent->parent) {
             if (lysp_type_match(name, parent)) {
-                LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
-                       "Invalid name \"%s\" of typedef - name collision with another scoped type.", name);
+                LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Invalid name \"%s\" of typedef - name collision with another scoped type.", name);
                 return LY_EEXIST;
             }
         }
@@ -511,14 +506,12 @@
     if (node) {
         lyht_insert(tpdfs_scoped, &name, hash, NULL);
         if (!lyht_find(tpdfs_global, &name, hash, NULL)) {
-            LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
-                   "Invalid name \"%s\" of typedef - scoped type collide with a top-level type.", name);
+            LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Invalid name \"%s\" of typedef - scoped type collide with a top-level type.", name);
             return LY_EEXIST;
         }
     } else {
         if (lyht_insert(tpdfs_global, &name, hash, NULL)) {
-            LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
-                   "Invalid name \"%s\" of typedef - name collision with another top-level type.", name);
+            LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Invalid name \"%s\" of typedef - name collision with another top-level type.", name);
             return LY_EEXIST;
         }
         /* it is not necessary to test collision with the scoped types - in lysp_check_typedefs, all the
@@ -675,7 +668,7 @@
 };
 
 static LY_ERR
-lysp_load_module_check(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data)
+lysp_load_module_check(const struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data)
 {
     struct lysp_load_module_check_data *info = data;
     const char *filename, *dot, *rev, *name;
@@ -960,8 +953,9 @@
 }
 
 LY_ERR
-lysp_load_submodule(struct lys_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
+lysp_load_submodule(struct lys_parser_ctx *pctx, struct lysp_module *mod, struct lysp_include *inc)
 {
+    struct ly_ctx *ctx = (struct ly_ctx *)(PARSER_CTX(pctx));
     struct lysp_submodule *submod = NULL;
     const char *submodule_data = NULL;
     LYS_INFORMAT format = LYS_IN_UNKNOWN;
@@ -969,31 +963,31 @@
     struct lysp_load_module_check_data check_data = {0};
 
     /* submodule not present in the context, get the input data and parse it */
-    if (!(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+    if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
 search_clb:
-        if (ctx->ctx->imp_clb) {
-            if (ctx->ctx->imp_clb(mod->mod->name, NULL, inc->name, inc->rev[0] ? inc->rev : NULL, ctx->ctx->imp_clb_data,
+        if (ctx->imp_clb) {
+            if (ctx->imp_clb(mod->mod->name, NULL, inc->name, inc->rev[0] ? inc->rev : NULL, ctx->imp_clb_data,
                                   &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
                 check_data.name = inc->name;
                 check_data.revision = inc->rev[0] ? inc->rev : NULL;
                 check_data.submoduleof = mod->mod->name;
-                submod = lys_parse_mem_submodule(ctx->ctx, submodule_data, format, ctx,
+                submod = lys_parse_mem_submodule(ctx, submodule_data, format, pctx,
                                                  lysp_load_module_check, &check_data);
                 if (submodule_data_free) {
-                    submodule_data_free((void*)submodule_data, ctx->ctx->imp_clb_data);
+                    submodule_data_free((void*)submodule_data, ctx->imp_clb_data);
                 }
             }
         }
-        if (!submod && !(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+        if (!submod && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
             goto search_file;
         }
     } else {
 search_file:
-        if (!(ctx->ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
+        if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
             /* submodule was not received from the callback or there is no callback set */
-            lys_module_localfile(ctx->ctx, inc->name, inc->rev[0] ? inc->rev : NULL, 0, ctx, mod->mod->name, 1, (void**)&submod);
+            lys_module_localfile(ctx, inc->name, inc->rev[0] ? inc->rev : NULL, 0, pctx, mod->mod->name, 1, (void**)&submod);
         }
-        if (!submod && (ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+        if (!submod && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
             goto search_clb;
         }
     }
@@ -1007,7 +1001,7 @@
         inc->submodule = submod;
     }
     if (!inc->submodule) {
-        LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.",
+        LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.",
                inc->name, mod->mod->name);
         return LY_EVALID;
     }
@@ -1426,7 +1420,7 @@
 }
 
 enum ly_stmt
-lysp_match_kw(struct lys_parser_ctx *ctx, const char **data)
+lysp_match_kw(struct lys_yang_parser_ctx *ctx, const char **data)
 {
 /**
  * @brief Move the DATA pointer by COUNT items. Also updates the indent value in yang parser context
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 9b927e0..71b673d 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -24,8 +24,6 @@
 
 #define YIN_NS_URI "urn:ietf:params:xml:ns:yang:yin:1"
 
-#define LOGVAL_PARSER(CTX, ...) LOGVAL((CTX)->ctx, (CTX)->pos_type, (CTX)->pos_type == LY_VLOG_LINE ? &(CTX)->line : (void*)(CTX)->path, __VA_ARGS__)
-
 /**
  * @brief Check module version is at least 2 (YANG 1.1) because of the keyword presence.
  * Logs error message and returns LY_EVALID in case of module in YANG version 1.0.
@@ -73,9 +71,9 @@
         } \
     }
 
-#define YANG_CHECK_NONEMPTY(CTX, VALUE_LEN, STMT) \
+#define CHECK_NONEMPTY(CTX, VALUE_LEN, STMT) \
     if (!VALUE_LEN) { \
-        LOGWRN((CTX)->ctx, "Empty argument of %s statement does not make sense.", STMT); \
+        LOGWRN(PARSER_CTX(CTX), "Empty argument of %s statement does not make sense.", STMT); \
     }
 
 /**
@@ -99,10 +97,30 @@
     Y_MAYBE_STR_ARG       /**< optional YANG "string" rule */
 };
 
+#define PARSER_CTX(CTX) (CTX)->format == LYS_IN_YANG ? ((struct lys_yang_parser_ctx *)CTX)->ctx : ((struct lys_yin_parser_ctx *)CTX)->xmlctx->ctx
+
+#define LOGVAL_PARSER(CTX, ...) (CTX)->format == LYS_IN_YANG ? LOGVAL_YANG(CTX, __VA_ARGS__) : LOGVAL_YIN(CTX, __VA_ARGS__)
+
+#define LOGVAL_YANG(CTX, ...) LOGVAL(PARSER_CTX(CTX), ((struct lys_yang_parser_ctx *)CTX)->pos_type, \
+                                     ((struct lys_yang_parser_ctx *)CTX)->pos_type == LY_VLOG_LINE ? \
+                                        (void *)&((struct lys_yang_parser_ctx *)CTX)->line : \
+                                        (void *)((struct lys_yang_parser_ctx *)CTX)->path, __VA_ARGS__)
+
+#define LOGVAL_YIN(CTX, ...) LOGVAL(PARSER_CTX(CTX), LY_VLOG_LINE, \
+                                     &((struct lys_yin_parser_ctx *)CTX)->xmlctx->line, __VA_ARGS__)
+
+struct lys_parser_ctx {
+    LYS_INFORMAT format;        /**< parser format */
+    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 */
+};
+
 /**
  * @brief Internal context for yang schema parser.
  */
-struct lys_parser_ctx {
+struct lys_yang_parser_ctx {
+    LYS_INFORMAT format;        /**< parser format */
     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 */
@@ -118,17 +136,17 @@
 /**
  * @brief free lys parser context.
  */
-void lys_parser_ctx_free(struct lys_parser_ctx *ctx);
+void yang_parser_ctx_free(struct lys_yang_parser_ctx *ctx);
 
 /**
  * @brief Internal context for yin schema parser.
  */
-struct yin_parser_ctx {
+struct lys_yin_parser_ctx {
+    LYS_INFORMAT format;           /**< parser format */
     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 */
-    enum LY_VLOG_ELEM pos_type; /**< */
-    struct lyxml_context xml_ctx;  /**< context for xml parser */
+    struct lyxml_ctx *xmlctx;      /**< context for xml parser */
 };
 
 /**
@@ -136,7 +154,7 @@
  *
  * @param[in] ctx Context to free.
  */
-void yin_parser_ctx_free(struct yin_parser_ctx *ctx);
+void yin_parser_ctx_free(struct lys_yin_parser_ctx *ctx);
 
 struct lysc_incomplete_dflt {
     struct lyd_value *dflt;
@@ -147,7 +165,7 @@
 /**
  * @brief Check that \p c is valid UTF8 code point for YANG string.
  *
- * @param[in] ctx yang parser context for logging.
+ * @param[in] ctx parser context for logging.
  * @param[in] c UTF8 code point of a character to check.
  * @return LY_ERR values.
  */
@@ -156,7 +174,7 @@
 /**
  * @brief Check that \p c is valid UTF8 code point for YANG identifier.
  *
- * @param[in] ctx yang parser context for logging.
+ * @param[in] ctx 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:
@@ -296,7 +314,7 @@
  * submodule is stored into this structure.
  * @return LY_ERR value.
  */
-LY_ERR lysp_load_submodule(struct lys_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc);
+LY_ERR lysp_load_submodule(struct lys_parser_ctx *pctx, struct lysp_module *mod, struct lysp_include *inc);
 
 /**
  * @brief Compile printable schema into a validated schema linking all the references.
@@ -480,8 +498,10 @@
  */
 const char *lys_datatype2str(LY_DATA_TYPE basetype);
 
+typedef LY_ERR (*lys_custom_check)(const struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *check_data);
+
 /**
- * @brief Parse YANG module from a string.
+ * @brief Parse module from a string.
  *
  * The modules are added into the context and the latest_revision flag is updated.
  *
@@ -495,11 +515,10 @@
  * @return Pointer to the data model structure or NULL on error.
  */
 struct lys_module *lys_parse_mem_module(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, int implement,
-                                        LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *check_data),
-                                        void *check_data);
+                                        lys_custom_check custom_check, void *check_data);
 
 /**
- * @brief Parse YANG submodule from a string.
+ * @brief Parse submodule from a string.
  *
  * The latest_revision flag of submodule is updated.
  *
@@ -513,11 +532,10 @@
  * @return Pointer to the data model structure or NULL on error.
  */
 struct lysp_submodule *lys_parse_mem_submodule(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, struct lys_parser_ctx *main_ctx,
-                                               LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *check_data),
-                                               void *check_data);
+                                               lys_custom_check custom_check, void *check_data);
 
 /**
- * @brief Parse YANG module or submodule from a file descriptor.
+ * @brief Parse module or submodule from a file descriptor.
  *
  * The modules are added into the context, submodules not. The latest_revision flag is updated in both cases.
  *
@@ -535,8 +553,7 @@
  * @return Pointer to the data model structure or NULL on error.
  */
 void *lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct lys_parser_ctx *main_ctx,
-                    LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
-                    void *check_data);
+                    lys_custom_check custom_check, void *check_data);
 
 /**
  * @brief Parse YANG module from a file descriptor.
@@ -555,11 +572,10 @@
  * @return Pointer to the data model structure or NULL on error.
  */
 struct lys_module *lys_parse_fd_module(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement,
-                                           LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *check_data),
-                                           void *check_data);
+                                       lys_custom_check custom_check, void *check_data);
 
 /**
- * @brief Parse YANG submodule from a file descriptor.
+ * @brief Parse submodule from a file descriptor.
  *
  * The latest_revision flag of submodules is updated.
  *
@@ -575,8 +591,7 @@
  * @return Pointer to the data model structure or NULL on error.
  */
 struct lysp_submodule *lys_parse_fd_submodule(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, struct lys_parser_ctx *main_ctx,
-                                              LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *check_data),
-                                              void *check_data);
+                                              lys_custom_check custom_check, void *check_data);
 
 /**
  * @brief Parse YANG module from a filepath.
@@ -594,8 +609,7 @@
  * @return Pointer to the data model structure or NULL on error.
  */
 struct lys_module *lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, int implement,
-                                   LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
-                                   void *check_data);
+                                   lys_custom_check custom_check, void *check_data);
 
 /**
  * @brief Load the (sub)module into the context.
@@ -812,7 +826,7 @@
  * @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 **context, struct ly_ctx *ly_ctx, struct lys_parser_ctx *main_ctx,
+LY_ERR yang_parse_submodule(struct lys_yang_parser_ctx **context, struct ly_ctx *ly_ctx, struct lys_parser_ctx *main_ctx,
                             const char *data, struct lysp_submodule **submod);
 
 /**
@@ -823,7 +837,7 @@
  * 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 **context, const char *data, struct lys_module *mod);
+LY_ERR yang_parse_module(struct lys_yang_parser_ctx **context, const char *data, struct lys_module *mod);
 
 /**
  * @brief Parse module from YIN data.
@@ -835,7 +849,7 @@
  *
  * @return LY_ERR values.
  */
-LY_ERR yin_parse_module(struct yin_parser_ctx **yin_ctx, const char *data, struct lys_module *mod);
+LY_ERR yin_parse_module(struct lys_yin_parser_ctx **yin_ctx, const char *data, struct lys_module *mod);
 
 /**
  * @brief Parse submodule from YIN data.
@@ -847,7 +861,7 @@
  * @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,
+LY_ERR yin_parse_submodule(struct lys_yin_parser_ctx **yin_ctx, struct ly_ctx *ctx, struct lys_parser_ctx *main_ctx,
                            const char *data, struct lysp_submodule **submod);
 
 
@@ -868,7 +882,7 @@
  * @param[in,out] data Data to read from, always moved to currently handled character.
  * @return yang_keyword values.
  */
-enum ly_stmt lysp_match_kw(struct lys_parser_ctx *ctx, const char **data);
+enum ly_stmt lysp_match_kw(struct lys_yang_parser_ctx *ctx, const char **data);
 
 /**
  * @brief Generate path of the given node in the requested format.
diff --git a/src/xml.c b/src/xml.c
index d4b8a9e..8a9a3da 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -1,6 +1,7 @@
 /**
  * @file xml.c
  * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief Generic XML parser implementation for libyang
  *
  * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
@@ -24,11 +25,14 @@
 #include "xml.h"
 #include "printer_internal.h"
 
-/* Move input p by s characters, if EOF log with lyxml_context c */
-#define move_input(c,p,s) p += s; LY_CHECK_ERR_RET(!p[0], LOGVAL(c->ctx, LY_VLOG_LINE, &c->line, LY_VCODE_EOF), LY_EVALID)
+/* Move input p by s characters, if EOF log with lyxml_ctx c */
+#define move_input(c,s) c->input += s; LY_CHECK_ERR_RET(!c->input[0], LOGVAL(c->ctx, LY_VLOG_LINE, &c->line, LY_VCODE_EOF), LY_EVALID)
 
 /* Ignore whitespaces in the input string p */
-#define ign_xmlws(c,p) while (is_xmlws(*(p))) {if (*(p) == '\n') {++c->line;} ++p;}
+#define ign_xmlws(c) while (is_xmlws(*(c)->input)) {if (*(c)->input == '\n') {++c->line;} ++c->input;}
+
+static LY_ERR lyxml_next_attr_content(struct lyxml_ctx *xmlctx, const char **value, size_t *value_len, int *ws_only,
+                                      int *dynamic);
 
 /**
  * @brief Ignore any characters until the delim of the size delim_len is read
@@ -66,6 +70,257 @@
 }
 
 /**
+ * @brief Check/Get an XML identifier from the input string.
+ *
+ * The identifier must have at least one valid character complying the name start character constraints.
+ * The identifier is terminated by the first character, which does not comply to the name character constraints.
+ *
+ * See https://www.w3.org/TR/xml-names/#NT-NCName
+ *
+ * @param[in] xmlctx XML context.
+ * @param[out] start Pointer to the start of the identifier.
+ * @param[out] end Pointer ot the end of the identifier.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyxml_parse_identifier(struct lyxml_ctx *xmlctx, const char **start, const char **end)
+{
+    const char *s, *in;
+    uint32_t c;
+    size_t parsed;
+    LY_ERR rc;
+
+    in = s = xmlctx->input;
+
+    /* check NameStartChar (minus colon) */
+    LY_CHECK_ERR_RET(ly_getutf8(&in, &c, &parsed),
+                     LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_INCHAR, in[0]),
+                     LY_EVALID);
+    LY_CHECK_ERR_RET(!is_xmlqnamestartchar(c),
+                     LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX,
+                            "Identifier \"%s\" starts with an invalid character.", in - parsed),
+                     LY_EVALID);
+
+    /* check rest of the identifier */
+    do {
+        /* move only successfully parsed bytes */
+        xmlctx->input += parsed;
+
+        rc = ly_getutf8(&in, &c, &parsed);
+        LY_CHECK_ERR_RET(rc, LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_INCHAR, in[0]), LY_EVALID);
+    } while (is_xmlqnamechar(c));
+
+    *start = s;
+    *end = xmlctx->input;
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Add namespace definition into XML context.
+ *
+ * Namespaces from a single element are supposed to be added sequentially together (not interleaved by a namespace from other
+ * element). This mimic namespace visibility, since the namespace defined in element E is not visible from its parents or
+ * siblings. On the other hand, namespace from a parent element can be redefined in a child element. This is also reflected
+ * by lyxml_ns_get() which returns the most recent namespace definition for the given prefix.
+ *
+ * When leaving processing of a subtree of some element (after it is removed from xmlctx->elements), caller is supposed to call
+ * lyxml_ns_rm() to remove all the namespaces defined in such an element from the context.
+ *
+ * @param[in] xmlctx XML context to work with.
+ * @param[in] prefix Pointer to the namespace prefix. Can be NULL for default namespace.
+ * @param[in] prefix_len Length of the prefix.
+ * @param[in] uri Namespace URI (value) to store directly. Value is always spent.
+ * @return LY_ERR values.
+ */
+LY_ERR
+lyxml_ns_add(struct lyxml_ctx *xmlctx, const char *prefix, size_t prefix_len, char *uri)
+{
+    struct lyxml_ns *ns;
+
+    ns = malloc(sizeof *ns);
+    LY_CHECK_ERR_RET(!ns, LOGMEM(xmlctx->ctx), LY_EMEM);
+
+    /* we need to connect the depth of the element where the namespace is defined with the
+     * namespace record to be able to maintain (remove) the record when the parser leaves
+     * (to its sibling or back to the parent) the element where the namespace was defined */
+    ns->depth = xmlctx->elements.count;
+
+    ns->uri = uri;
+    if (prefix) {
+        ns->prefix = strndup(prefix, prefix_len);
+        LY_CHECK_ERR_RET(!ns->prefix, LOGMEM(xmlctx->ctx); free(ns->uri); free(ns), LY_EMEM);
+    } else {
+        ns->prefix = NULL;
+    }
+
+    LY_CHECK_ERR_RET(ly_set_add(&xmlctx->ns, ns, LY_SET_OPT_USEASLIST) == -1,
+                     free(ns->prefix); free(ns->uri); free(ns), LY_EMEM);
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Remove all the namespaces defined in the element recently closed (removed from the xmlctx->elements).
+ *
+ * @param[in] xmlctx XML context to work with.
+ */
+void
+lyxml_ns_rm(struct lyxml_ctx *xmlctx)
+{
+    unsigned int u;
+
+    for (u = xmlctx->ns.count - 1; u + 1 > 0; --u) {
+        if (((struct lyxml_ns *)xmlctx->ns.objs[u])->depth != xmlctx->elements.count + 1) {
+            /* we are done, the namespaces from a single element are supposed to be together */
+            break;
+        }
+        /* remove the ns structure */
+        free(((struct lyxml_ns *)xmlctx->ns.objs[u])->prefix);
+        free(((struct lyxml_ns *)xmlctx->ns.objs[u])->uri);
+        free(xmlctx->ns.objs[u]);
+        --xmlctx->ns.count;
+    }
+
+    if (!xmlctx->ns.count) {
+        /* cleanup the xmlctx's namespaces storage */
+        ly_set_erase(&xmlctx->ns, NULL);
+    }
+}
+
+void *
+lyxml_elem_dup(void *item)
+{
+    struct lyxml_elem *dup;
+
+    dup = malloc(sizeof *dup);
+    memcpy(dup, item, sizeof *dup);
+
+    return dup;
+}
+
+void *
+lyxml_ns_dup(void *item)
+{
+    struct lyxml_ns *dup, *orig;
+
+    orig = (struct lyxml_ns *)item;
+    dup = malloc(sizeof *dup);
+    dup->prefix = orig->prefix ? strdup(orig->prefix) : NULL;
+    dup->uri = strdup(orig->uri);
+    dup->depth = orig->depth;
+
+    return dup;
+}
+
+const struct lyxml_ns *
+lyxml_ns_get(struct lyxml_ctx *xmlctx, const char *prefix, size_t prefix_len)
+{
+    unsigned int u;
+    struct lyxml_ns *ns;
+
+    for (u = xmlctx->ns.count - 1; u + 1 > 0; --u) {
+        ns = (struct lyxml_ns *)xmlctx->ns.objs[u];
+        if (prefix && prefix_len) {
+            if (ns->prefix && !ly_strncmp(ns->prefix, prefix, prefix_len)) {
+                return ns;
+            }
+        } else if (!ns->prefix) {
+            /* default namespace */
+            return ns;
+        }
+    }
+
+    return NULL;
+}
+
+static LY_ERR
+lyxml_skip_until_end_or_after_otag(struct lyxml_ctx *xmlctx)
+{
+    const struct ly_ctx *ctx = xmlctx->ctx; /* shortcut */
+    const char *in, *endtag, *sectname;
+    size_t endtag_len, newlines;
+
+    while (1) {
+        ign_xmlws(xmlctx);
+
+        if (xmlctx->input[0] == '\0') {
+            /* EOF */
+            if (xmlctx->elements.count) {
+                LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_EOF);
+                return LY_EVALID;
+            }
+            return LY_SUCCESS;
+        } else if (xmlctx->input[0] != '<') {
+            LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(xmlctx->input),
+                   xmlctx->input, "element tag start ('<')");
+            return LY_EVALID;
+        }
+        move_input(xmlctx, 1);
+
+        if (xmlctx->input[0] == '!') {
+            move_input(xmlctx, 1);
+            /* sections to ignore */
+            if (!strncmp(xmlctx->input, "--", 2)) {
+                /* comment */
+                move_input(xmlctx, 2);
+                sectname = "Comment";
+                endtag = "-->";
+                endtag_len = 3;
+            } else if (!strncmp(xmlctx->input, "[CDATA[", 7)) {
+                /* CDATA section */
+                move_input(xmlctx, 7);
+                sectname = "CData";
+                endtag = "]]>";
+                endtag_len = 3;
+            } else if (!strncmp(xmlctx->input, "DOCTYPE", 7)) {
+                /* Document type declaration - not supported */
+                LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_NSUPP, "Document Type Declaration");
+                return LY_EVALID;
+            } else {
+                LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unknown XML section \"%.20s\".", &xmlctx->input[-2]);
+                return LY_EVALID;
+            }
+            in = ign_todelim(xmlctx->input, endtag, endtag_len, &newlines);
+            LY_CHECK_ERR_RET(!in, LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_NTERM, sectname), LY_EVALID);
+            xmlctx->line += newlines;
+            xmlctx->input = in + endtag_len;
+        } else if (xmlctx->input[0] == '?') {
+            in = ign_todelim(xmlctx->input, "?>", 2, &newlines);
+            LY_CHECK_ERR_RET(!in, LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_NTERM, "Declaration"), LY_EVALID);
+            xmlctx->line += newlines;
+            xmlctx->input = in + 2;
+        } else {
+            /* other non-WS character */
+            break;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+static LY_ERR
+lyxml_parse_qname(struct lyxml_ctx *xmlctx, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len)
+{
+    const char *start, *end;
+
+    *prefix = NULL;
+    *prefix_len = 0;
+
+    LY_CHECK_RET(lyxml_parse_identifier(xmlctx, &start, &end));
+    if (end[0] == ':') {
+        /* we have prefixed identifier */
+        *prefix = start;
+        *prefix_len = end - start;
+
+        move_input(xmlctx, 1);
+        LY_CHECK_RET(lyxml_parse_identifier(xmlctx, &start, &end));
+    }
+
+    *name = start;
+    *name_len = end - start;
+    return LY_SUCCESS;
+}
+
+/**
  * Store UTF-8 character specified as 4byte integer into the dst buffer.
  * Returns number of written bytes (4 max), expects that dst has enough space.
  *
@@ -128,561 +383,85 @@
     return LY_SUCCESS;
 }
 
-/**
- * @brief Check/Get an XML qualified name from the input string.
- *
- * The identifier must have at least one valid character complying the name start character constraints.
- * The identifier is terminated by the first character, which does not comply to the name character constraints.
- *
- * See https://www.w3.org/TR/xml-names/#NT-NCName
- *
- * @param[in] context XML context to track lines or store errors into libyang context.
- * @param[in,out] input Input string to process, updated according to the processed/read data.
- * Note that the term_char is also read, so input points after the term_char at the end.
- * @param[out] term_char The first character in the input string which does not compy to the name constraints.
- * @param[out] term_char_len Number of bytes used to encode UTF8 term_char. Serves to be able to go back in input string.
- * @return LY_ERR value.
- */
 static LY_ERR
-lyxml_check_qname(struct lyxml_context *context, const char **input, unsigned int *term_char, size_t *term_char_len)
+lyxml_parse_value(struct lyxml_ctx *xmlctx, char endchar, char **value, size_t *length, int *ws_only, int *dynamic)
 {
-    unsigned int c;
-    const char *id = (*input);
-    LY_ERR rc;
+#define BUFSIZE 24
+#define BUFSIZE_STEP 128
 
-    /* check NameStartChar (minus colon) */
-    LY_CHECK_ERR_RET(ly_getutf8(input, &c, NULL) != LY_SUCCESS,
-                     LOGVAL(context->ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INCHAR, (*input)[0]), LY_EVALID);
-    LY_CHECK_ERR_RET(!is_xmlqnamestartchar(c),
-                     LOGVAL(context->ctx, LY_VLOG_LINE, &context->line, LYVE_SYNTAX,
-                            "Identifier \"%s\" starts with invalid character.", id),
-                     LY_EVALID);
-
-    /* check rest of the identifier */
-    for (rc = ly_getutf8(input, &c, term_char_len);
-         rc == LY_SUCCESS && is_xmlqnamechar(c);
-         rc = ly_getutf8(input, &c, term_char_len));
-    LY_CHECK_ERR_RET(rc != LY_SUCCESS, LOGVAL(context->ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INCHAR, (*input)[0]), LY_EVALID);
-
-    (*term_char) = c;
-    return LY_SUCCESS;
-}
-
-/**
- * @brief Add namespace definition into XML context.
- *
- * Namespaces from a single element are supposed to be added sequentially together (not interleaved by a namespace from other
- * element). This mimic namespace visibility, since the namespace defined in element E is not visible from its parents or
- * siblings. On the other hand, namespace from a parent element can be redefined in a child element. This is also reflected
- * by lyxml_ns_get() which returns the most recent namespace definition for the given prefix.
- *
- * When leaving processing of a subtree of some element (after it is removed from context->elements), caller is supposed to call
- * lyxml_ns_rm() to remove all the namespaces defined in such an element from the context.
- *
- * @param[in] context XML context to work with.
- * @param[in] prefix Pointer to the namespace prefix as taken from lyxml_get_attribute(). Can be NULL for default namespace.
- * @param[in] prefix_len Length of the prefix string (since it is not NULL-terminated when returned from lyxml_get_attribute()).
- * @param[in] uri Namespace URI (value) to store. Value can be obtained via lyxml_get_string() and caller is not supposed to
- * work with the pointer when the function succeeds. In case of error the value is freed.
- * @return LY_ERR values.
- */
-LY_ERR
-lyxml_ns_add(struct lyxml_context *context, const char *prefix, size_t prefix_len, char *uri)
-{
-    struct lyxml_ns *ns;
-
-    ns = malloc(sizeof *ns);
-    LY_CHECK_ERR_RET(!ns, LOGMEM(context->ctx), LY_EMEM);
-
-    /* we need to connect the depth of the element where the namespace is defined with the
-     * namespace record to be able to maintain (remove) the record when the parser leaves
-     * (to its sibling or back to the parent) the element where the namespace was defined */
-    ns->depth = context->elements.count;
-
-    ns->uri = uri;
-    if (prefix) {
-        ns->prefix = strndup(prefix, prefix_len);
-        LY_CHECK_ERR_RET(!ns->prefix, LOGMEM(context->ctx); free(ns->uri); free(ns), LY_EMEM);
-    } else {
-        ns->prefix = NULL;
-    }
-
-    LY_CHECK_ERR_RET(ly_set_add(&context->ns, ns, LY_SET_OPT_USEASLIST) == -1,
-                     free(ns->prefix); free(ns->uri); free(ns), LY_EMEM);
-    return LY_SUCCESS;
-}
-
-/**
- * @brief Remove all the namespaces defined in the element recently closed (removed from the context->elements).
- *
- * @param[in] context XML context to work with.
- */
-void
-lyxml_ns_rm(struct lyxml_context *context)
-{
-    unsigned int u;
-
-    for (u = context->ns.count - 1; u + 1 > 0; --u) {
-        if (((struct lyxml_ns *)context->ns.objs[u])->depth != context->elements.count + 1) {
-            /* we are done, the namespaces from a single element are supposed to be together */
-            break;
-        }
-        /* remove the ns structure */
-        free(((struct lyxml_ns *)context->ns.objs[u])->prefix);
-        free(((struct lyxml_ns *)context->ns.objs[u])->uri);
-        free(context->ns.objs[u]);
-        --context->ns.count;
-    }
-
-    if (!context->ns.count) {
-        /* cleanup the context's namespaces storage */
-        ly_set_erase(&context->ns, NULL);
-    }
-}
-
-void *
-lyxml_elem_dup(void *item)
-{
-    struct lyxml_elem *dup;
-
-    dup = malloc(sizeof *dup);
-    memcpy(dup, item, sizeof *dup);
-
-    return dup;
-}
-
-void *
-lyxml_ns_dup(void *item)
-{
-    struct lyxml_ns *dup, *orig;
-
-    orig = (struct lyxml_ns *)item;
-    dup = malloc(sizeof *dup);
-    dup->prefix = orig->prefix ? strdup(orig->prefix) : NULL;
-    dup->uri = strdup(orig->uri);
-    dup->depth = orig->depth;
-
-    return dup;
-}
-
-const struct lyxml_ns *
-lyxml_ns_get(struct lyxml_context *context, const char *prefix, size_t prefix_len)
-{
-    unsigned int u;
-    struct lyxml_ns *ns;
-
-    for (u = context->ns.count - 1; u + 1 > 0; --u) {
-        ns = (struct lyxml_ns *)context->ns.objs[u];
-        if (prefix && prefix_len) {
-            if (ns->prefix && !ly_strncmp(ns->prefix, prefix, prefix_len)) {
-                return ns;
-            }
-        } else if (!ns->prefix) {
-            /* default namespace */
-            return ns;
-        }
-    }
-
-    return NULL;
-}
-
-static LY_ERR
-lyxml_parse_element_start(struct lyxml_context *context, const char **input, int *closing)
-{
-    struct ly_ctx *ctx = context->ctx; /* shortcut */
-    const char *in = (*input);
-    const char *endtag;
-    const char *sectname;
-    size_t endtag_len, newlines;
-
-    while (1) {
-        ign_xmlws(context, in);
-
-        if (in[0] == '\0') {
-            /* EOF */
-            if (context->elements.count) {
-                LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_EOF);
-                return LY_EVALID;
-            }
-            context->status = LYXML_END;
-            (*input) = in;
-            return LY_SUCCESS;
-        } else if (in[0] != '<') {
-            return LY_EINVAL;
-        }
-        move_input(context, in, 1);
-
-        if (in[0] == '!') {
-            move_input(context, in, 1);
-            /* sections to ignore */
-            if (!strncmp(in, "--", 2)) {
-                /* comment */
-                move_input(context, in, 2);
-                sectname = "Comment";
-                endtag = "-->";
-                endtag_len = 3;
-            } else if (!strncmp(in, "[CDATA[", 7)) {
-                /* CDATA section */
-                move_input(context, in, 7);
-                sectname = "CData";
-                endtag = "]]>";
-                endtag_len = 3;
-            } else if (!strncmp(in, "DOCTYPE", 7)) {
-                /* Document type declaration - not supported */
-                LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_NSUPP, "Document Type Declaration");
-                return LY_EVALID;
-            } else {
-                LOGVAL(ctx, LY_VLOG_LINE, &context->line, LYVE_SYNTAX, "Unknown XML section \"%.20s\".", &in[-2]);
-                return LY_EVALID;
-            }
-            in = ign_todelim(in, endtag, endtag_len, &newlines);
-            LY_CHECK_ERR_RET(!in, LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_NTERM, sectname), LY_EVALID);
-            context->line += newlines;
-            in += endtag_len;
-        } else if (in[0] == '?') {
-            in = ign_todelim(in, "?>", 2, &newlines);
-            LY_CHECK_ERR_RET(!in, LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_NTERM, "Declaration"), LY_EVALID);
-            context->line += newlines;
-            in += 2;
-        } else if (in[0] == '/') {
-            /* closing element tag */
-            *closing = 1;
-            ++in;
-            goto element;
-        } else {
-            /* opening element tag */
-            *closing = 0;
-element:
-            ign_xmlws(context, in);
-            LY_CHECK_ERR_RET(!in[0], LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_EOF), LY_EVALID);
-
-            (*input) = in;
-            return LY_SUCCESS;
-        }
-    }
-}
-
-static LY_ERR
-lyxml_parse_element_name(struct lyxml_context *context, const char **input, size_t *endtag_len, unsigned int *term_char,
-                         const char **prefix, size_t *prefix_len, const char **name, size_t *name_len)
-{
-    LY_ERR rc;
-    const char *in = (*input);
-    const char *id;
-    const char *endtag;
-
-    id = in;
-    rc = lyxml_check_qname(context, &in, term_char, endtag_len);
-    LY_CHECK_RET(rc);
-    if (*term_char == ':') {
-        /* we have prefixed identifier */
-        endtag = in - *endtag_len;
-
-        rc = lyxml_check_qname(context, &in, term_char, endtag_len);
-        LY_CHECK_RET(rc);
-
-        (*prefix) = id;
-        (*prefix_len) = endtag - id;
-        id = endtag + 1;
-    }
-    if (!is_xmlws(*term_char) && *term_char != '/' && *term_char != '>') {
-        (*input) = in - *endtag_len;
-        LOGVAL(context->ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(*input), *input,
-               "whitespace or element tag termination ('>' or '/>'");
-        return LY_EVALID;
-    }
-    (*name) = id;
-    (*name_len) = in - *endtag_len - id;
-
-    if (is_xmlws(*term_char)) {
-        /* go to the next meaningful input */
-        ign_xmlws(context, in);
-        LY_CHECK_ERR_RET(!in[0], LOGVAL(context->ctx, LY_VLOG_LINE, &context->line, LY_VCODE_EOF), LY_EVALID);
-        *term_char = in[0];
-        ++in;
-        *endtag_len = 1;
-    }
-
-    (*input) = in;
-    return LY_SUCCESS;
-}
-
-LY_ERR
-lyxml_get_element(struct lyxml_context *context, const char **input, const char **prefix_p, size_t *prefix_len_p,
-                  const char **name_p, size_t *name_len_p)
-{
-    struct ly_ctx *ctx = context->ctx; /* shortcut */
-    const char *in = (*input), *prefix = NULL, *name = NULL;
-    size_t endtag_len, prefix_len = 0, name_len = 0;
-    bool loop = true;
-    int closing = 0;
-    unsigned int c;
-    LY_ERR rc;
-    struct lyxml_elem *e;
-
-    while (loop) {
-        rc = lyxml_parse_element_start(context, &in, &closing);
-        if (rc) {
-            return rc;
-        } else if (context->status == LYXML_END) {
-            goto success;
-        }
-        /* we are at the begining of the element name, remember the identifier start before checking its format */
-        LY_CHECK_RET(rc = lyxml_parse_element_name(context, &in, &endtag_len, &c, &prefix, &prefix_len, &name, &name_len));
-
-        if (closing) {
-            /* match opening and closing element tags */
-            LY_CHECK_ERR_RET(
-                    !context->elements.count,
-                    LOGVAL(ctx, LY_VLOG_LINE, &context->line, LYVE_SYNTAX,
-                           "Opening and closing elements tag missmatch (\"%.*s\").", name_len, name),
-                    LY_EVALID);
-            e = (struct lyxml_elem*)context->elements.objs[context->elements.count - 1];
-            if (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)) {
-                LOGVAL(ctx, LY_VLOG_LINE, &context->line, LYVE_SYNTAX,
-                       "Opening and closing elements tag missmatch (\"%.*s\").", name_len, name);
-                return LY_EVALID;
-            }
-            /* opening and closing element tags matches, remove record from the opening tags list */
-            free(e);
-            --context->elements.count;
-
-            /* remove also the namespaces connected with the element */
-            lyxml_ns_rm(context);
-
-            /* clear closing element */
-            name = prefix = NULL;
-            name_len = prefix_len = 0;
-
-            if (c == '>') {
-                /* end of closing element */
-                context->status = LYXML_ELEMENT;
-            } else {
-                in -= endtag_len;
-                LOGVAL(ctx, LY_VLOG_LINE, &context->line, LYVE_SYNTAX, "Unexpected data \"%.*s\" in closing element tag.",
-                       LY_VCODE_INSTREXP_len(in), in);
-                return LY_EVALID;
-            }
-        } else {
-            if (c == '>') {
-                /* end of opening element */
-                context->status = LYXML_ELEM_CONTENT;
-            } else if (c == '/' && in[0] == '>') {
-                /* empty element closing */
-                context->status = LYXML_ELEMENT;
-                ++in;
-            } else {
-                /* attribute */
-                context->status = LYXML_ATTRIBUTE;
-                in -= endtag_len;
-            }
-
-            if (context->status != LYXML_ELEMENT) {
-                /* store element opening tag information */
-                e = malloc(sizeof *e);
-                LY_CHECK_ERR_RET(!e, LOGMEM(ctx), LY_EMEM);
-                e->name = name;
-                e->prefix = prefix;
-                e->name_len = name_len;
-                e->prefix_len = prefix_len;
-                ly_set_add(&context->elements, e, LY_SET_OPT_USEASLIST);
-            }
-        }
-        loop = false;
-    }
-
-success:
-    /* check for end of input */
-    if (in[0] == '\0') {
-        /* EOF */
-        if (context->elements.count) {
-            LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_EOF);
-            return LY_EVALID;
-        }
-        context->status = LYXML_END;
-    }
-    /* move caller's input */
-    (*input) = in;
-    /* return values */
-    if (prefix_p) {
-        *prefix_p = prefix;
-        *prefix_len_p = prefix_len;
-    }
-    if (name_p) {
-        *name_p = name;
-        *name_len_p = name_len;
-    }
-    return LY_SUCCESS;
-}
-
-LY_ERR
-lyxml_skip_element(struct lyxml_context *context, const char **input)
-{
-    LY_ERR ret;
-    unsigned int parents_count = context->elements.count;
-
-    while (context->elements.count >= parents_count) {
-        /* skip attributes */
-        while (context->status == LYXML_ATTRIBUTE) {
-            LY_CHECK_RET(lyxml_get_attribute(context, input, NULL, NULL, NULL, NULL));
-        }
-
-        /* skip content */
-        if (context->status == LYXML_ELEM_CONTENT) {
-            ret = lyxml_get_string(context, input, NULL, NULL, NULL, NULL, NULL);
-            if (ret && (ret != LY_EINVAL)) {
-                return ret;
-            }
-        }
-
-        if (context->status != LYXML_ELEMENT) {
-            LOGINT(context->ctx);
-            return LY_EINT;
-        }
-
-        /* nested element/closing element */
-        LY_CHECK_RET(lyxml_get_element(context, input, NULL, NULL, NULL, NULL));
-    }
-
-    return LY_SUCCESS;
-}
-
-LY_ERR
-lyxml_get_string(struct lyxml_context *context, const char **input, char **buffer, size_t *buffer_size, char **output,
-                 size_t *length, int *dynamic)
-{
-#define BUFSIZE 4096
-#define BUFSIZE_STEP 4096
-#define BUFSIZE_CHECK(CTX, BUF, SIZE, CURR, NEED) \
-    if (CURR+NEED >= SIZE) { \
-        BUF = ly_realloc(BUF, SIZE + BUFSIZE_STEP); \
-        LY_CHECK_ERR_RET(!BUF, LOGMEM(CTX), LY_EMEM); \
-        SIZE += BUFSIZE_STEP; \
-    }
-
-    struct ly_ctx *ctx = context->ctx; /* shortcut */
-    const char *in = (*input), *start;
-    char *buf = NULL, delim;
+    const struct ly_ctx *ctx = xmlctx->ctx; /* shortcut */
+    const char *in = xmlctx->input, *start;
+    char *buf = NULL;
     size_t offset;   /* read offset in input buffer */
     size_t len;      /* length of the output string (write offset in output buffer) */
     size_t size = 0; /* size of the output buffer */
     void *p;
     uint32_t n;
-    size_t u, newlines;
-    bool empty_content = false;
-    LY_ERR rc = LY_SUCCESS;
+    size_t u;
+    int ws = 1;
 
-    assert(context);
-    assert(context->status == LYXML_ELEM_CONTENT || context->status == LYXML_ATTR_CONTENT);
+    assert(xmlctx);
 
-    if (in[0] == '\'') {
-        delim = '\'';
-        ++in;
-    } else if (in[0] == '"') {
-        delim = '"';
-        ++in;
-    } else {
-        delim = '<';
-        empty_content = true;
-    }
-    start = in;
-
-    if (empty_content) {
-        /* only when processing element's content - try to ignore whitespaces used to format XML data
-         * before element's child or closing tag */
-        for (offset = newlines = 0; in[offset] && is_xmlws(in[offset]); ++offset) {
-            if (in[offset] == '\n') {
-                ++newlines;
-            }
-        }
-        LY_CHECK_ERR_RET(!in[offset], LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_EOF), LY_EVALID);
-        context->line += newlines;
-        if (in[offset] == '<') {
-            (*input) = in + offset;
-
-            /* get know if it is child element (indentation) or closing element (whitespace-only content) */
-            len = offset;
-            offset = 0;
-            in = *input;
-            goto element_endtag_check;
-        }
-    }
     /* init */
+    start = in;
     offset = len = 0;
-    empty_content = false;
-
-    if (0) {
-getbuffer:
-        /* prepare output buffer */
-        if (*buffer) {
-            buf = *buffer;
-            size = *buffer_size;
-        } else {
-            buf = malloc(BUFSIZE);
-            size = BUFSIZE;
-            LY_CHECK_ERR_RET(!buf, LOGMEM(ctx), LY_EMEM);
-        }
-    }
 
     /* parse */
     while (in[offset]) {
         if (in[offset] == '&') {
-            if (output) {
-                if (!buf) {
-                    /* it is necessary to modify the input, so we will need a dynamically allocated buffer */
-                    goto getbuffer;
-                }
+            /* non WS */
+            ws = 0;
 
-                if (offset) {
-                    /* store what we have so far */
-                    BUFSIZE_CHECK(ctx, buf, size, len, offset);
-                    memcpy(&buf[len], in, offset);
-                    len += offset;
-                    in += offset;
-                    offset = 0;
-                }
-                /* process reference */
-                /* we will need 4 bytes at most since we support only the predefined
-                 * (one-char) entities and character references */
-                BUFSIZE_CHECK(ctx, buf, size, len, 4);
+            if (!buf) {
+                /* prepare output buffer */
+                buf = malloc(BUFSIZE);
+                LY_CHECK_ERR_RET(!buf, LOGMEM(ctx), LY_EMEM);
+                size = BUFSIZE;
             }
+
+            /* allocate enough for the offset and next character,
+             * we will need 4 bytes at most since we support only the predefined
+             * (one-char) entities and character references */
+            if (len + offset + 4 >= size) {
+                buf = ly_realloc(buf, size + BUFSIZE_STEP);
+                LY_CHECK_ERR_RET(!buf, LOGMEM(ctx), LY_EMEM);
+                size += BUFSIZE_STEP;
+            }
+
+            if (offset) {
+                /* store what we have so far */
+                memcpy(&buf[len], in, offset);
+                len += offset;
+                in += offset;
+                offset = 0;
+            }
+
             ++offset;
             if (in[offset] != '#') {
                 /* entity reference - only predefined references are supported */
                 if (!strncmp(&in[offset], "lt;", 3)) {
-                    if (output) {
-                        buf[len++] = '<';
-                    }
+                    buf[len++] = '<';
                     in += 4; /* &lt; */
                 } else if (!strncmp(&in[offset], "gt;", 3)) {
-                    if (output) {
-                        buf[len++] = '>';
-                    }
+                    buf[len++] = '>';
                     in += 4; /* &gt; */
                 } else if (!strncmp(&in[offset], "amp;", 4)) {
-                    if (output) {
-                        buf[len++] = '&';
-                    }
+                    buf[len++] = '&';
                     in += 5; /* &amp; */
                 } else if (!strncmp(&in[offset], "apos;", 5)) {
-                    if (output) {
-                        buf[len++] = '\'';
-                    }
+                    buf[len++] = '\'';
                     in += 6; /* &apos; */
                 } else if (!strncmp(&in[offset], "quot;", 5)) {
-                    if (output) {
-                        buf[len++] = '\"';
-                    }
+                    buf[len++] = '\"';
                     in += 6; /* &quot; */
                 } else {
-                    LOGVAL(ctx, LY_VLOG_LINE, &context->line, LYVE_SYNTAX,
+                    LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX,
                            "Entity reference \"%.*s\" not supported, only predefined references allowed.", 10, &in[offset-1]);
                     goto error;
                 }
                 offset = 0;
             } else {
-                p = (void*)&in[offset - 1];
+                p = (void *)&in[offset - 1];
                 /* character reference */
                 ++offset;
                 if (isdigit(in[offset])) {
@@ -701,310 +480,548 @@
                         n = (16 * n) + u;
                     }
                 } else {
-                    LOGVAL(ctx, LY_VLOG_LINE, &context->line, LYVE_SYNTAX, "Invalid character reference \"%.*s\".", 12, p);
+                    LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Invalid character reference \"%.*s\".", 12, p);
                     goto error;
 
                 }
+
                 LY_CHECK_ERR_GOTO(in[offset] != ';',
-                                  LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INSTREXP,
+                                  LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_INSTREXP,
                                          LY_VCODE_INSTREXP_len(&in[offset]), &in[offset], ";"),
                                   error);
                 ++offset;
-                if (output) {
-                    rc = lyxml_pututf8(&buf[len], n, &u);
-                } else {
-                    char utf8[4];
-                    rc = lyxml_pututf8(&utf8[0], n, &u);
-                }
-                LY_CHECK_ERR_GOTO(rc, LOGVAL(ctx, LY_VLOG_LINE, &context->line, LYVE_SYNTAX,
-                                             "Invalid character reference \"%.*s\" (0x%08x).", 12, p, n),
+                LY_CHECK_ERR_GOTO(lyxml_pututf8(&buf[len], n, &u),
+                                  LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX,
+                                         "Invalid character reference \"%.*s\" (0x%08x).", 12, p, n),
                                   error);
                 len += u;
                 in += offset;
                 offset = 0;
             }
-        } else if (in[offset] == delim) {
+        } else if (in[offset] == endchar) {
             /* end of string */
             if (buf) {
-                if (len + offset >= size) {
-                    buf = ly_realloc(buf, len + offset + 1);
-                    LY_CHECK_ERR_RET(!buf, LOGMEM(ctx), LY_EMEM);
-                    size = len + offset + 1;
-                }
+                /* realloc exact size string */
+                buf = ly_realloc(buf, len + offset + 1);
+                LY_CHECK_ERR_RET(!buf, LOGMEM(ctx), LY_EMEM);
+                size = len + offset + 1;
                 memcpy(&buf[len], in, offset);
+
+                /* set terminating NULL byte */
+                buf[len + offset] = '\0';
             }
             len += offset;
-            /* in case of element content, keep the leading <,
-             * for attribute's value move after the terminating quotation mark */
-element_endtag_check:
-            if (context->status == LYXML_ELEM_CONTENT) {
-                const char *name = NULL, *prefix = NULL;
-                size_t name_len = 0, prefix_len = 0;
-                int closing = 0;
-                /* use fake context to preserve real context (lines, status) since we don't want really parse the element tag here */
-                struct lyxml_context fakecontext = {.ctx = context->ctx, .line = context->line, .status = context->status};
-
-                in += offset;
-
-                /* get know if it is child element (mixed content) or closing element (regular content) */
-                /* We don't want actually to parse the closing element, we just need to check mixed content.
-                 * The closing element tag is preserved to keep the context for the data (returned string),
-                 * since it can contain data using XML prefixes defined in this element and the caller can
-                 * want to work with it */
-                (*input) = in;
-                rc = lyxml_parse_element_start(&fakecontext, &in, &closing);
-                if (rc) {
-                    /* some parsing error */
-                    goto error;
-                } else {
-                    size_t endtag_len;
-                    unsigned int c;
-                    struct lyxml_elem *e;
-
-                    LY_CHECK_GOTO(lyxml_parse_element_name(&fakecontext, &in, &endtag_len, &c, &prefix, &prefix_len, &name, &name_len), error);
-
-                    if (!closing) {
-                        if (empty_content) {
-                            /* the element here is not closing element, so we have the just indentation formatting before the child */
-                            context->status = LYXML_ELEMENT;
-                            return LY_EINVAL;
-                        } else {
-                            /* the element here is not closing element, so we have not allowed mixed content */
-                            struct lyxml_elem *e = (struct lyxml_elem*)context->elements.objs[--context->elements.count];
-                            LOGVAL(ctx, LY_VLOG_LINE, &context->line, LYVE_SYNTAX, "Mixed XML content is not allowed (%.*s).",
-                                   offset + (in - (*input)), &(*input)[-offset]);
-                            free(e);
-                            goto error;
-                        }
-                    }
-
-                    /* closing element start - check the name if it matches the opening element tag */
-                    LY_CHECK_ERR_GOTO(!context->elements.count,
-                            LOGVAL(ctx, LY_VLOG_LINE, &fakecontext.line, LYVE_SYNTAX, "Opening and closing elements tag missmatch (\"%.*s\").",
-                                   name_len, name),
-                            error);
-                    e = (struct lyxml_elem*)context->elements.objs[context->elements.count - 1];
-                    if (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)) {
-                        LOGVAL(ctx, LY_VLOG_LINE, &fakecontext.line, LYVE_SYNTAX,
-                               "Opening and closing elements tag missmatch (\"%.*s\", expected \"%.*s\").",
-                               name_len, name, e->name_len, e->name);
-                        free(e);
-                        --context->elements.count;
-                        goto error;
-                    }
-                    /* opening and closing element tags matches */
-                    /* return input back */
-                    in = (*input);
-                }
-            } else {
-                in += offset + 1;
-            }
+            in += offset;
             goto success;
         } else {
+            if (!is_xmlws(in[offset])) {
+                /* non WS */
+                ws = 0;
+            }
+
             /* log lines */
             if (in[offset] == '\n') {
-                ++context->line;
+                ++xmlctx->line;
             }
 
             /* continue */
             ++offset;
         }
     }
-    LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_EOF);
+
+    /* EOF reached before endchar */
+    LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_EOF);
+
 error:
-    if (!(*buffer)) {
-        /* buffer not provided, buf is local */
-        free(buf);
-    } else if (buf) {
-        /* buf is shared with caller via buffer, but buf could be reallocated, so update the provided buffer */
-        (*buffer) = buf;
-        (*buffer_size) = size;
-    }
+    free(buf);
     return LY_EVALID;
 
 success:
     if (buf) {
-        if (!(*buffer) && size != len + 1) {
-            /* not using provided buffer, so fit the allocated buffer to what we really have inside */
-            p = realloc(buf, len + 1);
-            /* ignore realloc fail because we are reducing the buffer,
-             * so just return bigger buffer than needed */
-            if (p) {
-                size = len + 1;
-                buf = p;
-            }
-        }
-        /* set terminating NULL byte */
-        buf[len] = '\0';
+        *value = buf;
+        *dynamic = 1;
+    } else {
+        *value = (char *)start;
+        *dynamic = 0;
     }
+    *length = len;
+    *ws_only = ws;
 
-    context->status -= 1;
-    if (buf) {
-        (*buffer) = buf;
-        (*buffer_size) = size;
-        (*output) = buf;
-        (*dynamic) = 1;
-        (*length) = len;
-    } else if (output) {
-        (*output) = (char*)start;
-        (*dynamic) = 0;
-        (*length) = len;
-    }
-
-    if (context->status == LYXML_ATTRIBUTE) {
-        /* skip whitespaces after the value */
-        ign_xmlws(context, in);
-
-        if (in[0] == '>') {
-            /* element terminated by > - termination of the opening tag */
-            context->status = LYXML_ELEM_CONTENT;
-            ++in;
-        } else if (in[0] == '/' && in[1] == '>') {
-            /* element terminated by /> - termination of an empty element */
-            context->status = LYXML_ELEMENT;
-            in += 2;
-
-            /* remove the closed element record from the tags list */
-            free(context->elements.objs[context->elements.count - 1]);
-            --context->elements.count;
-
-            /* remove also the namespaces conneted with the element */
-            lyxml_ns_rm(context);
-
-            if (!context->elements.count && in[0] == '\0') {
-                /* EOF */
-                context->status = LYXML_END;
-            }
-        } /* else another attribute */
-    }
-
-    (*input) = in;
-    return rc;
+    xmlctx->input = in;
+    return LY_SUCCESS;
 
 #undef BUFSIZE
 #undef BUFSIZE_STEP
-#undef BUFSIZE_CHECK
 }
 
-LY_ERR
-lyxml_get_attribute(struct lyxml_context *context, const char **input,
-                    const char **prefix, size_t *prefix_len, const char **name, size_t *name_len)
+static LY_ERR
+lyxml_close_element(struct lyxml_ctx *xmlctx, const char *prefix, size_t prefix_len, const char *name, size_t name_len,
+                    int empty)
 {
-    struct ly_ctx *ctx = context->ctx; /* shortcut */
-    const char *in = (*input);
-    const char *id;
-    const char *endtag;
-    LY_ERR rc;
-    unsigned int c;
-    size_t endtag_len;
-    int is_ns = 0;
-    const char *ns_prefix;
-    size_t ns_prefix_len;
+    struct lyxml_elem *e;
 
-    /* initialize output variables */
-    (*prefix) = (*name) = NULL;
-    (*prefix_len) = (*name_len) = 0;
+    /* match opening and closing element tags */
+    if (!xmlctx->elements.count) {
+        LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Stray closing element tag (\"%.*s\").",
+               name_len, name);
+        return LY_EVALID;
+    }
 
-    do {
-        /* skip initial whitespaces */
-        ign_xmlws(context, in);
+    e = (struct lyxml_elem *)xmlctx->elements.objs[xmlctx->elements.count - 1];
+    if ((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)) {
+        LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX,
+               "Opening (\"%.*s%s%.*s\") and closing (\"%.*s%s%.*s\") elements tag mismatch.",
+               e->prefix_len, e->prefix ? e->prefix : "", e->prefix ? ":" : "", e->name_len, e->name,
+               prefix_len, prefix ? prefix : "", prefix ? ":" : "", name_len, name);
+        return LY_EVALID;
+    }
 
-        if (in[0] == '\0') {
-            /* EOF - not expected at this place */
-            LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_EOF);
-            return LY_EVALID;
-        }
+    /* opening and closing element tags matches, remove record from the opening tags list */
+    ly_set_rm_index(&xmlctx->elements, xmlctx->elements.count - 1, free);
 
-        /* remember the identifier start before checking its format */
-        id = in;
-        rc = lyxml_check_qname(context, &in, &c, &endtag_len);
-        LY_CHECK_RET(rc);
-        if (c == ':') {
-            /* we have prefixed identifier */
-            endtag = in - endtag_len;
+    /* remove also the namespaces connected with the element */
+    lyxml_ns_rm(xmlctx);
 
-            rc = lyxml_check_qname(context, &in, &c, &endtag_len);
-            LY_CHECK_RET(rc);
+    /* skip WS */
+    ign_xmlws(xmlctx);
 
-            (*prefix) = id;
-            (*prefix_len) = endtag - id;
-            id = endtag + 1;
-        }
-        if (!is_xmlws(c) && c != '=') {
-            in = in - endtag_len;
-            LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(in), in, "whitespace or '='");
-            return LY_EVALID;
-        }
-        in = in - endtag_len;
-        (*name) = id;
-        (*name_len) = in - id;
+    /* special "<elem/>" element */
+    if (empty && (xmlctx->input[0] == '/')) {
+        move_input(xmlctx, 1);
+    }
 
-        /* eat '=' and stop at the value beginning */
-        ign_xmlws(context, in);
-        if (in[0] != '=') {
-            LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(in), in, "'='");
-            return LY_EVALID;
-        }
-        ++in;
-        ign_xmlws(context, in);
-        if (in[0] != '\'' && in[0] != '"') {
-            LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INSTREXP,
-                LY_VCODE_INSTREXP_len(in), in, "either single or double quotation mark");
-            return LY_EVALID;
-        }
-        context->status = LYXML_ATTR_CONTENT;
+    /* parse closing tag */
+    if (xmlctx->input[0] != '>') {
+        LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(xmlctx->input),
+               xmlctx->input, "element tag termination ('>')");
+        return LY_EVALID;
+    }
 
-        is_ns = 0;
-        if (*prefix && *prefix_len == 5 && !strncmp(*prefix, "xmlns", 5)) {
-            is_ns = 1;
-            ns_prefix = *name;
-            ns_prefix_len = *name_len;
-        } else if (*name_len == 5 && !strncmp(*name, "xmlns", 5)) {
-            is_ns = 1;
-            ns_prefix = NULL;
-            ns_prefix_len = 0;
-        }
-        if (is_ns) {
-            /* instead of attribute, we have namespace specification,
-            * so process it automatically and then move to another attribute (if any) */
-            char *value = NULL;
-            size_t value_len = 0;
-            int dynamic = 0;
+    /* move after closing tag without checking for EOF */
+    ++xmlctx->input;
 
-            LY_CHECK_RET(lyxml_get_string(context, &in, &value, &value_len, &value, &value_len, &dynamic));
-            if ((rc = lyxml_ns_add(context, ns_prefix, ns_prefix_len, dynamic ? value : strndup(value, value_len)))) {
-                if (dynamic) {
-                    free(value);
-                    return rc;
-                }
-            }
-
-            /* do not return ns */
-            (*prefix) = (*name) = NULL;
-            (*prefix_len) = (*name_len) = 0;
-        }
-    } while (is_ns && (context->status == LYXML_ATTRIBUTE));
-
-    /* move caller's input */
-    (*input) = in;
     return LY_SUCCESS;
 }
 
-void
-lyxml_context_clear(struct lyxml_context *context)
+static LY_ERR
+lyxml_open_element(struct lyxml_ctx *xmlctx, const char *prefix, size_t prefix_len, const char *name, size_t name_len)
 {
-    unsigned int u;
+    LY_ERR ret = LY_SUCCESS;
+    struct lyxml_elem *e;
+    const char *prev_input;
+    char *value;
+    size_t parsed, value_len;
+    int ws_only, dynamic, is_ns;
+    uint32_t c;
 
-    ly_set_erase(&context->elements, free);
-    for (u = context->ns.count - 1; u + 1 > 0; --u) {
-        /* remove the ns structure */
-        free(((struct lyxml_ns *)context->ns.objs[u])->prefix);
-        free(((struct lyxml_ns *)context->ns.objs[u])->uri);
-        free(context->ns.objs[u]);
+    /* store element opening tag information */
+    e = malloc(sizeof *e);
+    LY_CHECK_ERR_RET(!e, LOGMEM(xmlctx->ctx), LY_EMEM);
+    e->name = name;
+    e->prefix = prefix;
+    e->name_len = name_len;
+    e->prefix_len = prefix_len;
+    ly_set_add(&xmlctx->elements, e, LY_SET_OPT_USEASLIST);
+
+    /* skip WS */
+    ign_xmlws(xmlctx);
+
+    /* parse and store all namespaces */
+    prev_input = xmlctx->input;
+    is_ns = 1;
+    while ((xmlctx->input[0] != '\0') && !ly_getutf8(&xmlctx->input, &c, &parsed) && is_xmlqnamestartchar(c)) {
+        xmlctx->input -= parsed;
+
+        /* parse attribute name */
+        LY_CHECK_GOTO(ret = lyxml_parse_qname(xmlctx, &prefix, &prefix_len, &name, &name_len), cleanup);
+
+        /* parse the value */
+        LY_CHECK_GOTO(ret = lyxml_next_attr_content(xmlctx, (const char **)&value, &value_len, &ws_only, &dynamic), cleanup);
+
+        /* store every namespace */
+        if ((prefix && !ly_strncmp("xmlns", prefix, prefix_len)) || (!prefix && !ly_strncmp("xmlns", name, name_len))) {
+            LY_CHECK_GOTO(ret = lyxml_ns_add(xmlctx, prefix ? name : NULL, prefix ? name_len : 0,
+                                             dynamic ? value : strndup(value, value_len)), cleanup);
+            dynamic = 0;
+        } else {
+            /* not a namespace */
+            is_ns = 0;
+        }
+        if (dynamic) {
+            free(value);
+        }
+
+        /* skip WS */
+        ign_xmlws(xmlctx);
+
+        if (is_ns) {
+            /* we can actually skip all the namespaces as there is no reason to parse them again */
+            prev_input = xmlctx->input;
+        }
     }
-    ly_set_erase(&context->ns, NULL);
-    context->status = 0;
+
+cleanup:
+    if (!ret) {
+        xmlctx->input = prev_input;
+    }
+    return ret;
+}
+
+static LY_ERR
+lyxml_next_attr_content(struct lyxml_ctx *xmlctx, const char **value, size_t *value_len, int *ws_only, int *dynamic)
+{
+    char quot;
+
+    /* skip WS */
+    ign_xmlws(xmlctx);
+
+    /* skip '=' */
+    if (xmlctx->input[0] == '\0') {
+        LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_EOF);
+        return LY_EVALID;
+    } else if (xmlctx->input[0] != '=') {
+        LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(xmlctx->input),
+               xmlctx->input, "'='");
+        return LY_EVALID;
+    }
+    move_input(xmlctx, 1);
+
+    /* skip WS */
+    ign_xmlws(xmlctx);
+
+    /* find quotes */
+    if (xmlctx->input[0] == '\0') {
+        LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_EOF);
+        return LY_EVALID;
+    } else if ((xmlctx->input[0] != '\'') && (xmlctx->input[0] != '\"')) {
+        LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(xmlctx->input),
+               xmlctx->input, "either single or double quotation mark");
+        return LY_EVALID;
+    }
+
+    /* remember quote */
+    quot = xmlctx->input[0];
+    move_input(xmlctx, 1);
+
+    /* parse attribute value */
+    LY_CHECK_RET(lyxml_parse_value(xmlctx, quot, (char **)value, value_len, ws_only, dynamic));
+
+    /* move after ending quote (without checking for EOF) */
+    ++xmlctx->input;
+
+    return LY_SUCCESS;
+}
+
+static LY_ERR
+lyxml_next_attribute(struct lyxml_ctx *xmlctx, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len)
+{
+    const char *in;
+    char *value;
+    uint32_t c;
+    size_t parsed, value_len;
+    int ws_only, dynamic;
+
+    /* skip WS */
+    ign_xmlws(xmlctx);
+
+    /* parse only possible attributes */
+    while ((xmlctx->input[0] != '>') && (xmlctx->input[0] != '/')) {
+        in = xmlctx->input;
+        if (in[0] == '\0') {
+            LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_EOF);
+            return LY_EVALID;
+        } else if ((ly_getutf8(&in, &c, &parsed) || !is_xmlqnamestartchar(c))) {
+            LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(in - parsed), in - parsed,
+                "element tag end ('>' or '/>') or an attribute");
+            return LY_EVALID;
+        }
+
+        /* parse attribute name */
+        LY_CHECK_RET(lyxml_parse_qname(xmlctx, prefix, prefix_len, name, name_len));
+
+        if ((!*prefix || ly_strncmp("xmlns", *prefix, *prefix_len)) && (*prefix || ly_strncmp("xmlns", *name, *name_len))) {
+            /* standard attribute */
+            break;
+        }
+
+        /* namespace, skip it */
+        LY_CHECK_RET(lyxml_next_attr_content(xmlctx, (const char **)&value, &value_len, &ws_only, &dynamic));
+        if (dynamic) {
+            free(value);
+        }
+
+        /* skip WS */
+        ign_xmlws(xmlctx);
+    }
+
+    return LY_SUCCESS;
+}
+
+static LY_ERR
+lyxml_next_element(struct lyxml_ctx *xmlctx, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len,
+                   int *closing)
+{
+    /* skip WS until EOF or after opening tag '<' */
+    LY_CHECK_RET(lyxml_skip_until_end_or_after_otag(xmlctx));
+    if (xmlctx->input[0] == '\0') {
+        /* set return values */
+        *prefix = *name = NULL;
+        *prefix_len = *name_len = 0;
+        return LY_SUCCESS;
+    }
+
+    if (xmlctx->input[0] == '/') {
+        move_input(xmlctx, 1);
+        *closing = 1;
+    } else {
+        *closing = 0;
+    }
+
+    /* skip WS */
+    ign_xmlws(xmlctx);
+
+    /* parse element name */
+    LY_CHECK_RET(lyxml_parse_qname(xmlctx, prefix, prefix_len, name, name_len));
+
+    return LY_SUCCESS;
+}
+
+LY_ERR
+lyxml_ctx_new(const struct ly_ctx *ctx, const char *input, struct lyxml_ctx **xmlctx_p)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct lyxml_ctx *xmlctx;
+    int closing;
+
+    /* new context */
+    xmlctx = calloc(1, sizeof *xmlctx);
+    LY_CHECK_ERR_RET(!xmlctx, LOGMEM(ctx), LY_EMEM);
+    xmlctx->ctx = ctx;
+    xmlctx->line = 1;
+    xmlctx->input = input;
+
+    /* parse next element, if any */
+    LY_CHECK_GOTO(ret = lyxml_next_element(xmlctx, &xmlctx->prefix, &xmlctx->prefix_len, &xmlctx->name,
+                                           &xmlctx->name_len, &closing), cleanup);
+
+    if (xmlctx->input[0] == '\0') {
+        /* update status */
+        xmlctx->status = LYXML_END;
+    } else if (closing) {
+        LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Stray closing element tag (\"%.*s\").",
+               xmlctx->name_len, xmlctx->name);
+        ret = LY_EVALID;
+        goto cleanup;
+    } else {
+        /* open an element, also parses all enclosed namespaces */
+        LY_CHECK_GOTO(ret = lyxml_open_element(xmlctx, xmlctx->prefix, xmlctx->prefix_len, xmlctx->name, xmlctx->name_len), cleanup);
+
+        /* update status */
+        xmlctx->status = LYXML_ELEMENT;
+    }
+
+cleanup:
+    if (ret) {
+        lyxml_ctx_free(xmlctx);
+    } else {
+        *xmlctx_p = xmlctx;
+    }
+    return ret;
+}
+
+LY_ERR
+lyxml_ctx_next(struct lyxml_ctx *xmlctx)
+{
+    LY_ERR ret = LY_SUCCESS;
+    int closing;
+    struct lyxml_elem *e;
+
+    /* if the value was not used, free it */
+    if (((xmlctx->status == LYXML_ELEM_CONTENT) || (xmlctx->status == LYXML_ATTR_CONTENT)) && xmlctx->dynamic) {
+        free((char *)xmlctx->value);
+        xmlctx->value = NULL;
+        xmlctx->dynamic = 0;
+    }
+
+    switch (xmlctx->status) {
+    /* content |</elem> */
+    case LYXML_ELEM_CONTENT:
+        /* handle special case when empty content for "<elem/>" was returned */
+        if (xmlctx->input[0] == '/') {
+            assert(xmlctx->elements.count);
+            e = (struct lyxml_elem *)xmlctx->elements.objs[xmlctx->elements.count - 1];
+
+            /* close the element (parses closing tag) */
+            LY_CHECK_GOTO(ret = lyxml_close_element(xmlctx, e->prefix, e->prefix_len, e->name, e->name_len, 1), cleanup);
+
+            /* update status */
+            xmlctx->status = LYXML_ELEM_CLOSE;
+            break;
+        }
+        /* fallthrough */
+
+    /* </elem>| <elem2>* */
+    case LYXML_ELEM_CLOSE:
+        /* parse next element, if any */
+        LY_CHECK_GOTO(ret = lyxml_next_element(xmlctx, &xmlctx->prefix, &xmlctx->prefix_len, &xmlctx->name,
+                                               &xmlctx->name_len, &closing), cleanup);
+
+        if (xmlctx->input[0] == '\0') {
+            /* update status */
+            xmlctx->status = LYXML_END;
+        } else if (closing) {
+            /* close an element (parses also closing tag) */
+            LY_CHECK_GOTO(ret = lyxml_close_element(xmlctx, xmlctx->prefix, xmlctx->prefix_len, xmlctx->name, xmlctx->name_len, 0), cleanup);
+
+            /* update status */
+            xmlctx->status = LYXML_ELEM_CLOSE;
+        } else {
+            /* open an element, also parses all enclosed namespaces */
+            LY_CHECK_GOTO(ret = lyxml_open_element(xmlctx, xmlctx->prefix, xmlctx->prefix_len, xmlctx->name, xmlctx->name_len), cleanup);
+
+            /* update status */
+            xmlctx->status = LYXML_ELEMENT;
+        }
+        break;
+
+    /* <elem| attr='val'* > content  */
+    case LYXML_ELEMENT:
+
+    /* attr='val'| attr='val'* > content */
+    case LYXML_ATTR_CONTENT:
+        /* parse attribute name, if any */
+        LY_CHECK_GOTO(ret = lyxml_next_attribute(xmlctx, &xmlctx->prefix, &xmlctx->prefix_len, &xmlctx->name, &xmlctx->name_len), cleanup);
+
+        if (xmlctx->input[0] == '>') {
+            /* no attributes but a closing tag */
+            move_input(xmlctx, 1);
+
+            /* parse element content */
+            LY_CHECK_GOTO(ret = lyxml_parse_value(xmlctx, '<', (char **)&xmlctx->value, &xmlctx->value_len, &xmlctx->ws_only,
+                                                  &xmlctx->dynamic), cleanup);
+
+            if (!xmlctx->value_len) {
+                /* use empty value, easier to work with */
+                xmlctx->value = "";
+                assert(!xmlctx->dynamic);
+            }
+
+            /* update status */
+            xmlctx->status = LYXML_ELEM_CONTENT;
+        } else if (xmlctx->input[0] == '/') {
+            /* no content but we still return it */
+            xmlctx->value = "";
+            xmlctx->value_len = 0;
+            xmlctx->ws_only = 1;
+            xmlctx->dynamic = 0;
+
+            /* update status */
+            xmlctx->status = LYXML_ELEM_CONTENT;
+        } else {
+            /* update status */
+            xmlctx->status = LYXML_ATTRIBUTE;
+        }
+        break;
+
+    /* attr|='val' */
+    case LYXML_ATTRIBUTE:
+        /* skip formatting and parse value */
+        LY_CHECK_GOTO(ret = lyxml_next_attr_content(xmlctx, &xmlctx->value, &xmlctx->value_len, &xmlctx->ws_only,
+                                                    &xmlctx->dynamic), cleanup);
+
+        /* update status */
+        xmlctx->status = LYXML_ATTR_CONTENT;
+        break;
+
+    /* </elem>   |EOF */
+    case LYXML_END:
+        /* nothing to do */
+        break;
+    }
+
+cleanup:
+    if (ret) {
+        /* invalidate context */
+        xmlctx->status = LYXML_END;
+    }
+    return ret;
+}
+
+LY_ERR
+lyxml_ctx_peek(struct lyxml_ctx *xmlctx, enum LYXML_PARSER_STATUS *next)
+{
+    LY_ERR ret = LY_SUCCESS;
+    const char *prefix, *name, *prev_input;
+    size_t prefix_len, name_len;
+    int closing;
+
+    prev_input = xmlctx->input;
+
+    switch (xmlctx->status) {
+    case LYXML_ELEM_CONTENT:
+        if (xmlctx->input[0] == '/') {
+            *next = LYXML_ELEM_CLOSE;
+            break;
+        }
+        /* fallthrough */
+    case LYXML_ELEM_CLOSE:
+        /* parse next element, if any */
+        LY_CHECK_GOTO(ret = lyxml_next_element(xmlctx, &prefix, &prefix_len, &name, &name_len, &closing), cleanup);
+
+        if (xmlctx->input[0] == '\0') {
+            *next = LYXML_END;
+        } else if (closing) {
+            *next = LYXML_ELEM_CLOSE;
+        } else {
+            *next = LYXML_ELEMENT;
+        }
+        break;
+    case LYXML_ELEMENT:
+    case LYXML_ATTR_CONTENT:
+        /* parse attribute name, if any */
+        LY_CHECK_GOTO(ret = lyxml_next_attribute(xmlctx, &prefix, &prefix_len, &name, &name_len), cleanup);
+
+        if ((xmlctx->input[0] == '>') || (xmlctx->input[0] == '/')) {
+            *next = LYXML_ELEM_CONTENT;
+        } else {
+            *next = LYXML_ATTRIBUTE;
+        }
+        break;
+    case LYXML_ATTRIBUTE:
+        *next = LYXML_ATTR_CONTENT;
+        break;
+    case LYXML_END:
+        *next = LYXML_END;
+        break;
+    }
+
+cleanup:
+    xmlctx->input = prev_input;
+    return ret;
+}
+
+void
+lyxml_ctx_free(struct lyxml_ctx *xmlctx)
+{
+    uint32_t u;
+
+    if (!xmlctx) {
+        return;
+    }
+
+    if (((xmlctx->status == LYXML_ELEM_CONTENT) || (xmlctx->status == LYXML_ATTR_CONTENT)) && xmlctx->dynamic) {
+        free((char *)xmlctx->value);
+    }
+    ly_set_erase(&xmlctx->elements, free);
+    for (u = xmlctx->ns.count - 1; u + 1 > 0; --u) {
+        /* remove the ns structure */
+        free(((struct lyxml_ns *)xmlctx->ns.objs[u])->prefix);
+        free(((struct lyxml_ns *)xmlctx->ns.objs[u])->uri);
+        free(xmlctx->ns.objs[u]);
+    }
+    ly_set_erase(&xmlctx->ns, NULL);
+    free(xmlctx);
 }
 
 LY_ERR
@@ -1044,7 +1061,7 @@
 }
 
 LY_ERR
-lyxml_get_prefixes(struct lyxml_context *ctx, const char *value, size_t value_len, struct ly_prefix **val_prefs)
+lyxml_get_prefixes(struct lyxml_ctx *xmlctx, const char *value, size_t value_len, struct ly_prefix **val_prefs)
 {
     LY_ERR ret;
     uint32_t u, c;
@@ -1064,7 +1081,7 @@
             if (*stop == ':') {
                 /* we have a possible prefix */
                 len = stop - start;
-                ns = lyxml_ns_get(ctx, start, len);
+                ns = lyxml_ns_get(xmlctx, start, len);
                 if (ns) {
                     struct ly_prefix *p = NULL;
 
@@ -1076,9 +1093,9 @@
                         }
                     }
                     if (!p) {
-                        LY_ARRAY_NEW_GOTO(ctx->ctx, prefixes, p, ret, error);
-                        p->pref = lydict_insert(ctx->ctx, start, len);
-                        p->ns = lydict_insert(ctx->ctx, ns->uri, 0);
+                        LY_ARRAY_NEW_GOTO(xmlctx->ctx, prefixes, p, ret, error);
+                        p->pref = lydict_insert(xmlctx->ctx, start, len);
+                        p->ns = lydict_insert(xmlctx->ctx, ns->uri, 0);
                     } /* else the prefix already present */
                 }
             }
@@ -1091,7 +1108,7 @@
 
 error:
     LY_ARRAY_FOR(prefixes, u) {
-        lydict_remove(ctx->ctx, prefixes[u].pref);
+        lydict_remove(xmlctx->ctx, prefixes[u].pref);
     }
     LY_ARRAY_FREE(prefixes);
     return ret;
diff --git a/src/xml.h b/src/xml.h
index 8e30478..2bbf5da 100644
--- a/src/xml.h
+++ b/src/xml.h
@@ -52,7 +52,7 @@
 struct lyxml_ns {
     char *prefix;         /* prefix of the namespace, NULL for the default namespace */
     char *uri;            /* namespace URI */
-    unsigned int depth;   /* depth level of the element to maintain the list of accessible namespace definitions */
+    uint32_t depth;       /* depth level of the element to maintain the list of accessible namespace definitions */
 };
 
 /* element tag identifier for matching opening and closing tags */
@@ -67,125 +67,58 @@
  * @brief Status of the parser providing information what is expected next (which function is supposed to be called).
  */
 enum LYXML_PARSER_STATUS {
-    LYXML_ELEMENT = 0,    /* expecting XML element, call lyxml_get_element() */
-    LYXML_ELEM_CONTENT,   /* expecting content of an element, call lyxml_get_string */
-    LYXML_ATTRIBUTE,      /* expecting XML attribute, call lyxml_get_attribute() */
-    LYXML_ATTR_CONTENT,   /* expecting value of an attribute, call lyxml_get_string */
+    LYXML_ELEMENT,        /* opening XML element parsed */
+    LYXML_ELEM_CLOSE,     /* closing XML element parsed */
+    LYXML_ELEM_CONTENT,   /* XML element context parsed */
+    LYXML_ATTRIBUTE,      /* XML attribute parsed */
+    LYXML_ATTR_CONTENT,   /* XML attribute content parsed */
     LYXML_END             /* end of input data */
 };
 
-struct lyxml_context {
-    struct ly_ctx *ctx;
+struct lyxml_ctx {
+    enum LYXML_PARSER_STATUS status; /* status providing information about the last parsed object, following attributes
+                                        are filled based on it */
+    union {
+        const char *prefix; /* LYXML_ELEMENT, LYXML_ATTRIBUTE */
+        const char *value;  /* LYXML_ELEM_CONTENT, LYXML_ATTR_CONTENT */
+    };
+    union {
+        size_t prefix_len;  /* LYXML_ELEMENT, LYXML_ATTRIBUTE */
+        size_t value_len;   /* LYXML_ELEM_CONTENT, LYXML_ATTR_CONTENT */
+    };
+    union {
+        const char *name;   /* LYXML_ELEMENT, LYXML_ATTRIBUTE */
+        int ws_only;        /* LYXML_ELEM_CONTENT, LYXML_ATTR_CONTENT */
+    };
+    union {
+        size_t name_len;    /* LYXML_ELEMENT, LYXML_ATTRIBUTE */
+        int dynamic;        /* LYXML_ELEM_CONTENT, LYXML_ATTR_CONTENT */
+    };
+
+    const struct ly_ctx *ctx;
     uint64_t line;
-    enum LYXML_PARSER_STATUS status; /* status providing information about the next expected object in input data */
+    const char *input;
     struct ly_set elements; /* list of not-yet-closed elements */
-    struct ly_set ns;     /* handled with LY_SET_OPT_USEASLIST */
+    struct ly_set ns;       /* handled with LY_SET_OPT_USEASLIST */
 };
 
-/**
- * @brief Parse input expecting an XML element.
- *
- * Able to silently skip comments, PIs and CData. DOCTYPE is not parseable, so it is reported as LY_EVALID error.
- * If '<' is not found in input, LY_EINVAL is returned (but no error is logged), so it is possible to continue
- * with parsing input as text content.
- *
- * Input string is not being modified, so the returned values are not NULL-terminated, instead their length
- * is returned.
- *
- * @param[in] context XML context to track lines or store errors into libyang context.
- * @param[in,out] input Input string to process, updated according to the processed/read data.
- * @param[in] options Currently unused options to modify input processing.
- * @param[out] prefix_p Pointer to prefix if present in the element name, NULL otherwise.
- * @param[out] prefix_len_p Length of the prefix if any.
- * @param[out] name_p Element name. When LY_SUCCESS is returned but name is NULL, check context's status field:
- * - LYXML_END - end of input was reached
- * - LYXML_ELEMENT - closing element found, expecting now a sibling element so call lyxml_get_element() again
- * @param[out] name_len_p Length of the element name.
- * @return LY_ERR values.
- */
-LY_ERR lyxml_get_element(struct lyxml_context *context, const char **input, const char **prefix_p, size_t *prefix_len_p,
-                         const char **name_p, size_t *name_len_p);
+LY_ERR lyxml_ctx_new(const struct ly_ctx *ctx, const char *input, struct lyxml_ctx **xmlctx);
 
-/**
- * @brief Skip an element after its opening tag was parsed.
- *
- * @param[in] context XML context.
- * @param[in,out] input Input string to process, updated according to the read data.
- * @return LY_ERR values.
- */
-LY_ERR lyxml_skip_element(struct lyxml_context *context, const char **input);
+LY_ERR lyxml_ctx_next(struct lyxml_ctx *xmlctx);
 
-/**
- * @brief Parse input expecting an XML attribute (including XML namespace).
- *
- * Input string is not being modified, so the returned values are not NULL-terminated, instead their length
- * is returned.
- *
- * Namespace definitions are processed automatically and stored internally. To get namespace for a specific
- * prefix, use lyxml_get_ns(). This also means, that in case there are only the namespace definitions,
- * lyxml_get_attribute() can succeed, but nothing (name, prefix) is returned.
- *
- * The status member of the context is updated to provide information what the caller is supposed to call
- * after this function.
- *
- * @param[in] context XML context to track lines or store errors into libyang context.
- * @param[in,out] input Input string to process, updated according to the processed/read data so,
- * when succeeded, it points to the opening quote of the attribute's value.
- * @param[out] prefix Pointer to prefix if present in the attribute name, NULL otherwise.
- * @param[out] prefix_len Length of the prefix if any.
- * @param[out] name Attribute name. Can be NULL only in case there is actually no attribute, but namespaces.
- * @param[out] name_len Length of the element name.
- * @return LY_ERR values.
- */
-LY_ERR lyxml_get_attribute(struct lyxml_context *context, const char **input,
-                           const char **prefix, size_t *prefix_len, const char **name, size_t *name_len);
-
-/**
- * @brief Parse input as XML text (attribute's values and element's content).
- *
- * Mixed content of XML elements is not allowed. Formating whitespaces before child element are ignored,
- * LY_EINVAL is returned in such a case (output is not set, no error is printed) and input is moved
- * to the beginning of a child definition.
- *
- * In the case of attribute's values, the input string is expected to start on a quotation mark to
- * select which delimiter (single or double quote) is used. Otherwise, the element content is being
- * parsed expected to be terminated by '<' character.
- *
- * If function succeeds, the string in a dynamically allocated output buffer is always NULL-terminated.
- *
- * The dynamically allocated buffer is used only when necessary because of a character or the supported entity
- * reference which modify the input data. These constructs are replaced by their real value, so in case the output
- * string will be again printed as an XML data, it may be necessary to correctly encode such characters.
- *
- * Optionally, the buffer, buffer_size, output, length and dynamic arguments (altogether) can be NULL.
- * In such a case, the XML text in @p input is just checked, the @p input pointer is moved after the XML text, but nothing is stored.
- *
- * @param[in] context XML context to track lines or store errors into libyang context.
- * @param[in,out] input Input string to process, updated according to the processed/read data.
- * @param[in, out] buffer Storage for the output string. If the parameter points to NULL, the buffer is allocated if needed.
- * Otherwise, when needed, the buffer is used and enlarged when necessary. Whenever the buffer is used, the string is NULL-terminated.
- * @param[in, out] buffer_size Allocated size of the returned buffer. If a buffer is provided by a caller, it
- * is not being reduced even if the string is shorter. On the other hand, it can be enlarged if needed.
- * @param[out] output Returns pointer to the resulting string - to the provided/allocated buffer if it was necessary to modify
- * the input string or directly into the input string (see the \p dynamic parameter).
- * @param[out] length Length of the \p output string.
- * @param[out] dynamic Flag if a dynamically allocated memory (\p buffer) was used and caller is supposed to free it at the end.
- * In case the value is zero, the \p output points directly into the \p input string.
- * @return LY_ERR value.
- */
-LY_ERR lyxml_get_string(struct lyxml_context *context, const char **input, char **buffer, size_t *buffer_size, char **output, size_t *length, int *dynamic);
+LY_ERR lyxml_ctx_peek(struct lyxml_ctx *xmlctx, enum LYXML_PARSER_STATUS *next);
 
 /**
  * @brief Get a namespace record for the given prefix in the current context.
  *
- * @param[in] context XML context to work with.
+ * @param[in] xmlctx XML context to work with.
  * @param[in] prefix Pointer to the namespace prefix as taken from lyxml_get_attribute() or lyxml_get_element().
  * Can be NULL for default namespace.
  * @param[in] prefix_len Length of the prefix string (since it is not NULL-terminated when returned from lyxml_get_attribute() or
  * lyxml_get_element()).
  * @return The namespace record or NULL if the record for the specified prefix not found.
  */
-const struct lyxml_ns *lyxml_ns_get(struct lyxml_context *context, const char *prefix, size_t prefix_len);
+const struct lyxml_ns *lyxml_ns_get(struct lyxml_ctx *xmlctx, const char *prefix, size_t prefix_len);
 
 /**
  * @brief Print the given @p text as XML string which replaces some of the characters which cannot appear in XML data.
@@ -200,20 +133,20 @@
 /**
  * @brief Remove the allocated working memory of the context.
  *
- * @param[in] context XML context to clear.
+ * @param[in] xmlctx XML context to clear.
  */
-void lyxml_context_clear(struct lyxml_context *context);
+void lyxml_ctx_free(struct lyxml_ctx *xmlctx);
 
 /**
  * @brief Find all possible prefixes in a value.
  *
- * @param[in] ctx XML context to use.
+ * @param[in] xmlctx XML context to use.
  * @param[in] value Value to check.
  * @param[in] value_len Value length.
  * @param[out] val_prefs Array of found prefixes.
  * @return LY_ERR value.
  */
-LY_ERR lyxml_get_prefixes(struct lyxml_context *ctx, const char *value, size_t value_len, struct ly_prefix **val_prefs);
+LY_ERR lyxml_get_prefixes(struct lyxml_ctx *xmlctx, const char *value, size_t value_len, struct ly_prefix **val_prefs);
 
 /**
  * @brief Compare values and their prefix mappings.