xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
                       xmlRelaxNGGrammarPtr grammar)
{
    xmlRelaxNGDefinePtr starts;
    xmlChar *combine;
    int choiceOrInterleave = -1;
    int missing = 0;
    xmlRelaxNGDefinePtr cur;

    starts = grammar->start;
    if ((starts == NULL) || (starts->next == NULL))
        return;
    cur = starts;
    while (cur != NULL) {
        if ((cur->node == NULL) || (cur->node->parent == NULL) ||
            (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
            combine = NULL;
            xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING,
                       "Internal error: start element not found\n", NULL,
                       NULL);
        } else {
            combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
        }

        if (combine != NULL) {
            if (xmlStrEqual(combine, BAD_CAST "choice")) {
                if (choiceOrInterleave == -1)
                    choiceOrInterleave = 1;
                else if (choiceOrInterleave == 0) {
                    xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
                               "<start> use both 'choice' and 'interleave'\n",
                               NULL, NULL);
                }
            } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
                if (choiceOrInterleave == -1)
                    choiceOrInterleave = 0;
                else if (choiceOrInterleave == 1) {
                    xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
                               "<start> use both 'choice' and 'interleave'\n",
                               NULL, NULL);
                }
            } else {
                xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE,
                           "<start> uses unknown combine value '%s''\n",
                           combine, NULL);
            }
            xmlFree(combine);
        } else {
            if (missing == 0)
                missing = 1;
            else {
                xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE,
                           "Some <start> element miss the combine attribute\n",
                           NULL, NULL);
            }
        }

        cur = cur->next;
    }
#ifdef DEBUG
    xmlGenericError(xmlGenericErrorContext,
                    "xmlRelaxNGCombineStart(): merging <start>: %d\n",
                    choiceOrInterleave);
#endif
    if (choiceOrInterleave == -1)
        choiceOrInterleave = 0;
    cur = xmlRelaxNGNewDefine(ctxt, starts->node);
    if (cur == NULL)
        return;
    if (choiceOrInterleave == 0)
        cur->type = XML_RELAXNG_INTERLEAVE;
    else
        cur->type = XML_RELAXNG_CHOICE;
    cur->content = grammar->start;
    grammar->start = cur;
    if (choiceOrInterleave == 0) {
        if (ctxt->interleaves == NULL)
            ctxt->interleaves = xmlHashCreate(10);
        if (ctxt->interleaves == NULL) {
            xmlRngPErr(ctxt, cur->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, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
                           "Failed to add %s to hash table\n",
			   (const xmlChar *) tmpname, NULL);
            }
        }
    }
}