xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
                       xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * name)
{
    xmlChar *combine;
    int choiceOrInterleave = -1;
    int missing = 0;
    xmlRelaxNGDefinePtr cur, last, tmp, tmp2;

    if (define->nextHash == NULL)
        return;
    cur = define;
    while (cur != NULL) {
        combine = xmlGetProp(cur->node, BAD_CAST "combine");
        if (combine != NULL) {
            if (xmlStrEqual(combine, BAD_CAST "choice")) {
                if (choiceOrInterleave == -1)
                    choiceOrInterleave = 1;
                else if (choiceOrInterleave == 0) {
                    xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
                               "Defines for %s use both 'choice' and 'interleave'\n",
                               name, NULL);
                }
            } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
                if (choiceOrInterleave == -1)
                    choiceOrInterleave = 0;
                else if (choiceOrInterleave == 1) {
                    xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
                               "Defines for %s use both 'choice' and 'interleave'\n",
                               name, NULL);
                }
            } else {
                xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE,
                           "Defines for %s use unknown combine value '%s''\n",
                           name, combine);
            }
            xmlFree(combine);
        } else {
            if (missing == 0)
                missing = 1;
            else {
                xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE,
                           "Some defines for %s needs the combine attribute\n",
                           name, NULL);
            }
        }

        cur = cur->nextHash;
    }
#ifdef DEBUG
    xmlGenericError(xmlGenericErrorContext,
                    "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
                    name, choiceOrInterleave);
#endif
    if (choiceOrInterleave == -1)
        choiceOrInterleave = 0;
    cur = xmlRelaxNGNewDefine(ctxt, define->node);
    if (cur == NULL)
        return;
    if (choiceOrInterleave == 0)
        cur->type = XML_RELAXNG_INTERLEAVE;
    else
        cur->type = XML_RELAXNG_CHOICE;
    tmp = define;
    last = NULL;
    while (tmp != NULL) {
        if (tmp->content != NULL) {
            if (tmp->content->next != NULL) {
                /*
                 * we need first to create a wrapper.
                 */
                tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
                if (tmp2 == NULL)
                    break;
                tmp2->type = XML_RELAXNG_GROUP;
                tmp2->content = tmp->content;
            } else {
                tmp2 = tmp->content;
            }
            if (last == NULL) {
                cur->content = tmp2;
            } else {
                last->next = tmp2;
            }
            last = tmp2;
        }
        tmp->content = cur;
        tmp = tmp->nextHash;
    }
    define->content = cur;
    if (choiceOrInterleave == 0) {
        if (ctxt->interleaves == NULL)
            ctxt->interleaves = xmlHashCreate(10);
        if (ctxt->interleaves == NULL) {
            xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
                       "Failed to create interleaves hash table\n", NULL,
                       NULL);
        } else {
            char tmpname[32];

            snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
            if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
                0) {
                xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
                           "Failed to add %s to hash table\n",
			   (const xmlChar *) tmpname, NULL);
            }
        }
    }
}