json REFACTOR major rewrite of JSON parser
diff --git a/src/json.c b/src/json.c
index eeb7478..53f41dc 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1,9 +1,10 @@
 /**
  * @file json.c
  * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief Generic JSON format parser for libyang
  *
- * Copyright (c) 2020 CESNET, z.s.p.o.
+ * Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -30,30 +31,30 @@
     switch (status) {
     case LYJSON_ERROR:
         return "error";
-    case LYJSON_ROOT:
-        return "document root";
-    case LYJSON_FALSE:
-        return "false";
-    case LYJSON_TRUE:
-        return "true";
-    case LYJSON_NULL:
-        return "null";
     case LYJSON_OBJECT:
         return "object";
+    case LYJSON_OBJECT_NEXT:
+        return "object next";
     case LYJSON_OBJECT_CLOSED:
         return "object closed";
-    case LYJSON_OBJECT_EMPTY:
-        return "empty object";
     case LYJSON_ARRAY:
         return "array";
+    case LYJSON_ARRAY_NEXT:
+        return "array next";
     case LYJSON_ARRAY_CLOSED:
         return "array closed";
-    case LYJSON_ARRAY_EMPTY:
-        return "empty array";
+    case LYJSON_OBJECT_NAME:
+        return "object name";
     case LYJSON_NUMBER:
         return "number";
     case LYJSON_STRING:
         return "string";
+    case LYJSON_TRUE:
+        return "true";
+    case LYJSON_FALSE:
+        return "false";
+    case LYJSON_NULL:
+        return "null";
     case LYJSON_END:
         return "end of input";
     }
@@ -61,25 +62,48 @@
     return "";
 }
 
-static LY_ERR
-skip_ws(struct lyjson_ctx *jsonctx)
+enum LYJSON_PARSER_STATUS
+lyjson_ctx_status(struct lyjson_ctx *jsonctx)
 {
-    /* skip leading whitespaces */
-    while (*jsonctx->in->current != '\0' && is_jsonws(*jsonctx->in->current)) {
+    assert(jsonctx);
+
+    if (!jsonctx->status.count) {
+        return LYJSON_END;
+    }
+
+    return (enum LYJSON_PARSER_STATUS)(uintptr_t)jsonctx->status.objs[jsonctx->status.count - 1];
+}
+
+uint32_t
+lyjson_ctx_depth(struct lyjson_ctx *jsonctx)
+{
+    return jsonctx->status.count;
+}
+
+/**
+ * @brief Skip WS in the JSON context.
+ *
+ * @param[in] jsonctx JSON parser context.
+ */
+static void
+lyjson_skip_ws(struct lyjson_ctx *jsonctx)
+{
+    /* skip whitespaces */
+    while (is_jsonws(*jsonctx->in->current)) {
         if (*jsonctx->in->current == '\n') {
             LY_IN_NEW_LINE(jsonctx->in);
         }
         ly_in_skip(jsonctx->in, 1);
     }
-    if (*jsonctx->in->current == '\0') {
-        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_END);
-    }
-
-    return LY_SUCCESS;
 }
 
-/*
- * @brief Set value corresponding to the current context's status
+/**
+ * @brief Set value in the JSON context.
+ *
+ * @param[in] jsonctx JSON parser context.
+ * @param[in] value Value to set.
+ * @param[in] value_len Length of @p value.
+ * @param[in] dynamic Whether @p value is dynamically-allocated.
  */
 static void
 lyjson_ctx_set_value(struct lyjson_ctx *jsonctx, const char *value, size_t value_len, ly_bool dynamic)
@@ -94,48 +118,24 @@
     jsonctx->dynamic = dynamic;
 }
 
-static LY_ERR
-lyjson_check_next(struct lyjson_ctx *jsonctx)
-{
-    if (jsonctx->status.count == 1) {
-        /* top level value (JSON-text), ws expected */
-        if ((*jsonctx->in->current == '\0') || is_jsonws(*jsonctx->in->current)) {
-            return LY_SUCCESS;
-        }
-    } else if (lyjson_ctx_status(jsonctx, 1) == LYJSON_OBJECT) {
-        LY_CHECK_RET(skip_ws(jsonctx));
-        if ((*jsonctx->in->current == ',') || (*jsonctx->in->current == '}')) {
-            return LY_SUCCESS;
-        }
-    } else if (lyjson_ctx_status(jsonctx, 1) == LYJSON_ARRAY) {
-        LY_CHECK_RET(skip_ws(jsonctx));
-        if ((*jsonctx->in->current == ',') || (*jsonctx->in->current == ']')) {
-            return LY_SUCCESS;
-        }
-    }
-
-    LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Unexpected character \"%c\" after JSON %s.",
-            *jsonctx->in->current, lyjson_token2str(lyjson_ctx_status(jsonctx, 0)));
-    return LY_EVALID;
-}
-
 /**
- * Input is expected to start after the opening quotation-mark.
- * When succeeds, input is moved after the closing quotation-mark.
+ * @brief Parse a JSON string (starting after double quotes) and store it in the context.
+ *
+ * @param[in] jsonctx JSON parser context.
+ * @return LY_ERR value.
  */
 static LY_ERR
-lyjson_string_(struct lyjson_ctx *jsonctx)
+lyjson_string(struct lyjson_ctx *jsonctx)
 {
-#define BUFSIZE 24
-#define BUFSIZE_STEP 128
-
-    const char *in = jsonctx->in->current, *start;
+    const char *in = jsonctx->in->current, *start, *c;
     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 */
     size_t u;
     uint64_t start_line;
+    uint32_t value;
+    uint8_t i;
 
     assert(jsonctx);
 
@@ -146,17 +146,15 @@
 
     /* parse */
     while (in[offset]) {
-        if (in[offset] == '\\') {
+        switch (in[offset]) {
+        case '\\':
             /* escape sequence */
-            const char *slash = &in[offset];
-            uint32_t value;
-            uint8_t i = 1;
-
+            c = &in[offset];
             if (!buf) {
                 /* prepare output buffer */
-                buf = malloc(BUFSIZE);
+                buf = malloc(LYJSON_STRING_BUF_START);
                 LY_CHECK_ERR_RET(!buf, LOGMEM(jsonctx->ctx), LY_EMEM);
-                size = BUFSIZE;
+                size = LYJSON_STRING_BUF_START;
             }
 
             /* allocate enough for the offset and next character,
@@ -165,10 +163,10 @@
             if (len + offset + 4 >= size) {
                 size_t increment;
 
-                for (increment = BUFSIZE_STEP; len + offset + 4 >= size + increment; increment += BUFSIZE_STEP) {}
+                for (increment = LYJSON_STRING_BUF_STEP; len + offset + 4 >= size + increment; increment += LYJSON_STRING_BUF_STEP) {}
                 buf = ly_realloc(buf, size + increment);
                 LY_CHECK_ERR_RET(!buf, LOGMEM(jsonctx->ctx), LY_EMEM);
-                size += BUFSIZE_STEP;
+                size += LYJSON_STRING_BUF_STEP;
             }
 
             if (offset) {
@@ -179,6 +177,7 @@
                 offset = 0;
             }
 
+            i = 1;
             switch (in[++offset]) {
             case '"':
                 /* quotation mark */
@@ -217,7 +216,7 @@
                 offset++;
                 for (value = i = 0; i < 4; i++) {
                     if (!in[offset + i]) {
-                        LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid basic multilingual plane character \"%s\".", slash);
+                        LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid basic multilingual plane character \"%s\".", c);
                         goto error;
                     } else if (isdigit(in[offset + i])) {
                         u = (in[offset + i] - '0');
@@ -239,13 +238,14 @@
             offset += i;   /* add read escaped characters */
             LY_CHECK_ERR_GOTO(ly_pututf8(&buf[len], value, &u),
                     LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character reference \"%.*s\" (0x%08x).",
-                    (int)(&in[offset] - slash), slash, value),
+                    (int)(&in[offset] - c), c, value),
                     error);
             len += u;      /* update number of bytes in buffer */
             in += offset;  /* move the input by the processed bytes stored in the buffer ... */
             offset = 0;    /* ... and reset the offset index for future moving data into buffer */
+            break;
 
-        } else if (in[offset] == '"') {
+        case '"':
             /* end of string */
             if (buf) {
                 /* realloc exact size string */
@@ -263,22 +263,21 @@
             ++offset;
             in += offset;
             goto success;
-        } else {
-            /* get it as UTF-8 character for check */
-            const char *c = &in[offset];
-            uint32_t code = 0;
-            size_t code_len = 0;
 
-            LY_CHECK_ERR_GOTO(ly_getutf8(&c, &code, &code_len),
+        default:
+            /* get it as UTF-8 character for check */
+            c = &in[offset];
+            LY_CHECK_ERR_GOTO(ly_getutf8(&c, &value, &u),
                     LOGVAL(jsonctx->ctx, LY_VCODE_INCHAR, in[offset]), error);
 
-            LY_CHECK_ERR_GOTO(!is_jsonstrchar(code),
+            LY_CHECK_ERR_GOTO(!is_jsonstrchar(value),
                     LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character in JSON string \"%.*s\" (0x%08x).",
-                    (int)(&in[offset] - start + code_len), start, code),
+                    (int)(&in[offset] - start + u), start, value),
                     error);
 
             /* character is ok, continue */
-            offset += code_len;
+            offset += u;
+            break;
         }
     }
 
@@ -299,24 +298,6 @@
     }
 
     return LY_SUCCESS;
-
-#undef BUFSIZE
-#undef BUFSIZE_STEP
-}
-
-/*
- *
- * Wrapper around lyjson_string_() adding LYJSON_STRING status into context to allow using lyjson_string_() for parsing object's name.
- */
-static LY_ERR
-lyjson_string(struct lyjson_ctx *jsonctx)
-{
-    LY_CHECK_RET(lyjson_string_(jsonctx));
-
-    LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_STRING);
-    LY_CHECK_RET(lyjson_check_next(jsonctx));
-
-    return LY_SUCCESS;
 }
 
 /**
@@ -414,8 +395,7 @@
  * @return Number of characters written to the @p dst.
  */
 static uint32_t
-lyjson_exp_number_copy_num_part(const char *num, uint32_t num_len,
-        char *dec_point, int32_t dp_position, char *dst)
+lyjson_exp_number_copy_num_part(const char *num, uint32_t num_len, char *dec_point, int32_t dp_position, char *dst)
 {
     int32_t dec_point_idx;
     int32_t n, d;
@@ -456,8 +436,8 @@
  * @return LY_ERR value.
  */
 static LY_ERR
-lyjson_exp_number(const struct ly_ctx *ctx, const char *in, const char *exponent,
-        uint64_t total_len, char **res, size_t *res_len)
+lyjson_exp_number(const struct ly_ctx *ctx, const char *in, const char *exponent, uint64_t total_len, char **res,
+        size_t *res_len)
 {
 
 #define MAYBE_WRITE_MINUS(ARRAY, INDEX, FLAG) \
@@ -642,6 +622,12 @@
     return LY_SUCCESS;
 }
 
+/**
+ * @brief Parse a JSON number and store it in the context.
+ *
+ * @param[in] jsonctx JSON parser context.
+ * @return LY_ERR value.
+ */
 static LY_ERR
 lyjson_number(struct lyjson_ctx *jsonctx)
 {
@@ -713,159 +699,16 @@
     }
     ly_in_skip(jsonctx->in, offset);
 
-    LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_NUMBER);
-    LY_CHECK_RET(lyjson_check_next(jsonctx));
-
-    return LY_SUCCESS;
-}
-
-static LY_ERR
-lyjson_object_name(struct lyjson_ctx *jsonctx)
-{
-    if (*jsonctx->in->current != '"') {
-        LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
-                jsonctx->in->current, "a JSON object's member");
-        return LY_EVALID;
-    }
-    ly_in_skip(jsonctx->in, 1);
-
-    LY_CHECK_RET(lyjson_string_(jsonctx));
-    LY_CHECK_RET(skip_ws(jsonctx));
-    if (*jsonctx->in->current != ':') {
-        LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current), jsonctx->in->current,
-                "a JSON object's name-separator ':'");
-        return LY_EVALID;
-    }
-    ly_in_skip(jsonctx->in, 1);
-    LY_CHECK_RET(skip_ws(jsonctx));
-
-    return LY_SUCCESS;
-}
-
-static LY_ERR
-lyjson_object(struct lyjson_ctx *jsonctx)
-{
-    LY_CHECK_RET(skip_ws(jsonctx));
-
-    if (*jsonctx->in->current == '}') {
-        assert(jsonctx->depth);
-        jsonctx->depth--;
-        /* empty object */
-        ly_in_skip(jsonctx->in, 1);
-        lyjson_ctx_set_value(jsonctx, NULL, 0, 0);
-        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT_EMPTY);
-        return LY_SUCCESS;
-    }
-
-    LY_CHECK_RET(lyjson_object_name(jsonctx));
-
-    /* output data are set by lyjson_string_() */
-    LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT);
-
-    return LY_SUCCESS;
-}
-
-/**
- * @brief Process JSON array envelope
- *
- * @param[in] jsonctx JSON parser context
- * @return LY_SUCCESS or LY_EMEM
- */
-static LY_ERR
-lyjson_array(struct lyjson_ctx *jsonctx)
-{
-    LY_CHECK_RET(skip_ws(jsonctx));
-
-    if (*jsonctx->in->current == ']') {
-        /* empty array */
-        ly_in_skip(jsonctx->in, 1);
-        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY_EMPTY);
-    } else {
-        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY);
-    }
-
-    /* erase previous values, array has no value on its own */
-    lyjson_ctx_set_value(jsonctx, NULL, 0, 0);
-
-    return LY_SUCCESS;
-}
-
-static LY_ERR
-lyjson_value(struct lyjson_ctx *jsonctx)
-{
-    if (jsonctx->status.count && (lyjson_ctx_status(jsonctx, 0) == LYJSON_END)) {
-        return LY_SUCCESS;
-    }
-
-    if ((*jsonctx->in->current == 'f') && !strncmp(jsonctx->in->current, "false", ly_strlen_const("false"))) {
-        /* false */
-        lyjson_ctx_set_value(jsonctx, jsonctx->in->current, ly_strlen_const("false"), 0);
-        ly_in_skip(jsonctx->in, ly_strlen_const("false"));
-        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_FALSE);
-        LY_CHECK_RET(lyjson_check_next(jsonctx));
-
-    } else if ((*jsonctx->in->current == 't') && !strncmp(jsonctx->in->current, "true", ly_strlen_const("true"))) {
-        /* true */
-        lyjson_ctx_set_value(jsonctx, jsonctx->in->current, ly_strlen_const("true"), 0);
-        ly_in_skip(jsonctx->in, ly_strlen_const("true"));
-        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_TRUE);
-        LY_CHECK_RET(lyjson_check_next(jsonctx));
-
-    } else if ((*jsonctx->in->current == 'n') && !strncmp(jsonctx->in->current, "null", ly_strlen_const("null"))) {
-        /* none */
-        lyjson_ctx_set_value(jsonctx, "", 0, 0);
-        ly_in_skip(jsonctx->in, ly_strlen_const("null"));
-        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_NULL);
-        LY_CHECK_RET(lyjson_check_next(jsonctx));
-
-    } else if (*jsonctx->in->current == '"') {
-        /* string */
-        ly_in_skip(jsonctx->in, 1);
-        LY_CHECK_RET(lyjson_string(jsonctx));
-
-    } else if (*jsonctx->in->current == '[') {
-        /* array */
-        ly_in_skip(jsonctx->in, 1);
-        LY_CHECK_RET(lyjson_array(jsonctx));
-
-    } else if (*jsonctx->in->current == '{') {
-        jsonctx->depth++;
-
-        /* object */
-        ly_in_skip(jsonctx->in, 1);
-        LY_CHECK_RET(lyjson_object(jsonctx));
-
-    } else if ((*jsonctx->in->current == '-') || ((*jsonctx->in->current >= '0') && (*jsonctx->in->current <= '9'))) {
-        /* number */
-        LY_CHECK_RET(lyjson_number(jsonctx));
-
-    } else {
-        /* unexpected value */
-        LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
-                jsonctx->in->current, "a JSON value");
-        return LY_EVALID;
-    }
-
-    if (jsonctx->depth > LY_MAX_BLOCK_DEPTH) {
-        LOGERR(jsonctx->ctx, LY_EINVAL, "Maximum number %d of block nestings has been exceeded.", LY_MAX_BLOCK_DEPTH);
-        return LY_EINVAL;
-    } else if (jsonctx->status.count > LY_MAX_BLOCK_DEPTH * 10) {
-        LOGERR(jsonctx->ctx, LY_EINVAL, "Maximum number %d of nestings has been exceeded.", LY_MAX_BLOCK_DEPTH * 10);
-        return LY_EINVAL;
-    }
-
     return LY_SUCCESS;
 }
 
 LY_ERR
-lyjson_ctx_new(const struct ly_ctx *ctx, struct ly_in *in, ly_bool subtree, struct lyjson_ctx **jsonctx_p)
+lyjson_ctx_new(const struct ly_ctx *ctx, struct ly_in *in, struct lyjson_ctx **jsonctx_p)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyjson_ctx *jsonctx;
 
-    assert(ctx);
-    assert(in);
-    assert(jsonctx_p);
+    assert(ctx && in && jsonctx_p);
 
     /* new context */
     jsonctx = calloc(1, sizeof *jsonctx);
@@ -875,23 +718,18 @@
 
     LOG_LOCSET(NULL, NULL, NULL, in);
 
-    /* parse JSON value, if any */
-    LY_CHECK_GOTO(ret = skip_ws(jsonctx), cleanup);
-    if (lyjson_ctx_status(jsonctx, 0) == LYJSON_END) {
-        /* empty data input */
+    /* WS are always expected to be skipped */
+    lyjson_skip_ws(jsonctx);
+
+    if (jsonctx->in->current[0] == '\0') {
+        /* empty file, invalid */
+        LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Empty JSON file.");
+        ret = LY_EVALID;
         goto cleanup;
     }
 
-    if (subtree) {
-        ret = lyjson_object(jsonctx);
-        jsonctx->depth++;
-    } else {
-        ret = lyjson_value(jsonctx);
-    }
-    if ((jsonctx->status.count > 1) && (lyjson_ctx_status(jsonctx, 0) == LYJSON_END)) {
-        LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
-        ret = LY_EVALID;
-    }
+    /* start JSON parsing */
+    LY_CHECK_GOTO(ret = lyjson_ctx_next(jsonctx, NULL), cleanup);
 
 cleanup:
     if (ret) {
@@ -902,19 +740,318 @@
     return ret;
 }
 
+/**
+ * @brief Parse next JSON token, object-name is expected.
+ *
+ * @param[in] jsonctx JSON parser context.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyjson_next_object_name(struct lyjson_ctx *jsonctx)
+{
+    switch (*jsonctx->in->current) {
+    case '\0':
+        /* EOF */
+        LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
+        return LY_EVALID;
+
+    case '"':
+        /* object name */
+        ly_in_skip(jsonctx->in, 1);
+        LY_CHECK_RET(lyjson_string(jsonctx));
+        lyjson_skip_ws(jsonctx);
+
+        if (*jsonctx->in->current != ':') {
+            LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current), jsonctx->in->current,
+                    "a JSON value name-separator ':'");
+            return LY_EVALID;
+        }
+        ly_in_skip(jsonctx->in, 1);
+        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT_NAME);
+        break;
+
+    case '}':
+        /* object end */
+        ly_in_skip(jsonctx->in, 1);
+        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT_CLOSED);
+        break;
+
+    default:
+        /* unexpected value */
+        LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
+                jsonctx->in->current, "a JSON object name");
+        return LY_EVALID;
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse next JSON token, value is expected.
+ *
+ * @param[in] jsonctx JSON parser context.
+ * @param[in] array_end Whether array-end is accepted or not.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyjson_next_value(struct lyjson_ctx *jsonctx, ly_bool array_end)
+{
+    switch (*jsonctx->in->current) {
+    case '\0':
+        /* EOF */
+        LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
+        return LY_EVALID;
+
+    case '"':
+        /* string */
+        ly_in_skip(jsonctx->in, 1);
+        LY_CHECK_RET(lyjson_string(jsonctx));
+        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_STRING);
+        break;
+
+    case '-':
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+        /* number */
+        LY_CHECK_RET(lyjson_number(jsonctx));
+        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_NUMBER);
+        break;
+
+    case '{':
+        /* object */
+        ly_in_skip(jsonctx->in, 1);
+        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT);
+        break;
+
+    case '[':
+        /* array */
+        ly_in_skip(jsonctx->in, 1);
+        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY);
+        break;
+
+    case 't':
+        if (strncmp(jsonctx->in->current + 1, "rue", ly_strlen_const("rue"))) {
+            goto unexpected_value;
+        }
+
+        /* true */
+        lyjson_ctx_set_value(jsonctx, jsonctx->in->current, ly_strlen_const("true"), 0);
+        ly_in_skip(jsonctx->in, ly_strlen_const("true"));
+        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_TRUE);
+        break;
+
+    case 'f':
+        if (strncmp(jsonctx->in->current + 1, "alse", ly_strlen_const("alse"))) {
+            goto unexpected_value;
+        }
+
+        /* false */
+        lyjson_ctx_set_value(jsonctx, jsonctx->in->current, ly_strlen_const("false"), 0);
+        ly_in_skip(jsonctx->in, ly_strlen_const("false"));
+        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_FALSE);
+        break;
+
+    case 'n':
+        if (strncmp(jsonctx->in->current + 1, "ull", ly_strlen_const("ull"))) {
+            goto unexpected_value;
+        }
+
+        /* null */
+        lyjson_ctx_set_value(jsonctx, "", 0, 0);
+        ly_in_skip(jsonctx->in, ly_strlen_const("null"));
+        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_NULL);
+        break;
+
+    case ']':
+        if (!array_end) {
+            goto unexpected_value;
+        }
+
+        /* array end */
+        ly_in_skip(jsonctx->in, 1);
+        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY_CLOSED);
+        break;
+
+    default:
+unexpected_value:
+        LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
+                jsonctx->in->current, "a JSON value");
+        return LY_EVALID;
+    }
+
+    if (jsonctx->status.count > LY_MAX_BLOCK_DEPTH * 10) {
+        LOGERR(jsonctx->ctx, LY_EINVAL, "Maximum number %d of nestings has been exceeded.", LY_MAX_BLOCK_DEPTH * 10);
+        return LY_EINVAL;
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse next JSON token, object-next-item is expected.
+ *
+ * @param[in] jsonctx JSON parser context.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyjson_next_object_item(struct lyjson_ctx *jsonctx)
+{
+    switch (*jsonctx->in->current) {
+    case '\0':
+        /* EOF */
+        LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
+        return LY_EVALID;
+
+    case '}':
+        /* object end */
+        ly_in_skip(jsonctx->in, 1);
+        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT_CLOSED);
+        break;
+
+    case ',':
+        /* next object item */
+        ly_in_skip(jsonctx->in, 1);
+        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT_NEXT);
+        break;
+
+    default:
+        /* unexpected value */
+        LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
+                jsonctx->in->current, "a JSON object-end or next item");
+        return LY_EVALID;
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse next JSON token, array-next-item is expected.
+ *
+ * @param[in] jsonctx JSON parser context.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyjson_next_array_item(struct lyjson_ctx *jsonctx)
+{
+    switch (*jsonctx->in->current) {
+    case '\0':
+        /* EOF */
+        LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
+        return LY_EVALID;
+
+    case ']':
+        /* array end */
+        ly_in_skip(jsonctx->in, 1);
+        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY_CLOSED);
+        break;
+
+    case ',':
+        /* next array item */
+        ly_in_skip(jsonctx->in, 1);
+        LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY_NEXT);
+        break;
+
+    default:
+        /* unexpected value */
+        LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
+                jsonctx->in->current, "a JSON array-end or next item");
+        return LY_EVALID;
+    }
+
+    return LY_SUCCESS;
+}
+
+LY_ERR
+lyjson_ctx_next(struct lyjson_ctx *jsonctx, enum LYJSON_PARSER_STATUS *status)
+{
+    LY_ERR ret = LY_SUCCESS;
+    enum LYJSON_PARSER_STATUS cur;
+
+    assert(jsonctx);
+
+    cur = lyjson_ctx_status(jsonctx);
+    switch (cur) {
+    case LYJSON_OBJECT:
+        LY_CHECK_GOTO(ret = lyjson_next_object_name(jsonctx), cleanup);
+        break;
+    case LYJSON_ARRAY:
+        LY_CHECK_GOTO(ret = lyjson_next_value(jsonctx, 1), cleanup);
+        break;
+    case LYJSON_OBJECT_NEXT:
+        LYJSON_STATUS_POP(jsonctx);
+        LY_CHECK_GOTO(ret = lyjson_next_object_name(jsonctx), cleanup);
+        break;
+    case LYJSON_ARRAY_NEXT:
+        LYJSON_STATUS_POP(jsonctx);
+        LY_CHECK_GOTO(ret = lyjson_next_value(jsonctx, 0), cleanup);
+        break;
+    case LYJSON_OBJECT_NAME:
+        lyjson_ctx_set_value(jsonctx, NULL, 0, 0);
+        LYJSON_STATUS_POP(jsonctx);
+        LY_CHECK_GOTO(ret = lyjson_next_value(jsonctx, 0), cleanup);
+        break;
+    case LYJSON_OBJECT_CLOSED:
+    case LYJSON_ARRAY_CLOSED:
+        LYJSON_STATUS_POP(jsonctx);
+    /* fallthrough */
+    case LYJSON_NUMBER:
+    case LYJSON_STRING:
+    case LYJSON_TRUE:
+    case LYJSON_FALSE:
+    case LYJSON_NULL:
+        lyjson_ctx_set_value(jsonctx, NULL, 0, 0);
+        LYJSON_STATUS_POP(jsonctx);
+        cur = lyjson_ctx_status(jsonctx);
+
+        if (cur == LYJSON_OBJECT) {
+            LY_CHECK_GOTO(ret = lyjson_next_object_item(jsonctx), cleanup);
+            break;
+        } else if (cur == LYJSON_ARRAY) {
+            LY_CHECK_GOTO(ret = lyjson_next_array_item(jsonctx), cleanup);
+            break;
+        }
+
+        assert(cur == LYJSON_END);
+        goto cleanup;
+    case LYJSON_END:
+        LY_CHECK_GOTO(ret = lyjson_next_value(jsonctx, 0), cleanup);
+        break;
+    case LYJSON_ERROR:
+        LOGINT(jsonctx->ctx);
+        ret = LY_EINT;
+        goto cleanup;
+    }
+
+    /* skip WS */
+    lyjson_skip_ws(jsonctx);
+
+cleanup:
+    if (!ret && status) {
+        *status = lyjson_ctx_status(jsonctx);
+    }
+    return ret;
+}
+
 void
 lyjson_ctx_backup(struct lyjson_ctx *jsonctx)
 {
     if (jsonctx->backup.dynamic) {
         free((char *)jsonctx->backup.value);
     }
-    jsonctx->backup.status = lyjson_ctx_status(jsonctx, 0);
+    jsonctx->backup.status = lyjson_ctx_status(jsonctx);
     jsonctx->backup.status_count = jsonctx->status.count;
     jsonctx->backup.value = jsonctx->value;
     jsonctx->backup.value_len = jsonctx->value_len;
     jsonctx->backup.input = jsonctx->in->current;
     jsonctx->backup.dynamic = jsonctx->dynamic;
-    jsonctx->backup.depth = jsonctx->depth;
     jsonctx->dynamic = 0;
 }
 
@@ -930,105 +1067,9 @@
     jsonctx->value_len = jsonctx->backup.value_len;
     jsonctx->in->current = jsonctx->backup.input;
     jsonctx->dynamic = jsonctx->backup.dynamic;
-    jsonctx->depth = jsonctx->backup.depth;
     jsonctx->backup.dynamic = 0;
 }
 
-LY_ERR
-lyjson_ctx_next(struct lyjson_ctx *jsonctx, enum LYJSON_PARSER_STATUS *status)
-{
-    LY_ERR ret = LY_SUCCESS;
-    ly_bool toplevel = 0;
-    enum LYJSON_PARSER_STATUS prev;
-
-    assert(jsonctx);
-
-    prev = lyjson_ctx_status(jsonctx, 0);
-
-    if ((prev == LYJSON_OBJECT) || (prev == LYJSON_ARRAY)) {
-        /* get value for the object's member OR the first value in the array */
-        ret = lyjson_value(jsonctx);
-        goto result;
-    } else {
-        /* the previous token is closed and should be completely processed */
-        LYJSON_STATUS_POP_RET(jsonctx);
-        prev = lyjson_ctx_status(jsonctx, 0);
-    }
-
-    if (!jsonctx->status.count) {
-        /* we are done with the top level value */
-        toplevel = 1;
-    }
-    LY_CHECK_RET(skip_ws(jsonctx));
-    if (toplevel && !jsonctx->status.count) {
-        /* EOF expected, but there are some data after the top level token */
-        LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Expecting end-of-input, but some data follows the top level JSON value.");
-        return LY_EVALID;
-    }
-
-    if (toplevel) {
-        /* we are done */
-        goto result;
-    }
-
-    /* continue with the next token */
-    assert(prev == LYJSON_OBJECT || prev == LYJSON_ARRAY);
-
-    if (*jsonctx->in->current == ',') {
-        /* sibling item in the ... */
-        ly_in_skip(jsonctx->in, 1);
-        LY_CHECK_RET(skip_ws(jsonctx));
-
-        if (prev == LYJSON_OBJECT) {
-            /* ... object - get another object's member */
-            ret = lyjson_object_name(jsonctx);
-        } else { /* LYJSON_ARRAY */
-            /* ... array - get another complete value */
-            ret = lyjson_value(jsonctx);
-        }
-    } else if (((prev == LYJSON_OBJECT) && (*jsonctx->in->current == '}')) ||
-            ((prev == LYJSON_ARRAY) && (*jsonctx->in->current == ']'))) {
-        if (*jsonctx->in->current == '}') {
-            assert(jsonctx->depth);
-            jsonctx->depth--;
-        }
-        ly_in_skip(jsonctx->in, 1);
-        LYJSON_STATUS_POP_RET(jsonctx);
-        LYJSON_STATUS_PUSH_RET(jsonctx, prev + 1);
-    } else {
-        /* unexpected value */
-        LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current), jsonctx->in->current,
-                prev == LYJSON_ARRAY ? "another JSON value in array" : "another JSON object's member");
-        return LY_EVALID;
-    }
-
-result:
-    if ((ret == LY_SUCCESS) && (jsonctx->status.count > 1) && (lyjson_ctx_status(jsonctx, 0) == LYJSON_END)) {
-        LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
-        ret = LY_EVALID;
-    }
-
-    if ((ret == LY_SUCCESS) && status) {
-        *status = lyjson_ctx_status(jsonctx, 0);
-    }
-
-    return ret;
-}
-
-enum LYJSON_PARSER_STATUS
-lyjson_ctx_status(struct lyjson_ctx *jsonctx, uint32_t index)
-{
-    assert(jsonctx);
-
-    if (jsonctx->status.count < index) {
-        return LYJSON_ERROR;
-    } else if (jsonctx->status.count == index) {
-        return LYJSON_ROOT;
-    } else {
-        return (enum LYJSON_PARSER_STATUS)(uintptr_t)jsonctx->status.objs[jsonctx->status.count - (index + 1)];
-    }
-}
-
 void
 lyjson_ctx_free(struct lyjson_ctx *jsonctx)
 {
diff --git a/src/json.h b/src/json.h
index 53efe2a..61c561a 100644
--- a/src/json.h
+++ b/src/json.h
@@ -1,9 +1,10 @@
 /**
  * @file json.h
  * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief Generic JSON format parser routines.
  *
- * Copyright (c) 2020 CESNET, z.s.p.o.
+ * Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -24,6 +25,9 @@
 struct ly_ctx;
 struct ly_in;
 
+#define LYJSON_STRING_BUF_START 24
+#define LYJSON_STRING_BUF_STEP 128
+
 /* Macro to test if character is whitespace */
 #define is_jsonws(c) (c == 0x20 || c == 0x9 || c == 0xa || c == 0xd)
 
@@ -35,27 +39,27 @@
     LY_CHECK_RET(ly_set_add(&CTX->status, (void *)(uintptr_t)(STATUS), 1, NULL))
 
 /* Macro to pop JSON parser status */
-#define LYJSON_STATUS_POP_RET(CTX) \
+#define LYJSON_STATUS_POP(CTX) \
     assert(CTX->status.count); CTX->status.count--;
 
 /**
  * @brief Status of the parser providing information what is expected next (which function is supposed to be called).
  */
 enum LYJSON_PARSER_STATUS {
-    LYJSON_ERROR,          /* JSON parser error - value is used as an error return code */
-    LYJSON_ROOT,           /* JSON document root, used internally */
-    LYJSON_OBJECT,         /* JSON object */
-    LYJSON_OBJECT_CLOSED,  /* JSON object closed */
-    LYJSON_OBJECT_EMPTY,   /* empty JSON object { } */
-    LYJSON_ARRAY,          /* JSON array */
-    LYJSON_ARRAY_CLOSED,   /* JSON array closed */
-    LYJSON_ARRAY_EMPTY,    /* empty JSON array */
-    LYJSON_NUMBER,         /* JSON number value */
-    LYJSON_STRING,         /* JSON string value */
-    LYJSON_FALSE,          /* JSON false value */
-    LYJSON_TRUE,           /* JSON true value */
-    LYJSON_NULL,           /* JSON null value */
-    LYJSON_END             /* end of input data */
+    LYJSON_ERROR = 0,       /* JSON parser error - value is used as an error return code */
+    LYJSON_OBJECT,          /* JSON object */
+    LYJSON_OBJECT_NEXT,     /* JSON object next item */
+    LYJSON_OBJECT_CLOSED,   /* JSON object closed */
+    LYJSON_ARRAY,           /* JSON array */
+    LYJSON_ARRAY_NEXT,      /* JSON array next item */
+    LYJSON_ARRAY_CLOSED,    /* JSON array closed */
+    LYJSON_OBJECT_NAME,     /* JSON object name */
+    LYJSON_NUMBER,          /* JSON number value */
+    LYJSON_STRING,          /* JSON string value */
+    LYJSON_TRUE,            /* JSON true value */
+    LYJSON_FALSE,           /* JSON false value */
+    LYJSON_NULL,            /* JSON null value */
+    LYJSON_END              /* end of input data */
 };
 
 struct lyjson_ctx {
@@ -64,10 +68,9 @@
 
     struct ly_set status;   /* stack of ::LYJSON_PARSER_STATUS values corresponding to the JSON items being processed */
 
-    const char *value;      /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT */
-    size_t value_len;       /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT */
-    ly_bool dynamic;        /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT */
-    uint32_t depth;         /* current number of nested blocks, see ::LY_MAX_BLOCK_DEPTH */
+    const char *value;      /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT_NAME */
+    size_t value_len;       /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT_NAME */
+    ly_bool dynamic;        /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT_NAME */
 
     struct {
         enum LYJSON_PARSER_STATUS status;
@@ -75,32 +78,11 @@
         const char *value;
         size_t value_len;
         ly_bool dynamic;
-        uint32_t depth;
         const char *input;
     } backup;
 };
 
 /**
- * @brief Create a new JSON parser context and start parsing.
- *
- * @param[in] ctx libyang context.
- * @param[in] in JSON string data to parse.
- * @param[in] subtree Whether this is a special case of parsing a subtree (starting with object name).
- * @param[out] jsonctx New JSON context with status referring the parsed value.
- * @return LY_ERR value.
- */
-LY_ERR lyjson_ctx_new(const struct ly_ctx *ctx, struct ly_in *in, ly_bool subtree, struct lyjson_ctx **jsonctx);
-
-/**
- * @brief Get status of the parser as the last/previous parsed token
- *
- * @param[in] jsonctx JSON context to check.
- * @param[in] index Index of the token, starting by 0 for the last token
- * @return ::LYJSON_ERROR in case of invalid index, other ::LYJSON_PARSER_STATUS corresponding to the token.
- */
-enum LYJSON_PARSER_STATUS lyjson_ctx_status(struct lyjson_ctx *jsonctx, uint32_t index);
-
-/**
  * @brief Get string representation of the JSON context status (token).
  *
  * @param[in] status Context status (aka JSON token)
@@ -109,6 +91,33 @@
 const char *lyjson_token2str(enum LYJSON_PARSER_STATUS status);
 
 /**
+ * @brief Get current status of the parser.
+ *
+ * @param[in] jsonctx JSON parser context to check.
+ * @return ::LYJSON_PARSER_STATUS according to the last parsed token.
+ */
+enum LYJSON_PARSER_STATUS lyjson_ctx_status(struct lyjson_ctx *jsonctx);
+
+/**
+ * @brief Get current nesting (object/array) depth.
+ *
+ * @param[in] jsonctx JSON parser context to check.
+ * @return Current nesting depth.
+ */
+uint32_t lyjson_ctx_depth(struct lyjson_ctx *jsonctx);
+
+/**
+ * @brief Create a new JSON parser context and start parsing.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] in JSON string data to parse.
+ * @param[in] subtree Whether this is a special case of parsing a subtree (starting with object name).
+ * @param[out] jsonctx New JSON parser context with status referring the parsed value.
+ * @return LY_ERR value.
+ */
+LY_ERR lyjson_ctx_new(const struct ly_ctx *ctx, struct ly_in *in, struct lyjson_ctx **jsonctx);
+
+/**
  * @brief Move to the next JSON artifact and update parser status.
  *
  * @param[in] jsonctx XML context to move.
@@ -119,12 +128,14 @@
 
 /**
  * @brief Backup the JSON parser context's state To restore the backup, use ::lyjson_ctx_restore().
+ *
  * @param[in] jsonctx JSON parser context to backup.
  */
 void lyjson_ctx_backup(struct lyjson_ctx *jsonctx);
 
 /**
- * @brief REstore the JSON parser context's state from the backup created by ::lyjson_ctx_backup().
+ * @brief Restore the JSON parser context's state from the backup created by ::lyjson_ctx_backup().
+ *
  * @param[in] jsonctx JSON parser context to restore.
  */
 void lyjson_ctx_restore(struct lyjson_ctx *jsonctx);
@@ -132,7 +143,7 @@
 /**
  * @brief Remove the allocated working memory of the context.
  *
- * @param[in] jsonctx JSON context to clear.
+ * @param[in] jsonctx JSON parser context to clear.
  */
 void lyjson_ctx_free(struct lyjson_ctx *jsonctx);
 
diff --git a/src/parser_json.c b/src/parser_json.c
index 4c9858e..3abb1b5 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -4,7 +4,7 @@
  * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief JSON data parser for libyang
  *
- * Copyright (c) 2020 - 2022 CESNET, z.s.p.o.
+ * Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -195,36 +195,39 @@
 lydjson_data_skip(struct lyjson_ctx *jsonctx)
 {
     enum LYJSON_PARSER_STATUS status, current;
-    uint32_t orig_depth;
+    uint32_t depth;
 
-    status = lyjson_ctx_status(jsonctx, 0);
-    orig_depth = jsonctx->depth;
+    status = lyjson_ctx_status(jsonctx);
+    depth = lyjson_ctx_depth(jsonctx);
 
-    /* next */
-    LY_CHECK_RET(lyjson_ctx_next(jsonctx, &current));
+    switch (status) {
+    case LYJSON_OBJECT:
+        ++depth;
 
-    if ((status != LYJSON_OBJECT) && (status != LYJSON_ARRAY)) {
-        return LY_SUCCESS;
-    }
-
-    if ((status == LYJSON_OBJECT) && (current != LYJSON_OBJECT) && (current != LYJSON_ARRAY)) {
-        /* no nested objects */
-        return LY_SUCCESS;
-    }
-
-    /* skip after the content */
-    while ((jsonctx->depth > orig_depth) || (current != status + 1)) {
-        if (current == LYJSON_ARRAY) {
-            /* skip the array separately */
-            LY_CHECK_RET(lydjson_data_skip(jsonctx));
-            current = lyjson_ctx_status(jsonctx, 0);
-        } else {
+        /* skip until object closes */
+        do {
             LY_CHECK_RET(lyjson_ctx_next(jsonctx, &current));
-        }
+        } while ((current != LYJSON_OBJECT_CLOSED) || (depth != lyjson_ctx_depth(jsonctx)));
+        break;
+    case LYJSON_ARRAY:
+        ++depth;
 
-        if (current == LYJSON_END) {
-            break;
+        /* skip until array closes */
+        do {
+            LY_CHECK_RET(lyjson_ctx_next(jsonctx, &current));
+        } while ((current != LYJSON_ARRAY_CLOSED) || (depth != lyjson_ctx_depth(jsonctx)));
+        break;
+    case LYJSON_OBJECT_NAME:
+        /* just get to the value */
+        LY_CHECK_RET(lyjson_ctx_next(jsonctx, &current));
+        if ((current == LYJSON_OBJECT) || (current == LYJSON_ARRAY)) {
+            LY_CHECK_RET(lydjson_data_skip(jsonctx));
         }
+        break;
+    default:
+        /* no other status expected */
+        LOGINT(jsonctx->ctx);
+        return LY_EINT;
     }
 
     return LY_SUCCESS;
@@ -347,30 +350,34 @@
 static LY_ERR
 lydjson_check_list(struct lyjson_ctx *jsonctx, const struct lysc_node *list)
 {
-    LY_ERR ret = LY_SUCCESS;
-    enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(jsonctx, 0);
+    LY_ERR rc = LY_SUCCESS;
+    enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(jsonctx);
     struct ly_set key_set = {0};
     const struct lysc_node *snode;
-    uint32_t i, status_count;
+    uint32_t i;
 
     assert(list && (list->nodetype == LYS_LIST));
 
     /* get all keys into a set (keys do not have if-features or anything) */
     snode = NULL;
     while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
-        ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
-        LY_CHECK_GOTO(ret, cleanup);
+        rc = ly_set_add(&key_set, (void *)snode, 1, NULL);
+        LY_CHECK_GOTO(rc, cleanup);
+    }
+    if (!key_set.count) {
+        /* no keys */
+        goto cleanup;
     }
 
     if (status == LYJSON_OBJECT) {
-        status_count = jsonctx->status.count;
-
-        while (key_set.count && (status != LYJSON_OBJECT_CLOSED)) {
+        do {
             const char *name, *prefix;
             size_t name_len, prefix_len;
             ly_bool is_attr;
 
             /* match the key */
+            LY_CHECK_GOTO(rc = lyjson_ctx_next(jsonctx, &status), cleanup);
+            assert(status == LYJSON_OBJECT_NAME);
             snode = NULL;
             lydjson_parse_name(jsonctx->value, jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
 
@@ -381,45 +388,43 @@
                         break;
                     }
                 }
-                /* go into the item to a) process it as a key or b) start skipping it as another list child */
-                ret = lyjson_ctx_next(jsonctx, &status);
-                LY_CHECK_GOTO(ret, cleanup);
+
+                /* get the value */
+                LY_CHECK_GOTO(rc = lyjson_ctx_next(jsonctx, &status), cleanup);
 
                 if (snode) {
                     /* we have the key, validate the value */
-                    if (status < LYJSON_NUMBER) {
+                    if ((status < LYJSON_NUMBER) && (status > LYJSON_NULL)) {
                         /* not a terminal */
-                        ret = LY_ENOT;
+                        rc = LY_ENOT;
                         goto cleanup;
                     }
 
-                    ret = lys_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_VALUE_JSON, NULL);
-                    LY_CHECK_GOTO(ret, cleanup);
+                    rc = lys_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_VALUE_JSON, NULL);
+                    LY_CHECK_GOTO(rc, cleanup);
 
                     /* key with a valid value, remove from the set */
                     ly_set_rm_index(&key_set, i, NULL);
                 }
+
+                /* next object */
+                LY_CHECK_GOTO(rc = lyjson_ctx_next(jsonctx, &status), cleanup);
             } else {
-                /* start skipping the member we are not interested in */
-                ret = lyjson_ctx_next(jsonctx, &status);
-                LY_CHECK_GOTO(ret, cleanup);
+                /* skip the uninteresting object */
+                LY_CHECK_GOTO(rc = lydjson_data_skip(jsonctx), cleanup);
+                LY_CHECK_GOTO(rc = lyjson_ctx_next(jsonctx, &status), cleanup);
             }
-            /* move to the next child */
-            while (status_count < jsonctx->status.count) {
-                ret = lyjson_ctx_next(jsonctx, &status);
-                LY_CHECK_GOTO(ret, cleanup);
-            }
-        }
+        } while (key_set.count && (status == LYJSON_OBJECT_NEXT));
     }
 
     if (key_set.count) {
         /* some keys are missing/did not validate */
-        ret = LY_ENOT;
+        rc = LY_ENOT;
     }
 
 cleanup:
     ly_set_erase(&key_set, NULL);
-    return ret;
+    return rc;
 }
 
 /**
@@ -448,7 +453,7 @@
         }
 
         LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, NULL));
-        if (lyjson_ctx_status(lydctx->jsonctx, 0) != LYJSON_ARRAY_CLOSED) {
+        if (lyjson_ctx_status(lydctx->jsonctx) != LYJSON_ARRAY_CLOSED) {
             LOGVAL(lydctx->jsonctx->ctx, LYVE_SYNTAX_JSON, "Expected array end, but input data contains %s.",
                     lyjson_token2str(*status_p));
             return LY_EINVAL;
@@ -502,7 +507,7 @@
 
     /* backup parser */
     lyjson_ctx_backup(jsonctx);
-    status = lyjson_ctx_status(jsonctx, 0);
+    status = lyjson_ctx_status(jsonctx);
 
     if (lydctx->parse_opts & LYD_PARSE_OPAQ) {
         /* check if the node is parseable. if not, NULL the snode to announce that it is supposed to be parsed
@@ -529,7 +534,6 @@
             break;
         }
     } else if (snode->nodetype & LYD_NODE_TERM) {
-        status = lyjson_ctx_status(jsonctx, 0);
         ret = lydjson_value_type_hint(lydctx, &status, type_hint_p);
     }
 
@@ -715,7 +719,7 @@
 static LY_ERR
 lydjson_metadata(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, struct lyd_node *node)
 {
-    LY_ERR ret = LY_SUCCESS;
+    LY_ERR rc = LY_SUCCESS;
     enum LYJSON_PARSER_STATUS status;
     const char *expected;
     ly_bool in_parent = 0;
@@ -735,33 +739,29 @@
     LOG_LOCSET(snode, NULL, NULL, NULL);
 
     /* move to the second item in the name/X pair */
-    ret = lyjson_ctx_next(lydctx->jsonctx, &status);
-    LY_CHECK_GOTO(ret, cleanup);
+    LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
 
     /* check attribute encoding */
     switch (nodetype) {
     case LYS_LEAFLIST:
         expected = "@name/array of objects/nulls";
-
         LY_CHECK_GOTO(status != LYJSON_ARRAY, representation_error);
 
 next_entry:
-        instance++;
-
-        /* move into array/next entry */
-        ret = lyjson_ctx_next(lydctx->jsonctx, &status);
-        LY_CHECK_GOTO(ret, cleanup);
-
         if (status == LYJSON_ARRAY_CLOSED) {
             /* no more metadata */
             goto cleanup;
         }
+
+        /* move into the array/next item */
+        LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
+        instance++;
         LY_CHECK_GOTO((status != LYJSON_OBJECT) && (status != LYJSON_NULL), representation_error);
 
         if (!node || (node->schema != prev->schema)) {
             LOGVAL(lydctx->jsonctx->ctx, LYVE_REFERENCE, "Missing JSON data instance #%u of %s:%s to be coupled with metadata.",
                     instance, prev->schema->module->name, prev->schema->name);
-            ret = LY_EVALID;
+            rc = LY_EVALID;
             goto cleanup;
         }
 
@@ -769,6 +769,8 @@
             /* continue with the next entry in the leaf-list array */
             prev = node;
             node = node->next;
+
+            LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
             goto next_entry;
         }
         break;
@@ -790,31 +792,31 @@
         break;
     default:
         LOGINT(ctx);
-        ret = LY_EINT;
+        rc = LY_EINT;
         goto cleanup;
     }
 
     /* process all the members inside a single metadata object */
     assert(status == LYJSON_OBJECT);
-    while (status != LYJSON_OBJECT_CLOSED) {
-        LY_CHECK_GOTO(status != LYJSON_OBJECT, representation_error);
-
+    do {
+        LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
+        assert(status == LYJSON_OBJECT_NAME);
         lydjson_parse_name(lydctx->jsonctx->value, lydctx->jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_attr);
         lyjson_ctx_give_dynamic_value(lydctx->jsonctx, &dynamic_prefname);
 
         if (!name_len) {
             LOGVAL(ctx, LYVE_SYNTAX_JSON, "Metadata in JSON found with an empty name, followed by: %.10s", name);
-            ret = LY_EVALID;
+            rc = LY_EVALID;
             goto cleanup;
         } else if (!prefix_len) {
             LOGVAL(ctx, LYVE_SYNTAX_JSON, "Metadata in JSON must be namespace-qualified, missing prefix for \"%.*s\".",
                     (int)lydctx->jsonctx->value_len, lydctx->jsonctx->value);
-            ret = LY_EVALID;
+            rc = LY_EVALID;
             goto cleanup;
         } else if (is_attr) {
             LOGVAL(ctx, LYVE_SYNTAX_JSON, "Invalid format of the Metadata identifier in JSON, unexpected '@' in \"%.*s\"",
                     (int)lydctx->jsonctx->value_len, lydctx->jsonctx->value);
-            ret = LY_EVALID;
+            rc = LY_EVALID;
             goto cleanup;
         }
 
@@ -824,14 +826,13 @@
             if (lydctx->parse_opts & LYD_PARSE_STRICT) {
                 LOGVAL(ctx, LYVE_REFERENCE, "Prefix \"%.*s\" of the metadata \"%.*s\" does not match any module in the context.",
                         (int)prefix_len, prefix, (int)name_len, name);
-                ret = LY_EVALID;
+                rc = LY_EVALID;
                 goto cleanup;
             }
             if (node->schema) {
                 /* skip element with children */
-                ret = lydjson_data_skip(lydctx->jsonctx);
-                LY_CHECK_GOTO(ret, cleanup);
-                status = lyjson_ctx_status(lydctx->jsonctx, 0);
+                LY_CHECK_GOTO(rc = lydjson_data_skip(lydctx->jsonctx), cleanup);
+                status = lyjson_ctx_status(lydctx->jsonctx);
                 /* end of the item */
                 continue;
             }
@@ -839,22 +840,20 @@
         }
 
         /* get the value */
-        ret = lyjson_ctx_next(lydctx->jsonctx, &status);
-        LY_CHECK_GOTO(ret, cleanup);
+        LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
 
         /* get value hints */
-        ret = lydjson_value_type_hint(lydctx, &status, &val_hints);
-        LY_CHECK_GOTO(ret, cleanup);
+        LY_CHECK_GOTO(rc = lydjson_value_type_hint(lydctx, &status, &val_hints), cleanup);
 
         if (node->schema) {
             /* create metadata */
-            ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, node, NULL, mod, name, name_len, lydctx->jsonctx->value,
+            rc = lyd_parser_create_meta((struct lyd_ctx *)lydctx, node, NULL, mod, name, name_len, lydctx->jsonctx->value,
                     lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic, LY_VALUE_JSON, NULL, val_hints, node->schema);
-            LY_CHECK_GOTO(ret, cleanup);
+            LY_CHECK_GOTO(rc, cleanup);
 
             /* add/correct flags */
-            ret = lyd_parse_set_data_flags(node, &node->meta, (struct lyd_ctx *)lydctx, NULL);
-            LY_CHECK_GOTO(ret, cleanup);
+            rc = lyd_parse_set_data_flags(node, &node->meta, (struct lyd_ctx *)lydctx, NULL);
+            LY_CHECK_GOTO(rc, cleanup);
         } else {
             /* create attribute */
             const char *module_name;
@@ -863,22 +862,24 @@
             lydjson_get_node_prefix(node, prefix, prefix_len, &module_name, &module_name_len);
 
             /* attr2 is always changed to the created attribute */
-            ret = lyd_create_attr(node, NULL, lydctx->jsonctx->ctx, name, name_len, prefix, prefix_len, module_name,
+            rc = lyd_create_attr(node, NULL, lydctx->jsonctx->ctx, name, name_len, prefix, prefix_len, module_name,
                     module_name_len, lydctx->jsonctx->value, lydctx->jsonctx->value_len, &lydctx->jsonctx->dynamic,
                     LY_VALUE_JSON, NULL, val_hints);
-            LY_CHECK_GOTO(ret, cleanup);
+            LY_CHECK_GOTO(rc, cleanup);
         }
+
         /* next member */
-        ret = lyjson_ctx_next(lydctx->jsonctx, &status);
-        LY_CHECK_GOTO(ret, cleanup);
-        LY_CHECK_GOTO((status != LYJSON_OBJECT) && (status != LYJSON_OBJECT_CLOSED), representation_error);
-    }
+        LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
+    } while (status == LYJSON_OBJECT_NEXT);
+    LY_CHECK_GOTO(status != LYJSON_OBJECT_CLOSED, representation_error);
 
     if (nodetype == LYS_LEAFLIST) {
         /* continue by processing another metadata object for the following
          * leaf-list instance since they are always instantiated in JSON array */
         prev = node;
         node = node->next;
+
+        LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
         goto next_entry;
     }
 
@@ -890,12 +891,12 @@
             "The attribute(s) of %s \"%s\" is expected to be represented as JSON %s, but input data contains @%s/%s.",
             lys_nodetype2str(nodetype), node ? LYD_NAME(node) : LYD_NAME(prev), expected, lyjson_token2str(status),
             in_parent ? "" : "name");
-    ret = LY_EVALID;
+    rc = LY_EVALID;
 
 cleanup:
     free(dynamic_prefname);
     LOG_LOCBACK(1, 0, 0, 0);
-    return ret;
+    return rc;
 }
 
 /**
@@ -959,7 +960,7 @@
     ly_bool dynamic = 0;
     uint32_t type_hint = 0;
 
-    if ((*status_inner_p != LYJSON_OBJECT) && (*status_inner_p != LYJSON_OBJECT_EMPTY)) {
+    if (*status_inner_p != LYJSON_OBJECT) {
         /* prepare for creating opaq node with a value */
         value = lydctx->jsonctx->value;
         value_len = lydctx->jsonctx->value_len;
@@ -1024,18 +1025,17 @@
         goto finish;
     }
 
-    while ((*status_p == LYJSON_ARRAY) || (*status_p == LYJSON_ARRAY_EMPTY)) {
+    while (*status_p == LYJSON_ARRAY) {
         /* process another instance of the same node */
-
-        if ((*status_inner_p == LYJSON_OBJECT) || (*status_inner_p == LYJSON_OBJECT_EMPTY)) {
+        if (*status_inner_p == LYJSON_OBJECT) {
             /* array with objects, list */
             ((struct lyd_node_opaq *)*node_p)->hints |= LYD_NODEHINT_LIST;
 
             /* but first process children of the object in the array */
-            while ((*status_inner_p != LYJSON_OBJECT_CLOSED) && (*status_inner_p != LYJSON_OBJECT_EMPTY)) {
+            do {
                 LY_CHECK_RET(lydjson_subtree_r(lydctx, *node_p, lyd_node_child_p(*node_p), NULL));
-                *status_inner_p = lyjson_ctx_status(lydctx->jsonctx, 0);
-            }
+                *status_inner_p = lyjson_ctx_status(lydctx->jsonctx);
+            } while (*status_inner_p == LYJSON_OBJECT_NEXT);
         } else {
             /* array with values, leaf-list */
             ((struct lyd_node_opaq *)*node_p)->hints |= LYD_NODEHINT_LEAFLIST;
@@ -1045,19 +1045,21 @@
         if (*status_inner_p == LYJSON_ARRAY_CLOSED) {
             goto finish;
         }
+        assert(*status_inner_p == LYJSON_ARRAY_NEXT);
 
         /* continue with the next instance */
+        LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_inner_p));
         assert(node_p);
         lydjson_maintain_children(parent, first_p, node_p, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0, NULL);
         LY_CHECK_RET(lydjson_create_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status_inner_p, node_p));
     }
 
-    if ((*status_p == LYJSON_OBJECT) || (*status_p == LYJSON_OBJECT_EMPTY)) {
+    if (*status_p == LYJSON_OBJECT) {
         /* process children */
-        while (*status_p != LYJSON_OBJECT_CLOSED && *status_p != LYJSON_OBJECT_EMPTY) {
+        do {
             LY_CHECK_RET(lydjson_subtree_r(lydctx, *node_p, lyd_node_child_p(*node_p), NULL));
-            *status_p = lyjson_ctx_status(lydctx->jsonctx, 0);
-        }
+            *status_p = lyjson_ctx_status(lydctx->jsonctx);
+        } while (*status_p == LYJSON_OBJECT_NEXT);
     }
 
 finish:
@@ -1086,8 +1088,8 @@
  * @return LY_ERR value.
  */
 static LY_ERR
-lydjson_ctx_next_parse_opaq(struct lyd_json_ctx *lydctx, const char *name, size_t name_len,
-        const char *prefix, size_t prefix_len, struct lyd_node *parent, enum LYJSON_PARSER_STATUS *status_p,
+lydjson_ctx_next_parse_opaq(struct lyd_json_ctx *lydctx, const char *name, size_t name_len, const char *prefix,
+        size_t prefix_len, struct lyd_node *parent, enum LYJSON_PARSER_STATUS *status_p,
         struct lyd_node **first_p, struct lyd_node **node_p)
 {
     enum LYJSON_PARSER_STATUS status_inner = 0;
@@ -1228,17 +1230,18 @@
     uint32_t prev_parse_opts, prev_int_opts;
     struct ly_in in_start;
     char *val = NULL;
+    const char *end;
     struct lyd_node *tree = NULL;
 
     assert(snode->nodetype & LYD_NODE_ANY);
 
     /* status check according to allowed JSON types */
     if (snode->nodetype == LYS_ANYXML) {
-        LY_CHECK_RET((*status != LYJSON_OBJECT) && (*status != LYJSON_OBJECT_EMPTY) && (*status != LYJSON_ARRAY) &&
-                (*status != LYJSON_ARRAY_EMPTY) && (*status != LYJSON_NUMBER) && (*status != LYJSON_STRING) &&
-                (*status != LYJSON_FALSE) && (*status != LYJSON_TRUE) && (*status != LYJSON_NULL), LY_ENOT);
+        LY_CHECK_RET((*status != LYJSON_OBJECT) && (*status != LYJSON_ARRAY) && (*status != LYJSON_NUMBER) &&
+                (*status != LYJSON_STRING) && (*status != LYJSON_FALSE) && (*status != LYJSON_TRUE) &&
+                (*status != LYJSON_NULL), LY_ENOT);
     } else {
-        LY_CHECK_RET((*status != LYJSON_OBJECT) && (*status != LYJSON_OBJECT_EMPTY), LY_ENOT);
+        LY_CHECK_RET(*status != LYJSON_OBJECT, LY_ENOT);
     }
 
     /* create any node */
@@ -1253,12 +1256,12 @@
         lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
 
         /* process the anydata content */
-        while (*status != LYJSON_OBJECT_CLOSED) {
+        do {
             r = lydjson_subtree_r(lydctx, NULL, &tree, NULL);
             LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
 
-            *status = lyjson_ctx_status(lydctx->jsonctx, 0);
-        }
+            *status = lyjson_ctx_status(lydctx->jsonctx);
+        } while (*status == LYJSON_OBJECT_NEXT);
 
         /* restore parser options */
         lydctx->parse_opts = prev_parse_opts;
@@ -1271,22 +1274,19 @@
         r = lyd_create_any(snode, tree, LYD_ANYDATA_DATATREE, 1, node);
         LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
         break;
-    case LYJSON_ARRAY_EMPTY:
-        /* store the empty array */
-        if (asprintf(&val, "[]") == -1) {
-            LOGMEM(lydctx->jsonctx->ctx);
-            return LY_EMEM;
-        }
-        r = lyd_create_any(snode, val, LYD_ANYDATA_JSON, 1, node);
-        LY_CHECK_ERR_GOTO(r, rc = r, val_err);
-        break;
     case LYJSON_ARRAY:
         /* skip until the array end */
         in_start = *lydctx->jsonctx->in;
         LY_CHECK_RET(lydjson_data_skip(lydctx->jsonctx));
 
+        /* return back by all the WS */
+        end = lydctx->jsonctx->in->current;
+        while (is_jsonws(end[-1])) {
+            --end;
+        }
+
         /* make a copy of the whole array and store it */
-        if (asprintf(&val, "[%.*s", (int)(lydctx->jsonctx->in->current - in_start.current), in_start.current) == -1) {
+        if (asprintf(&val, "[%.*s", (int)(end - in_start.current), in_start.current) == -1) {
             LOGMEM(lydctx->jsonctx->ctx);
             return LY_EMEM;
         }
@@ -1322,11 +1322,6 @@
         r = lyd_create_any(snode, NULL, LYD_ANYDATA_JSON, 1, node);
         LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
         break;
-    case LYJSON_OBJECT_EMPTY:
-        /* empty object */
-        r = lyd_create_any(snode, NULL, LYD_ANYDATA_DATATREE, 1, node);
-        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
-        break;
     default:
         LOGINT_RET(lydctx->jsonctx->ctx);
     }
@@ -1358,7 +1353,7 @@
     LY_ERR r, rc = LY_SUCCESS;
     uint32_t prev_parse_opts = lydctx->parse_opts;
 
-    LY_CHECK_RET((*status != LYJSON_OBJECT) && (*status != LYJSON_OBJECT_EMPTY), LY_ENOT);
+    LY_CHECK_RET(*status != LYJSON_OBJECT, LY_ENOT);
 
     /* create inner node */
     LY_CHECK_RET(lyd_create_inner(snode, node));
@@ -1372,12 +1367,12 @@
     }
 
     /* process children */
-    while ((*status != LYJSON_OBJECT_CLOSED) && (*status != LYJSON_OBJECT_EMPTY)) {
+    do {
         r = lydjson_subtree_r(lydctx, *node, lyd_node_child_p(*node), NULL);
         LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
 
-        *status = lyjson_ctx_status(lydctx->jsonctx, 0);
-    }
+        *status = lyjson_ctx_status(lydctx->jsonctx);
+    } while (*status == LYJSON_OBJECT_NEXT);
 
     /* finish linking metadata */
     r = lydjson_metadata_finish(lydctx, lyd_node_child_p(*node));
@@ -1520,7 +1515,7 @@
 lydjson_subtree_r(struct lyd_json_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_set *parsed)
 {
     LY_ERR r, rc = LY_SUCCESS;
-    enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(lydctx->jsonctx, 0);
+    enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(lydctx->jsonctx);
     const char *name, *prefix = NULL, *expected = NULL;
     size_t name_len, prefix_len = 0;
     ly_bool is_meta = 0, parse_subtree;
@@ -1531,13 +1526,21 @@
     char *value = NULL;
 
     assert(parent || first_p);
-    assert(status == LYJSON_OBJECT);
+    assert((status == LYJSON_OBJECT) || (status == LYJSON_OBJECT_NEXT));
 
     parse_subtree = lydctx->parse_opts & LYD_PARSE_SUBTREE ? 1 : 0;
     /* all descendants should be parsed */
     lydctx->parse_opts &= ~LYD_PARSE_SUBTREE;
 
+    r = lyjson_ctx_next(lydctx->jsonctx, &status);
+    LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+    if (status == LYJSON_OBJECT_CLOSED) {
+        /* empty object, fine... */
+        goto cleanup;
+    }
+
     /* process the node name */
+    assert(status == LYJSON_OBJECT_NAME);
     lydjson_parse_name(lydctx->jsonctx->value, lydctx->jsonctx->value_len, &name, &name_len, &prefix, &prefix_len, &is_meta);
     lyjson_ctx_give_dynamic_value(lydctx->jsonctx, &value);
 
@@ -1643,18 +1646,18 @@
         switch (snode->nodetype) {
         case LYS_LEAFLIST:
         case LYS_LIST:
-            if (status == LYJSON_ARRAY_EMPTY) {
-                /* no instances, skip */
-                break;
-            }
             LY_CHECK_GOTO(status != LYJSON_ARRAY, representation_error);
 
-            /* move into array */
-            r = lyjson_ctx_next(lydctx->jsonctx, &status);
-            LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
-
             /* process all the values/objects */
             do {
+                /* move into array/next value */
+                r = lyjson_ctx_next(lydctx->jsonctx, &status);
+                LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
+                if (status == LYJSON_ARRAY_CLOSED) {
+                    /* empty array, fine... */
+                    break;
+                }
+
                 r = lydjson_parse_instance(lydctx, parent, first_p, snode, ext, name, name_len, prefix, prefix_len,
                         &status, &node);
                 if (r == LY_ENOT) {
@@ -1667,7 +1670,7 @@
                 /* move after the item(s) */
                 r = lyjson_ctx_next(lydctx->jsonctx, &status);
                 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
-            } while (status != LYJSON_ARRAY_CLOSED);
+            } while (status == LYJSON_ARRAY_NEXT);
 
             break;
         case LYS_LEAF:
@@ -1735,20 +1738,17 @@
  * @param[in] parse_opts Options for parser, see @ref dataparseroptions.
  * @param[in] val_opts Options for the validation phase, see @ref datavalidationoptions.
  * @param[out] lydctx_p Data parser context to finish validation.
- * @param[out] status Storage for the current context's status
  * @return LY_ERR value.
  */
 static LY_ERR
 lyd_parse_json_init(const struct ly_ctx *ctx, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts,
-        struct lyd_json_ctx **lydctx_p, enum LYJSON_PARSER_STATUS *status)
+        struct lyd_json_ctx **lydctx_p)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyd_json_ctx *lydctx;
-    size_t i;
-    ly_bool subtree;
+    enum LYJSON_PARSER_STATUS status;
 
     assert(lydctx_p);
-    assert(status);
 
     /* init context */
     lydctx = calloc(1, sizeof *lydctx);
@@ -1757,28 +1757,20 @@
     lydctx->val_opts = val_opts;
     lydctx->free = lyd_json_ctx_free;
 
-    /* starting top-level */
-    for (i = 0; in->current[i] != '\0' && is_jsonws(in->current[i]); i++) {
-        if (in->current[i] == '\n') {
-            /* new line */
-            LY_IN_NEW_LINE(in);
-        }
-    }
+    LY_CHECK_ERR_RET(ret = lyjson_ctx_new(ctx, in, &lydctx->jsonctx), free(lydctx), ret);
+    status = lyjson_ctx_status(lydctx->jsonctx);
 
-    subtree = (parse_opts & LYD_PARSE_SUBTREE) ? 1 : 0;
-    LY_CHECK_ERR_RET(ret = lyjson_ctx_new(ctx, in, subtree, &lydctx->jsonctx), free(lydctx), ret);
-    *status = lyjson_ctx_status(lydctx->jsonctx, 0);
-
-    if ((*status == LYJSON_END) || (*status == LYJSON_OBJECT_EMPTY) || (*status == LYJSON_OBJECT)) {
-        *lydctx_p = lydctx;
-        return LY_SUCCESS;
-    } else {
+    /* parse_opts & LYD_PARSE_SUBTREE not implemented */
+    if (status != LYJSON_OBJECT) {
         /* expecting top-level object */
-        LOGVAL(ctx, LYVE_SYNTAX_JSON, "Expected top-level JSON object, but %s found.", lyjson_token2str(*status));
+        LOGVAL(ctx, LYVE_SYNTAX_JSON, "Expected top-level JSON object, but %s found.", lyjson_token2str(status));
         *lydctx_p = NULL;
         lyd_json_ctx_free((struct lyd_ctx *)lydctx);
         return LY_EVALID;
     }
+
+    *lydctx_p = lydctx;
+    return LY_SUCCESS;
 }
 
 LY_ERR
@@ -1790,10 +1782,8 @@
     struct lyd_json_ctx *lydctx = NULL;
     enum LYJSON_PARSER_STATUS status;
 
-    rc = lyd_parse_json_init(ctx, in, parse_opts, val_opts, &lydctx, &status);
-    LY_CHECK_GOTO(rc || status == LYJSON_END || status == LYJSON_OBJECT_EMPTY, cleanup);
-
-    assert(status == LYJSON_OBJECT);
+    rc = lyd_parse_json_init(ctx, in, parse_opts, val_opts, &lydctx);
+    LY_CHECK_GOTO(rc, cleanup);
 
     lydctx->int_opts = int_opts;
     lydctx->ext = ext;
@@ -1802,20 +1792,20 @@
     LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
 
     /* read subtree(s) */
-    while (status == LYJSON_OBJECT) {
+    do {
         r = lydjson_subtree_r(lydctx, parent, first_p, parsed);
         LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
 
-        status = lyjson_ctx_status(lydctx->jsonctx, 0);
+        status = lyjson_ctx_status(lydctx->jsonctx);
 
         if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
             break;
         }
-    }
+    } while (status == LYJSON_OBJECT_NEXT);
     assert((status == LYJSON_END) || (status == LYJSON_OBJECT_CLOSED));
 
     if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && lydctx->jsonctx->in->current[0] &&
-            (lyjson_ctx_status(lydctx->jsonctx, 0) != LYJSON_OBJECT_CLOSED)) {
+            (lyjson_ctx_status(lydctx->jsonctx) != LYJSON_OBJECT_CLOSED)) {
         LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
         r = LY_EVALID;
         LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
diff --git a/tests/utests/basic/test_json.c b/tests/utests/basic/test_json.c
index e6774d4..08b7719 100644
--- a/tests/utests/basic/test_json.c
+++ b/tests/utests/basic/test_json.c
@@ -27,39 +27,40 @@
     /* empty */
     str = "";
     assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
-    lyjson_ctx_free(jsonctx);
+    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    CHECK_LOG_CTX("Empty JSON file.", "Line number 1.");
 
     str = "  \n\t \n";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
-    lyjson_ctx_free(jsonctx);
+    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    CHECK_LOG_CTX("Empty JSON file.", "Line number 3.");
 
     /* constant values */
     str = "true";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_TRUE, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_TRUE, lyjson_ctx_status(jsonctx));
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
     lyjson_ctx_free(jsonctx);
 
     str = "false";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_FALSE, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_FALSE, lyjson_ctx_status(jsonctx));
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
     lyjson_ctx_free(jsonctx);
 
     str = "null";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx));
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
     lyjson_ctx_free(jsonctx);
 
     ly_in_free(in, 0);
@@ -75,8 +76,8 @@
     /* simple value */
     str = "11";
     assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("11", jsonctx->value);
     assert_int_equal(2, jsonctx->value_len);
     assert_int_equal(0, jsonctx->dynamic);
@@ -85,8 +86,8 @@
     /* fraction number */
     str = "37.7668";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("37.7668", jsonctx->value);
     assert_int_equal(7, jsonctx->value_len);
     assert_int_equal(0, jsonctx->dynamic);
@@ -95,8 +96,8 @@
     /* negative number */
     str = "-122.3959";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("-122.3959", jsonctx->value);
     assert_int_equal(9, jsonctx->value_len);
     assert_int_equal(0, jsonctx->dynamic);
@@ -105,8 +106,8 @@
     /* integer, positive exponent */
     str = "550E3";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("550000", jsonctx->value);
     assert_int_equal(6, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -114,8 +115,8 @@
 
     str = "-550E3";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("-550000", jsonctx->value);
     assert_int_equal(7, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -124,8 +125,8 @@
     /* integer, negative exponent */
     str = "1E-1";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("0.1", jsonctx->value);
     assert_int_equal(3, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -133,8 +134,8 @@
 
     str = "15E-1";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("1.5", jsonctx->value);
     assert_int_equal(3, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -142,8 +143,8 @@
 
     str = "-15E-1";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("-1.5", jsonctx->value);
     assert_int_equal(4, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -151,8 +152,8 @@
 
     str = "16E-2";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("0.16", jsonctx->value);
     assert_int_equal(4, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -160,8 +161,8 @@
 
     str = "-16E-2";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("-0.16", jsonctx->value);
     assert_int_equal(5, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -169,8 +170,8 @@
 
     str = "17E-3";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("0.017", jsonctx->value);
     assert_int_equal(5, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -178,8 +179,8 @@
 
     str = "-17E-3";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("-0.017", jsonctx->value);
     assert_int_equal(6, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -187,8 +188,8 @@
 
     str = "21000E-2";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("210", jsonctx->value);
     assert_int_equal(3, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -196,8 +197,8 @@
 
     str = "21000E-4";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("2.1", jsonctx->value);
     assert_int_equal(3, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -205,8 +206,8 @@
 
     str = "21000E-7";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("0.0021", jsonctx->value);
     assert_int_equal(6, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -215,8 +216,8 @@
     /* decimal number, positive exponent */
     str = "5.087E1";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("50.87", jsonctx->value);
     assert_int_equal(5, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -224,8 +225,8 @@
 
     str = "-5.087E1";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("-50.87", jsonctx->value);
     assert_int_equal(6, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -233,8 +234,8 @@
 
     str = "5.087E5";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("508700", jsonctx->value);
     assert_int_equal(6, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -242,8 +243,8 @@
 
     str = "59.1e+1";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("591", jsonctx->value);
     assert_int_equal(3, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -251,8 +252,8 @@
 
     str = "0.005087E1";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("0.05087", jsonctx->value);
     assert_int_equal(7, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -260,8 +261,8 @@
 
     str = "0.005087E2";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("0.5087", jsonctx->value);
     assert_int_equal(6, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -269,8 +270,8 @@
 
     str = "0.005087E6";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("5087", jsonctx->value);
     assert_int_equal(4, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -278,8 +279,8 @@
 
     str = "0.05087E6";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("50870", jsonctx->value);
     assert_int_equal(5, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -287,8 +288,8 @@
 
     str = "0.005087E8";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("508700", jsonctx->value);
     assert_int_equal(6, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -297,8 +298,8 @@
     /* decimal number, negative exponent */
     str = "35.94e-1";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("3.594", jsonctx->value);
     assert_int_equal(5, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -306,8 +307,8 @@
 
     str = "-35.94e-1";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("-3.594", jsonctx->value);
     assert_int_equal(6, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -315,8 +316,8 @@
 
     str = "35.94e-2";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("0.3594", jsonctx->value);
     assert_int_equal(6, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -324,8 +325,8 @@
 
     str = "35.94e-3";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("0.03594", jsonctx->value);
     assert_int_equal(7, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -333,8 +334,8 @@
 
     str = "0.3594e-1";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("0.03594", jsonctx->value);
     assert_int_equal(7, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -342,8 +343,8 @@
 
     str = "0.03594e-1";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("0.003594", jsonctx->value);
     assert_int_equal(8, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -351,8 +352,8 @@
 
     str = "0.003594e-1";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("0.0003594", jsonctx->value);
     assert_int_equal(9, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -360,8 +361,8 @@
 
     str = "0.3594e-2";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("0.003594", jsonctx->value);
     assert_int_equal(8, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -369,8 +370,8 @@
 
     str = "0.03594e-2";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("0.0003594", jsonctx->value);
     assert_int_equal(9, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -378,8 +379,8 @@
 
     str = "0.003594e-2";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("0.00003594", jsonctx->value);
     assert_int_equal(10, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -388,8 +389,8 @@
     /* zero */
     str = "0";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_true(jsonctx->value[0] == '0');
     assert_int_equal(1, jsonctx->value_len);
     assert_int_equal(0, jsonctx->dynamic);
@@ -397,8 +398,8 @@
 
     str = "-0";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_true(jsonctx->value[0] == '-');
     assert_true(jsonctx->value[1] == '0');
     assert_int_equal(2, jsonctx->value_len);
@@ -407,8 +408,8 @@
 
     str = "94E0";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_true(jsonctx->value[0] == '9');
     assert_true(jsonctx->value[1] == '4');
     assert_int_equal(2, jsonctx->value_len);
@@ -417,8 +418,8 @@
 
     str = "0E2";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_true(jsonctx->value[0] == '0');
     assert_int_equal(1, jsonctx->value_len);
     assert_int_equal(0, jsonctx->dynamic);
@@ -426,8 +427,8 @@
 
     str = "-0E2";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_true(jsonctx->value[0] == '-');
     assert_true(jsonctx->value[1] == '0');
     assert_int_equal(2, jsonctx->value_len);
@@ -436,8 +437,8 @@
 
     str = "5.320e+2";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("532", jsonctx->value);
     assert_int_equal(3, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -445,8 +446,8 @@
 
     str = "5.320e-1";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
     assert_string_equal("0.532", jsonctx->value);
     assert_int_equal(5, jsonctx->value_len);
     assert_int_equal(1, jsonctx->dynamic);
@@ -455,69 +456,64 @@
     /* various invalid inputs */
     str = "-x";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
     CHECK_LOG_CTX("Invalid character in JSON Number value (\"x\").", "Line number 1.");
 
     str = "  -";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
     CHECK_LOG_CTX("Unexpected end-of-input.", "Line number 1.");
 
     str = "--1";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
     CHECK_LOG_CTX("Invalid character in JSON Number value (\"-\").", "Line number 1.");
 
     str = "+1";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
     CHECK_LOG_CTX("Invalid character sequence \"+1\", expected a JSON value.", "Line number 1.");
 
     str = "  1.x ";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
     CHECK_LOG_CTX("Invalid character in JSON Number value (\"x\").", "Line number 1.");
 
     str = "1.";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
     CHECK_LOG_CTX("Unexpected end-of-input.", "Line number 1.");
 
     str = "  1eo ";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
     CHECK_LOG_CTX("Invalid character in JSON Number value (\"o\").", "Line number 1.");
 
     str = "1e";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
     CHECK_LOG_CTX("Unexpected end-of-input.", "Line number 1.");
 
     str = "1E1000";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
     CHECK_LOG_CTX("Number encoded as a string exceeded the LY_NUMBER_MAXLEN limit.", "Line number 1.");
 
     str = "1e9999999999999999999";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
     CHECK_LOG_CTX("Exponent out-of-bounds in a JSON Number value (1e9999999999999999999).", "Line number 1.");
 
     str = "1.1e66000";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
     CHECK_LOG_CTX("Exponent out-of-bounds in a JSON Number value (1.1e66000).", "Line number 1.");
 
     str = "1.1e-66000";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
     CHECK_LOG_CTX("Exponent out-of-bounds in a JSON Number value (1.1e-66000).", "Line number 1.");
 
-    str = "-2.1e0.";
-    assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    CHECK_LOG_CTX("Unexpected character \".\" after JSON number.", "Line number 1.");
-
     ly_in_free(in, 0);
 }
 
@@ -535,7 +531,7 @@
     /* unterminated string */
     str = "\"unterminated string";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
     CHECK_LOG_CTX("Missing quotation-mark at the end of a JSON string.", "Line number 1.");
     CHECK_LOG_CTX("Unexpected end-of-input.", "Line number 1.");
 
@@ -552,95 +548,122 @@
     /* empty */
     str = "  { }  ";
     assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_OBJECT_EMPTY, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
+
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
     lyjson_ctx_free(jsonctx);
 
     /* simple value */
     str = "{\"name\" : \"Radek\"}";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx, 0));
+
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
+
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+    assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
     assert_ptr_equal(&str[2], jsonctx->value);
     assert_int_equal(4, jsonctx->value_len);
     assert_int_equal(0, jsonctx->dynamic);
-    assert_string_equal("\"Radek\"}", jsonctx->in->current);
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx));
     assert_string_equal("Radek\"}", jsonctx->value);
     assert_int_equal(5, jsonctx->value_len);
     assert_int_equal(0, jsonctx->dynamic);
-    assert_string_equal("}", jsonctx->in->current);
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
     lyjson_ctx_free(jsonctx);
 
     /* two values */
     str = "{\"smart\" : true,\"handsom\":false}";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
+
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+    assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
     assert_string_equal("smart\" : true,\"handsom\":false}", jsonctx->value);
     assert_int_equal(5, jsonctx->value_len);
     assert_int_equal(0, jsonctx->dynamic);
-    assert_string_equal("true,\"handsom\":false}", jsonctx->in->current);
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_TRUE, lyjson_ctx_status(jsonctx, 0));
-    assert_string_equal(",\"handsom\":false}", jsonctx->in->current);
+    assert_int_equal(LYJSON_TRUE, lyjson_ctx_status(jsonctx));
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_OBJECT_NEXT, lyjson_ctx_status(jsonctx));
+
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+    assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
     assert_string_equal("handsom\":false}", jsonctx->value);
     assert_int_equal(7, jsonctx->value_len);
     assert_int_equal(0, jsonctx->dynamic);
-    assert_string_equal("false}", jsonctx->in->current);
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_FALSE, lyjson_ctx_status(jsonctx, 0));
-    assert_string_equal("}", jsonctx->in->current);
+    assert_int_equal(LYJSON_FALSE, lyjson_ctx_status(jsonctx));
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
     lyjson_ctx_free(jsonctx);
 
     /* inherited objects */
     str = "{\"person\" : {\"name\":\"Radek\"}}";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
+
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+    assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
     assert_string_equal("person\" : {\"name\":\"Radek\"}}", jsonctx->value);
     assert_int_equal(6, jsonctx->value_len);
     assert_int_equal(0, jsonctx->dynamic);
-    assert_string_equal("{\"name\":\"Radek\"}}", jsonctx->in->current);
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
+
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+    assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
     assert_string_equal("name\":\"Radek\"}}", jsonctx->value);
     assert_int_equal(4, jsonctx->value_len);
     assert_int_equal(0, jsonctx->dynamic);
-    assert_string_equal("\"Radek\"}}", jsonctx->in->current);
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx));
     assert_string_equal("Radek\"}}", jsonctx->value);
     assert_int_equal(5, jsonctx->value_len);
     assert_int_equal(0, jsonctx->dynamic);
-    assert_string_equal("}}", jsonctx->in->current);
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx, 0));
-    assert_string_equal("}", jsonctx->in->current);
+    assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
     lyjson_ctx_free(jsonctx);
 
-    /* new line is allowed only as escaped character in JSON */
+    /* unquoted string */
     str = "{ unquoted : \"data\"}";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    CHECK_LOG_CTX("Invalid character sequence \"unquoted : \"data\"}\", expected a JSON object's member.", "Line number 1.");
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
+
+    assert_int_equal(LY_EVALID, lyjson_ctx_next(jsonctx, NULL));
+    CHECK_LOG_CTX("Invalid character sequence \"unquoted : \"data\"}\", expected a JSON object name.", "Line number 1.");
+    lyjson_ctx_free(jsonctx);
 
     ly_in_free(in, 0);
 }
@@ -655,67 +678,79 @@
     /* empty */
     str = "  [  ]  ";
     assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_ARRAY_EMPTY, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx));
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_ARRAY_CLOSED, lyjson_ctx_status(jsonctx));
+
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
     lyjson_ctx_free(jsonctx);
 
     /* simple value */
     str = "[ null]";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx));
     assert_null(jsonctx->value);
     assert_int_equal(0, jsonctx->value_len);
     assert_int_equal(0, jsonctx->dynamic);
-    assert_string_equal("null]", jsonctx->in->current);
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx, 0));
-    assert_string_equal("]", jsonctx->in->current);
+    assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx));
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_ARRAY_CLOSED, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_ARRAY_CLOSED, lyjson_ctx_status(jsonctx));
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
     lyjson_ctx_free(jsonctx);
 
     /* two values */
     str = "[{\"a\":null},\"x\"]";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
-    assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
+    assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx));
     assert_null(jsonctx->value);
     assert_int_equal(0, jsonctx->value_len);
     assert_int_equal(0, jsonctx->dynamic);
-    assert_string_equal("{\"a\":null},\"x\"]", jsonctx->in->current);
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
+
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+    assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
     assert_string_equal("a\":null},\"x\"]", jsonctx->value);
     assert_int_equal(1, jsonctx->value_len);
     assert_int_equal(0, jsonctx->dynamic);
-    assert_string_equal("null},\"x\"]", jsonctx->in->current);
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx, 0));
-    assert_string_equal("},\"x\"]", jsonctx->in->current);
+    assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx));
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx, 0));
-    assert_string_equal(",\"x\"]", jsonctx->in->current);
+    assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_ARRAY_NEXT, lyjson_ctx_status(jsonctx));
+
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
+    assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx));
     assert_string_equal("x\"]", jsonctx->value);
     assert_int_equal(1, jsonctx->value_len);
     assert_int_equal(0, jsonctx->dynamic);
-    assert_string_equal("]", jsonctx->in->current);
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_ARRAY_CLOSED, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_ARRAY_CLOSED, lyjson_ctx_status(jsonctx));
+
     assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
-    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0));
+    assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
     lyjson_ctx_free(jsonctx);
 
     /* new line is allowed only as escaped character in JSON */
     str = "[ , null]";
     assert_non_null(ly_in_memory(in, str));
-    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx));
+    assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
     assert_int_equal(LY_EVALID, lyjson_ctx_next(jsonctx, NULL));
     CHECK_LOG_CTX("Invalid character sequence \", null]\", expected a JSON value.", "Line number 1.");
     lyjson_ctx_free(jsonctx);
diff --git a/tests/utests/data/test_validation.c b/tests/utests/data/test_validation.c
index 17a7433..a953330 100644
--- a/tests/utests/data/test_validation.c
+++ b/tests/utests/data/test_validation.c
@@ -1219,7 +1219,7 @@
     CHECK_LOG_CTX_APPTAG("Too few \"ll\" instances.", "Schema location \"/ii:cont/ll\".", "too-few-elements");
     CHECK_LOG_CTX_APPTAG("l leaf is not left", "Data location \"/ii:cont/l3\".", "not-left");
     CHECK_LOG_CTX_APPTAG("Must condition \"../l = 'right'\" not satisfied.", "Data location \"/ii:cont/l2\".", "must-violation");
-    CHECK_LOG_CTX_APPTAG("Duplicate instance of \"l\".", "Data location \"/ii:cont/l\", line number 8.", NULL);
+    CHECK_LOG_CTX_APPTAG("Duplicate instance of \"l\".", "Data location \"/ii:cont/l\", line number 9.", NULL);
     CHECK_LOG_CTX_APPTAG("Invalid non-number-encoded uint32 value \"ahoy\".", "Data location \"/ii:cont/ll\", line number 7.", NULL);
 
     /* validation */
@@ -1511,7 +1511,7 @@
             "  }\n"
             "}\n", LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
     CHECK_LOG_CTX("Data for both cases \"v0\" and \"v2\" exist.",
-            "Data location \"/k:ch\", line number 5.");
+            "Data location \"/k:ch\", line number 6.");
 
     CHECK_PARSE_LYD_PARAM(
             "{\n"
@@ -1521,7 +1521,7 @@
             "  }\n"
             "}\n", LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
     CHECK_LOG_CTX("Data for both cases \"v0\" and \"v2\" exist.",
-            "Data location \"/k:ch\", line number 5.");
+            "Data location \"/k:ch\", line number 6.");
 }
 
 int
diff --git a/tests/utests/types/int8.c b/tests/utests/types/int8.c
index 14b1852..198d1f7 100644
--- a/tests/utests/types/int8.c
+++ b/tests/utests/types/int8.c
@@ -1243,10 +1243,10 @@
     TEST_SUCCESS_JSON("T0", "127", INT8, "127", 127);
     /* leading zeros */
     TEST_ERROR_JSON("T0", "015");
-    CHECK_LOG_CTX("Unexpected character \"1\" after JSON number.",
+    CHECK_LOG_CTX("Invalid character sequence \"15}\", expected a JSON object-end or next item.",
             "Line number 1.");
     TEST_ERROR_JSON("T0", "-015");
-    CHECK_LOG_CTX("Unexpected character \"1\" after JSON number.",
+    CHECK_LOG_CTX("Invalid character sequence \"15}\", expected a JSON object-end or next item.",
             "Line number 1.");
     TEST_ERROR_JSON("defs", "+50");
     CHECK_LOG_CTX("Invalid character sequence \"+50}\", expected a JSON value.",
diff --git a/tests/utests/types/string.c b/tests/utests/types/string.c
index a64a552..68c1d0a 100644
--- a/tests/utests/types/string.c
+++ b/tests/utests/types/string.c
@@ -868,7 +868,7 @@
     CHECK_LOG_CTX("Invalid character reference \"\\f\" (0x0000000c).", "Line number 1.");
 
     TEST_ERROR_JSON("T0", "\"");
-    CHECK_LOG_CTX("Unexpected character \"\"\" after JSON string.", "Line number 1.");
+    CHECK_LOG_CTX("Invalid character sequence \"\"}\", expected a JSON object-end or next item.", "Line number 1.");
 
     TEST_ERROR_JSON("T0", "aabb \\x");
     CHECK_LOG_CTX("Invalid character escape sequence \\x.", "Line number 1.");