lyd_merge_parent_children(struct lyd_node *target, struct lyd_node *source, int options)
{
    struct lyd_node *trg_parent, *src, *src_backup, *src_elem, *src_elem_backup, *src_next, *trg_child, *trg_parent_backup;
    int ret, clear_flag = 0;
    struct ly_ctx *ctx = target->schema->module->ctx; /* shortcut */

    LY_TREE_FOR_SAFE(source, src_backup, src) {
        for (src_elem = src_next = src, trg_parent = target;
            src_elem;
            src_elem = src_next) {

            /* it won't get inserted in this case */
            if (src_elem->dflt && (options & LYD_OPT_EXPLICIT)) {
                if (src_elem == src) {
                    /* we are done with this subtree in this case */
                    break;
                }
                trg_child = (struct lyd_node *)1;
                goto src_skip;
            }

            ret = 0;

#ifdef LY_ENABLED_CACHE
            struct lyd_node **trg_child_p;

            /* trees are supposed to be validated so all nodes must have their hash, but lets not be that strict */
            if (!src_elem->hash) {
                lyd_hash(src_elem);
            }

            if (trg_parent->ht) {
                trg_child = NULL;
                if (!lyht_find(trg_parent->ht, &src_elem, src_elem->hash, (void **)&trg_child_p)) {
                    trg_child = *trg_child_p;
                    ret = 1;

                    /* it is a bit more difficult with keyless state lists and leaf-lists */
                    if (((trg_child->schema->nodetype == LYS_LIST) && !((struct lys_node_list *)trg_child->schema)->keys_size)
                            || ((trg_child->schema->nodetype == LYS_LEAFLIST) && (trg_child->schema->flags & LYS_CONFIG_R))) {
                        assert(trg_child->schema->flags & LYS_CONFIG_R);

                        while (trg_child && (trg_child->validity & LYD_VAL_INUSE)) {
                            /* state lists, find one not-already-found */
                            if (lyht_find_next(trg_parent->ht, &trg_child, trg_child->hash, (void **)&trg_child_p)) {
                                trg_child = NULL;
                            } else {
                                trg_child = *trg_child_p;
                            }
                        }
                        if (trg_child) {
                            /* mark it as matched */
                            trg_child->validity |= LYD_VAL_INUSE;
                            ret = 2;
                        } else {
                            /* actually, it was matched already and no other instance found, so now not a match */
                            ret = 0;
                        }
                    }
                }
            } else
#endif
            {
                LY_TREE_FOR(trg_parent->child, trg_child) {
                    /* schema match, data match? */
                    ret = lyd_merge_node_schema_equal(trg_child, src_elem);
                    if (ret == 1) {
                        ret = lyd_merge_node_equal(trg_child, src_elem);
                    }
                    if (ret != 0) {
                        /* even data match */
                        break;
                    }
                }
            }

            if (ret > 0) {
                if (trg_child->schema->nodetype & (LYS_LEAF | LYS_ANYDATA)) {
                    lyd_merge_node_update(trg_child, src_elem);
                } else if (ret == 2) {
                    clear_flag = 1;
                }
            } else if (ret == -1) {
                /* error */
                lyd_free_withsiblings(source);
                return 1;
            }

            /* first prepare for the next iteration */
            src_elem_backup = src_elem;
            trg_parent_backup = trg_parent;
            if (((src_elem->schema->nodetype == LYS_CONTAINER) || ((src_elem->schema->nodetype == LYS_LIST)
                    && ((struct lys_node_list *)src_elem->schema)->keys_size)) && src_elem->child && trg_child) {
                /* go into children */
                src_next = src_elem->child;
                trg_parent = trg_child;
            } else {
src_skip:
                /* no children (or the whole subtree will be inserted), try siblings */
                if (src_elem == src) {
                    /* we are done with this subtree */
                    if (trg_child) {
                        /* it's an empty container, list without keys, or an already-updated leaf/anydata, nothing else to do */
                        break;
                    } else {
                        /* ... but we still need to insert it */
                        src_next = NULL;
                        goto src_insert;
                    }
                } else {
                    src_next = src_elem->next;
                    /* trg_parent does not change */
                }
            }
            while (!src_next) {
                src_elem = src_elem->parent;
                if (src_elem->parent == src->parent) {
                    /* we are done, no next element to process */
                    break;
                }

                /* parent is already processed, go to its sibling */
                src_next = src_elem->next;
                trg_parent = trg_parent->parent;
            }

            if (!trg_child) {
src_insert:
                /* we need to insert the whole subtree */
                if (ctx == src_elem_backup->schema->module->ctx) {
                    /* same context - unlink the subtree and insert it into the target */
                    lyd_unlink(src_elem_backup);
                } else {
                    /* different contexts - before inserting subtree, instead of unlinking, duplicate it into the
                     * target context */
                    src_elem_backup = lyd_dup_to_ctx(src_elem_backup, 1, ctx);
                }

                if (src_elem == source) {
                    /* it will be linked into another data tree and the pointers changed */
                    source = source->next;
                }

                /* insert subtree into the target */
                if (lyd_insert(trg_parent_backup, src_elem_backup)) {
                    LOGINT(ctx);
                    lyd_free_withsiblings(source);
                    return 1;
                }
                if (src_elem == src) {
                    /* we are finished for this src */
                    break;
                }
            }
        }
    }

    lyd_free_withsiblings(source);
    if (clear_flag) {
        return 2;
    }
    return 0;
}