xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
{
    xmlRelaxNGDefinePtr def = NULL;

    if (node == NULL) {
        return (NULL);
    }
    if (IS_RELAXNG(node, "element")) {
        def = xmlRelaxNGParseElement(ctxt, node);
    } else if (IS_RELAXNG(node, "attribute")) {
        def = xmlRelaxNGParseAttribute(ctxt, node);
    } else if (IS_RELAXNG(node, "empty")) {
        def = xmlRelaxNGNewDefine(ctxt, node);
        if (def == NULL)
            return (NULL);
        def->type = XML_RELAXNG_EMPTY;
        if (node->children != NULL) {
            xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY,
                       "empty: had a child node\n", NULL, NULL);
        }
    } else if (IS_RELAXNG(node, "text")) {
        def = xmlRelaxNGNewDefine(ctxt, node);
        if (def == NULL)
            return (NULL);
        def->type = XML_RELAXNG_TEXT;
        if (node->children != NULL) {
            xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD,
                       "text: had a child node\n", NULL, NULL);
        }
    } else if (IS_RELAXNG(node, "zeroOrMore")) {
        def = xmlRelaxNGNewDefine(ctxt, node);
        if (def == NULL)
            return (NULL);
        def->type = XML_RELAXNG_ZEROORMORE;
        if (node->children == NULL) {
            xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
                       "Element %s is empty\n", node->name, NULL);
        } else {
            def->content =
                xmlRelaxNGParsePatterns(ctxt, node->children, 1);
        }
    } else if (IS_RELAXNG(node, "oneOrMore")) {
        def = xmlRelaxNGNewDefine(ctxt, node);
        if (def == NULL)
            return (NULL);
        def->type = XML_RELAXNG_ONEORMORE;
        if (node->children == NULL) {
            xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
                       "Element %s is empty\n", node->name, NULL);
        } else {
            def->content =
                xmlRelaxNGParsePatterns(ctxt, node->children, 1);
        }
    } else if (IS_RELAXNG(node, "optional")) {
        def = xmlRelaxNGNewDefine(ctxt, node);
        if (def == NULL)
            return (NULL);
        def->type = XML_RELAXNG_OPTIONAL;
        if (node->children == NULL) {
            xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
                       "Element %s is empty\n", node->name, NULL);
        } else {
            def->content =
                xmlRelaxNGParsePatterns(ctxt, node->children, 1);
        }
    } else if (IS_RELAXNG(node, "choice")) {
        def = xmlRelaxNGNewDefine(ctxt, node);
        if (def == NULL)
            return (NULL);
        def->type = XML_RELAXNG_CHOICE;
        if (node->children == NULL) {
            xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
                       "Element %s is empty\n", node->name, NULL);
        } else {
            def->content =
                xmlRelaxNGParsePatterns(ctxt, node->children, 0);
        }
    } else if (IS_RELAXNG(node, "group")) {
        def = xmlRelaxNGNewDefine(ctxt, node);
        if (def == NULL)
            return (NULL);
        def->type = XML_RELAXNG_GROUP;
        if (node->children == NULL) {
            xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
                       "Element %s is empty\n", node->name, NULL);
        } else {
            def->content =
                xmlRelaxNGParsePatterns(ctxt, node->children, 0);
        }
    } else if (IS_RELAXNG(node, "ref")) {
        def = xmlRelaxNGNewDefine(ctxt, node);
        if (def == NULL)
            return (NULL);
        def->type = XML_RELAXNG_REF;
        def->name = xmlGetProp(node, BAD_CAST "name");
        if (def->name == NULL) {
            xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n",
                       NULL, NULL);
        } else {
            xmlRelaxNGNormExtSpace(def->name);
            if (xmlValidateNCName(def->name, 0)) {
                xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID,
                           "ref name '%s' is not an NCName\n", def->name,
                           NULL);
            }
        }
        if (node->children != NULL) {
            xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n",
                       NULL, NULL);
        }
        if (ctxt->grammar->refs == NULL)
            ctxt->grammar->refs = xmlHashCreate(10);
        if (ctxt->grammar->refs == NULL) {
            xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
                       "Could not create references hash\n", NULL, NULL);
            def = NULL;
        } else {
            int tmp;

            tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
            if (tmp < 0) {
                xmlRelaxNGDefinePtr prev;

                prev = (xmlRelaxNGDefinePtr)
                    xmlHashLookup(ctxt->grammar->refs, def->name);
                if (prev == NULL) {
                    if (def->name != NULL) {
		        xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
				   "Error refs definitions '%s'\n",
				   def->name, NULL);
                    } else {
		        xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
				   "Error refs definitions\n",
				   NULL, NULL);
                    }
                    def = NULL;
                } else {
                    def->nextHash = prev->nextHash;
                    prev->nextHash = def;
                }
            }
        }
    } else if (IS_RELAXNG(node, "data")) {
        def = xmlRelaxNGParseData(ctxt, node);
    } else if (IS_RELAXNG(node, "value")) {
        def = xmlRelaxNGParseValue(ctxt, node);
    } else if (IS_RELAXNG(node, "list")) {
        def = xmlRelaxNGNewDefine(ctxt, node);
        if (def == NULL)
            return (NULL);
        def->type = XML_RELAXNG_LIST;
        if (node->children == NULL) {
            xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
                       "Element %s is empty\n", node->name, NULL);
        } else {
            def->content =
                xmlRelaxNGParsePatterns(ctxt, node->children, 0);
        }
    } else if (IS_RELAXNG(node, "interleave")) {
        def = xmlRelaxNGParseInterleave(ctxt, node);
    } else if (IS_RELAXNG(node, "externalRef")) {
        def = xmlRelaxNGProcessExternalRef(ctxt, node);
    } else if (IS_RELAXNG(node, "notAllowed")) {
        def = xmlRelaxNGNewDefine(ctxt, node);
        if (def == NULL)
            return (NULL);
        def->type = XML_RELAXNG_NOT_ALLOWED;
        if (node->children != NULL) {
            xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY,
                       "xmlRelaxNGParse: notAllowed element is not empty\n",
                       NULL, NULL);
        }
    } else if (IS_RELAXNG(node, "grammar")) {
        xmlRelaxNGGrammarPtr grammar, old;
        xmlRelaxNGGrammarPtr oldparent;

#ifdef DEBUG_GRAMMAR
        xmlGenericError(xmlGenericErrorContext,
                        "Found <grammar> pattern\n");
#endif

        oldparent = ctxt->parentgrammar;
        old = ctxt->grammar;
        ctxt->parentgrammar = old;
        grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
        if (old != NULL) {
            ctxt->grammar = old;
            ctxt->parentgrammar = oldparent;
#if 0
            if (grammar != NULL) {
                grammar->next = old->next;
                old->next = grammar;
            }
#endif
        }
        if (grammar != NULL)
            def = grammar->start;
        else
            def = NULL;
    } else if (IS_RELAXNG(node, "parentRef")) {
        if (ctxt->parentgrammar == NULL) {
            xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT,
                       "Use of parentRef without a parent grammar\n", NULL,
                       NULL);
            return (NULL);
        }
        def = xmlRelaxNGNewDefine(ctxt, node);
        if (def == NULL)
            return (NULL);
        def->type = XML_RELAXNG_PARENTREF;
        def->name = xmlGetProp(node, BAD_CAST "name");
        if (def->name == NULL) {
            xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME,
                       "parentRef has no name\n", NULL, NULL);
        } else {
            xmlRelaxNGNormExtSpace(def->name);
            if (xmlValidateNCName(def->name, 0)) {
                xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID,
                           "parentRef name '%s' is not an NCName\n",
                           def->name, NULL);
            }
        }
        if (node->children != NULL) {
            xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY,
                       "parentRef is not empty\n", NULL, NULL);
        }
        if (ctxt->parentgrammar->refs == NULL)
            ctxt->parentgrammar->refs = xmlHashCreate(10);
        if (ctxt->parentgrammar->refs == NULL) {
            xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
                       "Could not create references hash\n", NULL, NULL);
            def = NULL;
        } else if (def->name != NULL) {
            int tmp;

            tmp =
                xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
            if (tmp < 0) {
                xmlRelaxNGDefinePtr prev;

                prev = (xmlRelaxNGDefinePtr)
                    xmlHashLookup(ctxt->parentgrammar->refs, def->name);
                if (prev == NULL) {
                    xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
                               "Internal error parentRef definitions '%s'\n",
                               def->name, NULL);
                    def = NULL;
                } else {
                    def->nextHash = prev->nextHash;
                    prev->nextHash = def;
                }
            }
        }
    } else if (IS_RELAXNG(node, "mixed")) {
        if (node->children == NULL) {
            xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n",
                       NULL, NULL);
            def = NULL;
        } else {
            def = xmlRelaxNGParseInterleave(ctxt, node);
            if (def != NULL) {
                xmlRelaxNGDefinePtr tmp;

                if ((def->content != NULL) && (def->content->next != NULL)) {
                    tmp = xmlRelaxNGNewDefine(ctxt, node);
                    if (tmp != NULL) {
                        tmp->type = XML_RELAXNG_GROUP;
                        tmp->content = def->content;
                        def->content = tmp;
                    }
                }

                tmp = xmlRelaxNGNewDefine(ctxt, node);
                if (tmp == NULL)
                    return (def);
                tmp->type = XML_RELAXNG_TEXT;
                tmp->next = def->content;
                def->content = tmp;
            }
        }
    } else {
        xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT,
                   "Unexpected node %s is not a pattern\n", node->name,
                   NULL);
        def = NULL;
    }
    return (def);
}