xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                         xmlNodePtr node, int topLevel)
{
    xmlSchemaTypePtr type, oldCtxtType;
    xmlNodePtr child = NULL;
    const xmlChar *attrValue = NULL;
    xmlAttrPtr attr;
    int hasRestriction = 0;

    if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
        return (NULL);

    if (topLevel) {
	attr = xmlSchemaGetPropNode(node, "name");
	if (attr == NULL) {
	    xmlSchemaPMissingAttrErr(ctxt,
		XML_SCHEMAP_S4S_ATTR_MISSING,
		NULL, node,
		"name", NULL);
	    return (NULL);
	} else {
	    if (xmlSchemaPValAttrNode(ctxt,
		NULL, attr,
		xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &attrValue) != 0)
		return (NULL);
	    /*
	    * Skip built-in types.
	    */
	    if (ctxt->isS4S) {
		xmlSchemaTypePtr biType;

		if (ctxt->isRedefine) {
		    /*
		    * REDEFINE: Disallow redefinition of built-in-types.
		    * TODO: It seems that the spec does not say anything
		    * about this case.
		    */
		    xmlSchemaPCustomErr(ctxt, XML_SCHEMAP_SRC_REDEFINE,
			NULL, node,
			"Redefinition of built-in simple types is not "
			"supported", NULL);
		    return(NULL);
		}
		biType = xmlSchemaGetPredefinedType(attrValue, xmlSchemaNs);
		if (biType != NULL)
		    return (biType);
	    }
	}
    }
    /*
    * TargetNamespace:
    * SPEC "The `actual value` of the targetNamespace [attribute]
    * of the <schema> ancestor element information item if present,
    * otherwise `absent`.
    */
    if (topLevel == 0) {
#ifdef ENABLE_NAMED_LOCALS
        char buf[40];
#endif
	/*
	* Parse as local simple type definition.
	*/
#ifdef ENABLE_NAMED_LOCALS
        snprintf(buf, 39, "#ST%d", ctxt->counter++ + 1);
	type = xmlSchemaAddType(ctxt, schema,
	    XML_SCHEMA_TYPE_SIMPLE,
	    xmlDictLookup(ctxt->dict, (const xmlChar *)buf, -1),
	    ctxt->targetNamespace, node, 0);
#else
	type = xmlSchemaAddType(ctxt, schema,
	    XML_SCHEMA_TYPE_SIMPLE,
	    NULL, ctxt->targetNamespace, node, 0);
#endif
	if (type == NULL)
	    return (NULL);
	type->type = XML_SCHEMA_TYPE_SIMPLE;
	type->contentType = XML_SCHEMA_CONTENT_SIMPLE;
	/*
	* Check for illegal attributes.
	*/
	attr = node->properties;
	while (attr != NULL) {
	    if (attr->ns == NULL) {
		if (!xmlStrEqual(attr->name, BAD_CAST "id")) {
		    xmlSchemaPIllegalAttrErr(ctxt,
			XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
		}
	    } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
		    xmlSchemaPIllegalAttrErr(ctxt,
			XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
	    }
	    attr = attr->next;
	}
    } else {
	/*
	* Parse as global simple type definition.
	*
	* Note that attrValue is the value of the attribute "name" here.
	*/
	type = xmlSchemaAddType(ctxt, schema, XML_SCHEMA_TYPE_SIMPLE,
	    attrValue, ctxt->targetNamespace, node, 1);
	if (type == NULL)
	    return (NULL);
	type->type = XML_SCHEMA_TYPE_SIMPLE;
	type->contentType = XML_SCHEMA_CONTENT_SIMPLE;
	type->flags |= XML_SCHEMAS_TYPE_GLOBAL;
	/*
	* Check for illegal attributes.
	*/
	attr = node->properties;
	while (attr != NULL) {
	    if (attr->ns == NULL) {
		if ((!xmlStrEqual(attr->name, BAD_CAST "id")) &&
		    (!xmlStrEqual(attr->name, BAD_CAST "name")) &&
		    (!xmlStrEqual(attr->name, BAD_CAST "final"))) {
		    xmlSchemaPIllegalAttrErr(ctxt,
			XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
		}
	    } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
		xmlSchemaPIllegalAttrErr(ctxt,
		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
	    }
	    attr = attr->next;
	}
	/*
	* Attribute "final".
	*/
	attr = xmlSchemaGetPropNode(node, "final");
	if (attr == NULL) {
	    if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION)
		type->flags |= XML_SCHEMAS_TYPE_FINAL_RESTRICTION;
	    if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_LIST)
		type->flags |= XML_SCHEMAS_TYPE_FINAL_LIST;
	    if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_UNION)
		type->flags |= XML_SCHEMAS_TYPE_FINAL_UNION;
	} else {
	    attrValue = xmlSchemaGetProp(ctxt, node, "final");
	    if (xmlSchemaPValAttrBlockFinal(attrValue, &(type->flags),
		-1, -1, XML_SCHEMAS_TYPE_FINAL_RESTRICTION, -1,
		XML_SCHEMAS_TYPE_FINAL_LIST,
		XML_SCHEMAS_TYPE_FINAL_UNION) != 0) {

		xmlSchemaPSimpleTypeErr(ctxt,
		    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
		    WXS_BASIC_CAST type, (xmlNodePtr) attr,
		    NULL, "(#all | List of (list | union | restriction)",
		    attrValue, NULL, NULL, NULL);
	    }
	}
    }
    type->targetNamespace = ctxt->targetNamespace;
    xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
    /*
    * And now for the children...
    */
    oldCtxtType = ctxt->ctxtType;

    ctxt->ctxtType = type;

    child = node->children;
    if (IS_SCHEMA(child, "annotation")) {
        type->annot = xmlSchemaParseAnnotation(ctxt, child, 1);
        child = child->next;
    }
    if (child == NULL) {
	xmlSchemaPContentErr(ctxt, XML_SCHEMAP_S4S_ELEM_MISSING,
	    NULL, node, child, NULL,
	    "(annotation?, (restriction | list | union))");
    } else if (IS_SCHEMA(child, "restriction")) {
        xmlSchemaParseRestriction(ctxt, schema, child,
	    XML_SCHEMA_TYPE_SIMPLE);
	hasRestriction = 1;
        child = child->next;
    } else if (IS_SCHEMA(child, "list")) {
        xmlSchemaParseList(ctxt, schema, child);
        child = child->next;
    } else if (IS_SCHEMA(child, "union")) {
        xmlSchemaParseUnion(ctxt, schema, child);
        child = child->next;
    }
    if (child != NULL) {
	xmlSchemaPContentErr(ctxt, XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
	    NULL, node, child, NULL,
	    "(annotation?, (restriction | list | union))");
    }
    /*
    * REDEFINE: SPEC src-redefine (5)
    * "Within the [children], each <simpleType> must have a
    * <restriction> among its [children] ... the `actual value` of whose
    * base [attribute] must be the same as the `actual value` of its own
    * name attribute plus target namespace;"
    */
    if (topLevel && ctxt->isRedefine && (! hasRestriction)) {
	xmlSchemaPCustomErr(ctxt, XML_SCHEMAP_SRC_REDEFINE,
	    NULL, node, "This is a redefinition, thus the "
	    "<simpleType> must have a <restriction> child", NULL);
    }

    ctxt->ctxtType = oldCtxtType;
    return (type);
}