parser FEATURE support for faster ordered parsing
diff --git a/src/parser_data.h b/src/parser_data.h
index 6b4aeea..47759f1 100644
--- a/src/parser_data.h
+++ b/src/parser_data.h
@@ -151,6 +151,12 @@
 #define LYD_PARSE_LYB_MOD_UPDATE  0x100000  /**< Only for LYB format, allow parsing data printed using a specific module
                                                  revision to be loaded even with a module with the same name but newer
                                                  revision. */
+#define LYD_PARSE_ORDERED 0x200000          /**< Do not search for the correct place of each node but instead expect
+                                                 that the nodes are being parsed in the correct schema-based order,
+                                                 which is always true if the data were printed by libyang and not
+                                                 modified manually. If this flag is used incorrectly (for unordered data),
+                                                 the behavior is undefined and most functions executed with these
+                                                 data will not work correctly. */
 
 #define LYD_PARSE_OPTS_MASK 0xFFFF0000      /**< Mask for all the LYD_PARSE_ options. */
 
diff --git a/src/parser_json.c b/src/parser_json.c
index ca11b31..ebb1449 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -847,18 +847,20 @@
 }
 
 /**
- * @brief Eat the node pointed by @p node_p by inserting it into @p parent and maintain the @p first_p pointing to the first child node.
+ * @brief Eat the node pointed by @p node_p by inserting it into @p parent and maintain the @p first_p pointing
+ * to the first child node.
  *
  * @param[in] parent Parent node to insert to, can be NULL in case of top-level (or provided first_p).
- * @param[in, out] first_p Pointer to the first sibling node in case of top-level.
- * @param[in, out] node_p pointer to the new node to insert, after the insert is done, pointer is set to NULL.
+ * @param[in,out] first_p Pointer to the first sibling node in case of top-level.
+ * @param[in,out] node_p pointer to the new node to insert, after the insert is done, pointer is set to NULL.
+ * @param[in] last If set, always insert at the end.
  */
 static void
-lydjson_maintain_children(struct lyd_node_inner *parent, struct lyd_node **first_p, struct lyd_node **node_p)
+lydjson_maintain_children(struct lyd_node_inner *parent, struct lyd_node **first_p, struct lyd_node **node_p, ly_bool last)
 {
     if (*node_p) {
         /* insert, keep first pointer correct */
-        lyd_insert_node(parent ? &parent->node : NULL, first_p, *node_p);
+        lyd_insert_node(parent ? &parent->node : NULL, first_p, *node_p, last);
         if (first_p) {
             if (parent) {
                 *first_p = parent->child;
@@ -971,7 +973,7 @@
 
         /* continue with the next instance */
         assert(node_p);
-        lydjson_maintain_children(parent, first_p, node_p);
+        lydjson_maintain_children(parent, first_p, node_p, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
         ret = lydjson_create_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status_inner_p, node_p);
         LY_CHECK_RET(ret);
     }
@@ -1331,7 +1333,8 @@
 
             /* process all the values/objects */
             do {
-                lydjson_maintain_children((struct lyd_node_inner *)parent, first_p, &node);
+                lydjson_maintain_children((struct lyd_node_inner *)parent, first_p, &node,
+                        lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
 
                 ret = lydjson_parse_instance(lydctx, (struct lyd_node_inner *)parent, first_p, snode, name, name_len,
                         prefix, prefix_len, &status, &node);
@@ -1383,7 +1386,8 @@
     }
 
     /* finally connect the parsed node */
-    lydjson_maintain_children((struct lyd_node_inner *)parent, first_p, &node);
+    lydjson_maintain_children((struct lyd_node_inner *)parent, first_p, &node,
+            lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
 
     /* rememeber a successfully parsed node */
     if (parsed) {
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index 3c8578f..78496fc 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -957,7 +957,7 @@
     }
 
     /* insert, keep first pointer correct */
-    lyd_insert_node(parent, first_p, node);
+    lyd_insert_node(parent, first_p, node, lybctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
     while (!parent && (*first_p)->prev->next) {
         *first_p = (*first_p)->prev;
     }
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 3e46ad4..787d29f 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -696,7 +696,7 @@
     }
 
     /* insert, keep first pointer correct */
-    lyd_insert_node(parent, first_p, node);
+    lyd_insert_node(parent, first_p, node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
     while (!parent && (*first_p)->prev->next) {
         *first_p = (*first_p)->prev;
     }
@@ -817,7 +817,7 @@
     r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
     if (r == LY_SUCCESS) {
         /* insert */
-        lyd_insert_node(*envp, NULL, child);
+        lyd_insert_node(*envp, NULL, child, 0);
 
         /* NETCONF action */
         *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
@@ -871,7 +871,7 @@
     LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
 
     /* insert */
-    lyd_insert_node(*envp, NULL, child);
+    lyd_insert_node(*envp, NULL, child, 0);
 
     /* validate value */
     /* TODO validate child->value as yang:date-and-time */
@@ -954,7 +954,7 @@
     }
 
     /* insert */
-    lyd_insert_node(parent, NULL, child);
+    lyd_insert_node(parent, NULL, child, 1);
 
 cleanup:
     lyd_free_attr_siblings(xmlctx->ctx, attr);
@@ -1080,7 +1080,7 @@
         LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
 
         /* insert */
-        lyd_insert_node(parent, NULL, child);
+        lyd_insert_node(parent, NULL, child, 1);
     }
 
     return LY_SUCCESS;
@@ -1255,7 +1255,7 @@
         LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
 
         /* insert */
-        lyd_insert_node(parent, NULL, child);
+        lyd_insert_node(parent, NULL, child, 1);
     }
 
     return LY_SUCCESS;
@@ -1299,7 +1299,7 @@
     r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
     if (r == LY_SUCCESS) {
         /* insert */
-        lyd_insert_node(*envp, NULL, child);
+        lyd_insert_node(*envp, NULL, child, 1);
 
         /* finish child parsing */
         if (xmlctx->status != LYXML_ELEM_CLOSE) {
@@ -1330,7 +1330,7 @@
         }
 
         /* insert */
-        lyd_insert_node(*envp, NULL, child);
+        lyd_insert_node(*envp, NULL, child, 1);
 
         /* parse all children of "rpc-error" */
         LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
diff --git a/src/tree_data.c b/src/tree_data.c
index 1230f8d..93d3da7 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -736,7 +736,7 @@
     /* create and insert all the keys */
     LY_ARRAY_FOR(predicates, u) {
         LY_CHECK_GOTO(ret = lyd_create_term2(predicates[u].key, &predicates[u].value, &key), cleanup);
-        lyd_insert_node(list, NULL, key);
+        lyd_insert_node(list, NULL, key, 0);
     }
 
     /* hash having all the keys */
@@ -882,7 +882,7 @@
 
     LY_CHECK_RET(lyd_create_inner(schema, &ret));
     if (parent) {
-        lyd_insert_node(parent, NULL, ret);
+        lyd_insert_node(parent, NULL, ret, 0);
     }
 
     if (node) {
@@ -967,11 +967,11 @@
 
         rc = lyd_create_term(key_s, key_val, key_len, NULL, format, NULL, LYD_HINT_DATA, NULL, &key);
         LY_CHECK_GOTO(rc, cleanup);
-        lyd_insert_node(ret, NULL, key);
+        lyd_insert_node(ret, NULL, key, 1);
     }
 
     if (parent) {
-        lyd_insert_node(parent, NULL, ret);
+        lyd_insert_node(parent, NULL, ret, 0);
     }
 
 cleanup:
@@ -1063,7 +1063,7 @@
         rc = lyd_create_term(key_s, key_val, key_val ? strlen(key_val) : 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA,
                 NULL, &key);
         LY_CHECK_GOTO(rc, cleanup);
-        lyd_insert_node(ret, NULL, key);
+        lyd_insert_node(ret, NULL, key, 1);
     }
 
 cleanup:
@@ -1105,7 +1105,7 @@
         LY_CHECK_RET(lyd_create_list2(schema, keys, strlen(keys), &ret));
     }
     if (parent) {
-        lyd_insert_node(parent, NULL, ret);
+        lyd_insert_node(parent, NULL, ret, 0);
     }
 
     if (node) {
@@ -1149,7 +1149,7 @@
     rc = lyd_create_term(schema, value, value_len, NULL, format, NULL, LYD_HINT_DATA, NULL, &ret);
     LY_CHECK_RET(rc);
     if (parent) {
-        lyd_insert_node(parent, NULL, ret);
+        lyd_insert_node(parent, NULL, ret, 0);
     }
 
     if (node) {
@@ -1226,7 +1226,7 @@
 
     LY_CHECK_RET(lyd_create_any(schema, value, value_type, use_value, &ret));
     if (parent) {
-        lyd_insert_node(parent, NULL, ret);
+        lyd_insert_node(parent, NULL, ret, 0);
     }
 
     if (node) {
@@ -1361,7 +1361,7 @@
     LY_CHECK_RET(lyd_create_opaq(ctx, name, strlen(name), prefix, prefix ? strlen(prefix) : 0, module_name,
             strlen(module_name), value, strlen(value), NULL, LY_VALUE_JSON, NULL, 0, &ret));
     if (parent) {
-        lyd_insert_node(parent, NULL, ret);
+        lyd_insert_node(parent, NULL, ret, 1);
     }
 
     if (node) {
@@ -1388,7 +1388,7 @@
     LY_CHECK_RET(lyd_create_opaq(ctx, name, strlen(name), prefix, prefix ? strlen(prefix) : 0, module_ns,
             strlen(module_ns), value, strlen(value), NULL, LY_VALUE_XML, NULL, 0, &ret));
     if (parent) {
-        lyd_insert_node(parent, NULL, ret);
+        lyd_insert_node(parent, NULL, ret, 1);
     }
 
     if (node) {
@@ -1982,10 +1982,10 @@
 
         if (cur_parent) {
             /* connect to the parent */
-            lyd_insert_node(cur_parent, NULL, node);
+            lyd_insert_node(cur_parent, NULL, node, 0);
         } else if (parent) {
             /* connect to top-level siblings */
-            lyd_insert_node(NULL, &parent, node);
+            lyd_insert_node(NULL, &parent, node, 0);
         }
 
 next_iter:
@@ -2098,7 +2098,7 @@
                 /* create default NP container */
                 LY_CHECK_RET(lyd_create_inner(iter, &node));
                 node->flags = LYD_DEFAULT | (lysc_has_when(iter) ? LYD_WHEN_TRUE : 0);
-                lyd_insert_node(parent, first, node);
+                lyd_insert_node(parent, first, node, 0);
 
                 if (lysc_has_when(iter) && node_when) {
                     /* remember to resolve when */
@@ -2132,7 +2132,7 @@
                     return ret;
                 }
                 node->flags = LYD_DEFAULT | (lysc_has_when(iter) ? LYD_WHEN_TRUE : 0);
-                lyd_insert_node(parent, first, node);
+                lyd_insert_node(parent, first, node, 0);
 
                 if (lysc_has_when(iter) && node_when) {
                     /* remember to resolve when */
@@ -2164,7 +2164,7 @@
                         return ret;
                     }
                     node->flags = LYD_DEFAULT | (lysc_has_when(iter) ? LYD_WHEN_TRUE : 0);
-                    lyd_insert_node(parent, first, node);
+                    lyd_insert_node(parent, first, node, 0);
 
                     if (lysc_has_when(iter) && node_when) {
                         /* remember to resolve when */
@@ -2526,7 +2526,7 @@
 }
 
 void
-lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling_p, struct lyd_node *node)
+lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling_p, struct lyd_node *node, ly_bool last)
 {
     struct lyd_node *anchor, *first_sibling;
 
@@ -2542,19 +2542,29 @@
     /* get first sibling */
     first_sibling = parent ? lyd_child(parent) : *first_sibling_p;
 
-    /* find the anchor, our next node, so we can insert before it */
-    anchor = lyd_insert_get_next_anchor(first_sibling, node);
+    if (last) {
+        /* no next anchor */
+        anchor = NULL;
+    } else {
+        /* find the anchor, our next node, so we can insert before it */
+        anchor = lyd_insert_get_next_anchor(first_sibling, node);
+    }
+
     if (anchor) {
+        /* insert before the anchor */
         lyd_insert_before_node(anchor, node);
         if (!parent && (*first_sibling_p == anchor)) {
             /* move first sibling */
             *first_sibling_p = node;
         }
     } else if (first_sibling) {
+        /* insert as the last node */
         lyd_insert_after_node(first_sibling->prev, node);
     } else if (parent) {
+        /* insert as the only child */
         lyd_insert_only_child(parent, node);
     } else {
+        /* insert as the only sibling */
         *first_sibling_p = node;
     }
 
@@ -2639,7 +2649,7 @@
     while (node) {
         iter = node->next;
         lyd_unlink_tree(node);
-        lyd_insert_node(parent, NULL, node);
+        lyd_insert_node(parent, NULL, node, 0);
         node = iter;
     }
     return LY_SUCCESS;
@@ -2673,7 +2683,7 @@
 
         iter = node->next;
         lyd_unlink_tree(node);
-        lyd_insert_node(NULL, &sibling, node);
+        lyd_insert_node(NULL, &sibling, node, 0);
         node = iter;
     }
 
@@ -3464,7 +3474,7 @@
     }
 
     /* insert */
-    lyd_insert_node(parent, first, dup);
+    lyd_insert_node(parent, first, dup, 0);
 
     if (dup_p) {
         *dup_p = dup;
@@ -3728,7 +3738,7 @@
         }
 
         /* insert */
-        lyd_insert_node(parent_trg, first_trg, dup_src);
+        lyd_insert_node(parent_trg, first_trg, dup_src, 0);
 
         if (first_inst) {
             /* remember not to find this instance next time */
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index 7a63e5f..fb5e4af 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -234,8 +234,9 @@
  * @param[in] parent Parent to insert into, NULL for top-level sibling.
  * @param[in,out] first_sibling First sibling, NULL if no top-level sibling exist yet. Can be also NULL if @p parent is set.
  * @param[in] node Individual node (without siblings) to insert.
+ * @param[in] last If set, do not search for the correct anchor but always insert at the end.
  */
-void lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling, struct lyd_node *node);
+void lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling, struct lyd_node *node, ly_bool last);
 
 /**
  * @brief Insert a metadata (last) into a parent
diff --git a/src/validation.c b/src/validation.c
index e206225..6b2c841 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -1649,7 +1649,7 @@
     lyd_val_op_merge_find(op_tree, op_node, dep_tree, &op_subtree, &tree_sibling, &tree_parent);
     op_parent = lyd_parent(op_subtree);
     lyd_unlink_tree(op_subtree);
-    lyd_insert_node(tree_parent, &tree_sibling, op_subtree);
+    lyd_insert_node(tree_parent, &tree_sibling, op_subtree, 0);
     if (!dep_tree) {
         dep_tree = tree_sibling;
     }
@@ -1693,7 +1693,7 @@
     /* restore operation tree */
     lyd_unlink_tree(op_subtree);
     if (op_parent) {
-        lyd_insert_node(op_parent, NULL, op_subtree);
+        lyd_insert_node(op_parent, NULL, op_subtree, 0);
     }
 
     ly_set_erase(&node_when, NULL);
diff --git a/tests/perf/perf.c b/tests/perf/perf.c
index d5a95ca..893a220 100644
--- a/tests/perf/perf.c
+++ b/tests/perf/perf.c
@@ -436,13 +436,14 @@
 static LY_ERR
 test_parse_xml_mem_no_validate(struct test_state *state, struct timespec *ts_start, struct timespec *ts_end)
 {
-    return _test_parse(state, LYD_XML, 0, LYD_PRINT_SHRINK, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, ts_start, ts_end);
+    return _test_parse(state, LYD_XML, 0, LYD_PRINT_SHRINK, LYD_PARSE_STRICT | LYD_PARSE_ONLY | LYD_PARSE_ORDERED, 0,
+            ts_start, ts_end);
 }
 
 static LY_ERR
 test_parse_xml_file_no_validate_format(struct test_state *state, struct timespec *ts_start, struct timespec *ts_end)
 {
-    return _test_parse(state, LYD_XML, 1, 0, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, ts_start, ts_end);
+    return _test_parse(state, LYD_XML, 1, 0, LYD_PARSE_STRICT | LYD_PARSE_ONLY | LYD_PARSE_ORDERED, 0, ts_start, ts_end);
 }
 
 static LY_ERR
@@ -454,13 +455,14 @@
 static LY_ERR
 test_parse_json_mem_no_validate(struct test_state *state, struct timespec *ts_start, struct timespec *ts_end)
 {
-    return _test_parse(state, LYD_JSON, 0, LYD_PRINT_SHRINK, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, ts_start, ts_end);
+    return _test_parse(state, LYD_JSON, 0, LYD_PRINT_SHRINK, LYD_PARSE_STRICT | LYD_PARSE_ONLY | LYD_PARSE_ORDERED, 0,
+            ts_start, ts_end);
 }
 
 static LY_ERR
 test_parse_json_file_no_validate_format(struct test_state *state, struct timespec *ts_start, struct timespec *ts_end)
 {
-    return _test_parse(state, LYD_JSON, 1, 0, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, ts_start, ts_end);
+    return _test_parse(state, LYD_JSON, 1, 0, LYD_PARSE_STRICT | LYD_PARSE_ONLY | LYD_PARSE_ORDERED, 0, ts_start, ts_end);
 }
 
 static LY_ERR
@@ -472,13 +474,14 @@
 static LY_ERR
 test_parse_lyb_mem_no_validate(struct test_state *state, struct timespec *ts_start, struct timespec *ts_end)
 {
-    return _test_parse(state, LYD_LYB, 0, LYD_PRINT_SHRINK, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, ts_start, ts_end);
+    return _test_parse(state, LYD_LYB, 0, LYD_PRINT_SHRINK, LYD_PARSE_STRICT | LYD_PARSE_ONLY | LYD_PARSE_ORDERED, 0,
+            ts_start, ts_end);
 }
 
 static LY_ERR
 test_parse_lyb_file_no_validate(struct test_state *state, struct timespec *ts_start, struct timespec *ts_end)
 {
-    return _test_parse(state, LYD_LYB, 1, 0, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, ts_start, ts_end);
+    return _test_parse(state, LYD_LYB, 1, 0, LYD_PARSE_STRICT | LYD_PARSE_ONLY | LYD_PARSE_ORDERED, 0, ts_start, ts_end);
 }
 
 static LY_ERR