_lyd_dup_node(const struct lyd_node *node, const struct lys_node *schema, struct ly_ctx *ctx, int options)
{
    struct lyd_node *new_node = NULL;
    struct lys_node_leaf *sleaf;
    struct lyd_node_leaf_list *new_leaf;
    struct lyd_node_anydata *new_any, *old_any;
    int r;

    /* fill specific part */
    switch (node->schema->nodetype) {
    case LYS_LEAF:
    case LYS_LEAFLIST:
        new_leaf = calloc(1, sizeof *new_leaf);
        new_node = (struct lyd_node *)new_leaf;
        LY_CHECK_ERR_GOTO(!new_node, LOGMEM(ctx), error);
        new_node->schema = (struct lys_node *)schema;

        new_leaf->value_str = lydict_insert(ctx, ((struct lyd_node_leaf_list *)node)->value_str, 0);
        new_leaf->value_type = ((struct lyd_node_leaf_list *)node)->value_type;
        new_leaf->value_flags = ((struct lyd_node_leaf_list *)node)->value_flags;
        if (_lyd_dup_node_common(new_node, node, ctx, options)) {
            goto error;
        }

        /* get schema from the correct context */
        sleaf = (struct lys_node_leaf *)new_leaf->schema;

        switch (new_leaf->value_type) {
        case LY_TYPE_BINARY:
        case LY_TYPE_STRING:
            /* value_str pointer is shared in these cases */
            new_leaf->value.string = new_leaf->value_str;
            break;
        case LY_TYPE_LEAFREF:
            new_leaf->validity |= LYD_VAL_LEAFREF;
            lyp_parse_value(&sleaf->type, &new_leaf->value_str, NULL, new_leaf, NULL, NULL, 1, node->dflt, 0);
            break;
        case LY_TYPE_INST:
            new_leaf->value.instance = NULL;
            break;
        case LY_TYPE_UNION:
            /* unresolved union (this must be non-validated tree), duplicate the stored string (duplicated
             * because of possible change of the value in case of instance-identifier) */
            new_leaf->value.string = lydict_insert(ctx, ((struct lyd_node_leaf_list *)node)->value.string, 0);
            break;
        case LY_TYPE_ENUM:
        case LY_TYPE_IDENT:
        case LY_TYPE_BITS:
            /* in case of duplicating bits (no matter if in the same context or not) or enum and identityref into
             * a different context, searching for the type and duplicating the data is almost as same as resolving
             * the string value, so due to a simplicity, parse the value for the duplicated leaf */
            if (!lyp_parse_value(&sleaf->type, &new_leaf->value_str, NULL, new_leaf, NULL, NULL, 1, node->dflt, 0)) {
                goto error;
            }
            break;
        default:
            new_leaf->value = ((struct lyd_node_leaf_list *)node)->value;
            break;
        }

        if (sleaf->type.der && sleaf->type.der->module) {
            r = lytype_store(sleaf->type.der->module, sleaf->type.der->name, new_leaf->value_str, &new_leaf->value);
            if (r == -1) {
                goto error;
            } else if (!r) {
                new_leaf->value_flags |= LY_VALUE_USER;
            }
        }
        break;
    case LYS_ANYXML:
    case LYS_ANYDATA:
        old_any = (struct lyd_node_anydata *)node;
        new_any = calloc(1, sizeof *new_any);
        new_node = (struct lyd_node *)new_any;
        LY_CHECK_ERR_GOTO(!new_node, LOGMEM(ctx), error);
        new_node->schema = (struct lys_node *)schema;

        if (_lyd_dup_node_common(new_node, node, ctx, options)) {
            goto error;
        }

        new_any->value_type = old_any->value_type;
        if (!(void*)old_any->value.tree) {
            /* no value to duplicate */
            break;
        }
        /* duplicate the value */
        switch (old_any->value_type) {
        case LYD_ANYDATA_CONSTSTRING:
        case LYD_ANYDATA_SXML:
        case LYD_ANYDATA_JSON:
            new_any->value.str = lydict_insert(ctx, old_any->value.str, 0);
            break;
        case LYD_ANYDATA_DATATREE:
            new_any->value.tree = lyd_dup_to_ctx(old_any->value.tree, 1, ctx);
            break;
        case LYD_ANYDATA_XML:
            new_any->value.xml = lyxml_dup_elem(ctx, old_any->value.xml, NULL, 1);
            break;
        case LYD_ANYDATA_LYB:
            r = lyd_lyb_data_length(old_any->value.mem);
            if (r == -1) {
                LOGERR(ctx, LY_EINVAL, "Invalid LYB data.");
                goto error;
            }
            new_any->value.mem = malloc(r);
            LY_CHECK_ERR_GOTO(!new_any->value.mem, LOGMEM(ctx), error);
            memcpy(new_any->value.mem, old_any->value.mem, r);
            break;
        case LYD_ANYDATA_STRING:
        case LYD_ANYDATA_SXMLD:
        case LYD_ANYDATA_JSOND:
        case LYD_ANYDATA_LYBD:
            /* dynamic strings are used only as input parameters */
            assert(0);
            break;
        }
        break;
    case LYS_CONTAINER:
    case LYS_LIST:
    case LYS_NOTIF:
    case LYS_RPC:
    case LYS_ACTION:
        new_node = calloc(1, sizeof *new_node);
        LY_CHECK_ERR_GOTO(!new_node, LOGMEM(ctx), error);
        new_node->schema = (struct lys_node *)schema;

        if (_lyd_dup_node_common(new_node, node, ctx, options)) {
            goto error;
        }
        break;
    default:
        LOGINT(ctx);
        goto error;
    }

    return new_node;

error:
    lyd_free(new_node);
    return NULL;
}