xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                          xmlNodePtr node, xmlSchemaTypeType parentType)
{
    xmlSchemaTypePtr type;
    xmlNodePtr child = NULL;
    xmlAttrPtr attr;

    if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
        return (NULL);
    /* Not a component, don't create it. */
    type = ctxt->ctxtType;
    type->flags |= XML_SCHEMAS_TYPE_DERIVATION_METHOD_RESTRICTION;

    /*
    * 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 "base"))) {
		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;
    }
    /*
    * Extract and validate attributes.
    */
    xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
    /*
    * Attribute
    */
    /*
    * Extract the base type. The "base" attribute is mandatory if inside
    * a complex type or if redefining.
    *
    * SPEC (1.2) "...otherwise (<restriction> has no <simpleType> "
    * among its [children]), the simple type definition which is
    * the {content type} of the type definition `resolved` to by
    * the `actual value` of the base [attribute]"
    */
    if (xmlSchemaPValAttrQName(ctxt, schema, NULL, node, "base",
	&(type->baseNs), &(type->base)) == 0)
    {
	if ((type->base == NULL) && (type->type == XML_SCHEMA_TYPE_COMPLEX)) {
	    xmlSchemaPMissingAttrErr(ctxt,
		XML_SCHEMAP_S4S_ATTR_MISSING,
		NULL, node, "base", NULL);
	} else if ((ctxt->isRedefine) &&
	    (type->flags & XML_SCHEMAS_TYPE_GLOBAL))
	{
	    if (type->base == NULL) {
		xmlSchemaPMissingAttrErr(ctxt,
		    XML_SCHEMAP_S4S_ATTR_MISSING,
		    NULL, node, "base", NULL);
	    } else if ((! xmlStrEqual(type->base, type->name)) ||
		(! xmlStrEqual(type->baseNs, type->targetNamespace)))
	    {
		xmlChar *str1 = NULL, *str2 = NULL;
		/*
		* 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;"
		*/
		xmlSchemaPCustomErrExt(ctxt, XML_SCHEMAP_SRC_REDEFINE,
		    NULL, node, "This is a redefinition, but the QName "
		    "value '%s' of the 'base' attribute does not match the "
		    "type's designation '%s'",
		    xmlSchemaFormatQName(&str1, type->baseNs, type->base),
		    xmlSchemaFormatQName(&str2, type->targetNamespace,
			type->name), NULL);
		FREE_AND_NULL(str1);
		FREE_AND_NULL(str2);
		/* Avoid confusion and erase the values. */
		type->base = NULL;
		type->baseNs = NULL;
	    }
	}
    }
    /*
    * And now for the children...
    */
    child = node->children;
    if (IS_SCHEMA(child, "annotation")) {
	/*
	* Add the annotation to the simple type ancestor.
	*/
	xmlSchemaAddAnnotation((xmlSchemaAnnotItemPtr) type,
	    xmlSchemaParseAnnotation(ctxt, child, 1));
        child = child->next;
    }
    if (parentType == XML_SCHEMA_TYPE_SIMPLE) {
	/*
	* Corresponds to <simpleType><restriction><simpleType>.
	*/
	if (IS_SCHEMA(child, "simpleType")) {
	    if (type->base != NULL) {
		/*
		* src-restriction-base-or-simpleType
		* Either the base [attribute] or the simpleType [child] of the
		* <restriction> element must be present, but not both.
		*/
		xmlSchemaPContentErr(ctxt,
		    XML_SCHEMAP_SRC_RESTRICTION_BASE_OR_SIMPLETYPE,
		    NULL, node, child,
		    "The attribute 'base' and the <simpleType> child are "
		    "mutually exclusive", NULL);
	    } else {
		type->baseType = (xmlSchemaTypePtr)
		    xmlSchemaParseSimpleType(ctxt, schema, child, 0);
	    }
	    child = child->next;
	} else if (type->base == NULL) {
	    xmlSchemaPContentErr(ctxt,
		XML_SCHEMAP_SRC_RESTRICTION_BASE_OR_SIMPLETYPE,
		NULL, node, child,
		"Either the attribute 'base' or a <simpleType> child "
		"must be present", NULL);
	}
    } else if (parentType == XML_SCHEMA_TYPE_COMPLEX_CONTENT) {
	/*
	* Corresponds to <complexType><complexContent><restriction>...
	* followed by:
	*
	* Model groups <all>, <choice> and <sequence>.
	*/
	if (IS_SCHEMA(child, "all")) {
	    type->subtypes = (xmlSchemaTypePtr)
		xmlSchemaParseModelGroup(ctxt, schema, child,
		    XML_SCHEMA_TYPE_ALL, 1);
	    child = child->next;
	} else if (IS_SCHEMA(child, "choice")) {
	    type->subtypes = (xmlSchemaTypePtr)
		xmlSchemaParseModelGroup(ctxt,
		    schema, child, XML_SCHEMA_TYPE_CHOICE, 1);
	    child = child->next;
	} else if (IS_SCHEMA(child, "sequence")) {
	    type->subtypes = (xmlSchemaTypePtr)
		xmlSchemaParseModelGroup(ctxt, schema, child,
		    XML_SCHEMA_TYPE_SEQUENCE, 1);
	    child = child->next;
	/*
	* Model group reference <group>.
	*/
	} else if (IS_SCHEMA(child, "group")) {
	    type->subtypes = (xmlSchemaTypePtr)
		xmlSchemaParseModelGroupDefRef(ctxt, schema, child);
	    /*
	    * Note that the reference will be resolved in
	    * xmlSchemaResolveTypeReferences();
	    */
	    child = child->next;
	}
    } else if (parentType == XML_SCHEMA_TYPE_SIMPLE_CONTENT) {
	/*
	* Corresponds to <complexType><simpleContent><restriction>...
	*
	* "1.1 the simple type definition corresponding to the <simpleType>
	* among the [children] of <restriction> if there is one;"
	*/
	if (IS_SCHEMA(child, "simpleType")) {
	    /*
	    * We will store the to-be-restricted simple type in
	    * type->contentTypeDef *temporarily*.
	    */
	    type->contentTypeDef = (xmlSchemaTypePtr)
		xmlSchemaParseSimpleType(ctxt, schema, child, 0);
	    if ( type->contentTypeDef == NULL)
		return (NULL);
	    child = child->next;
	}
    }

    if ((parentType == XML_SCHEMA_TYPE_SIMPLE) ||
	(parentType == XML_SCHEMA_TYPE_SIMPLE_CONTENT)) {
	xmlSchemaFacetPtr facet, lastfacet = NULL;
	/*
	* Corresponds to <complexType><simpleContent><restriction>...
	* <simpleType><restriction>...
	*/

	/*
	* Add the facets to the simple type ancestor.
	*/
	/*
	* TODO: Datatypes: 4.1.3 Constraints on XML Representation of
	* Simple Type Definition Schema Representation Constraint:
	* *Single Facet Value*
	*/
	while ((IS_SCHEMA(child, "minInclusive")) ||
	    (IS_SCHEMA(child, "minExclusive")) ||
	    (IS_SCHEMA(child, "maxInclusive")) ||
	    (IS_SCHEMA(child, "maxExclusive")) ||
	    (IS_SCHEMA(child, "totalDigits")) ||
	    (IS_SCHEMA(child, "fractionDigits")) ||
	    (IS_SCHEMA(child, "pattern")) ||
	    (IS_SCHEMA(child, "enumeration")) ||
	    (IS_SCHEMA(child, "whiteSpace")) ||
	    (IS_SCHEMA(child, "length")) ||
	    (IS_SCHEMA(child, "maxLength")) ||
	    (IS_SCHEMA(child, "minLength"))) {
	    facet = xmlSchemaParseFacet(ctxt, schema, child);
	    if (facet != NULL) {
		if (lastfacet == NULL)
		    type->facets = facet;
		else
		    lastfacet->next = facet;
		lastfacet = facet;
		lastfacet->next = NULL;
	    }
	    child = child->next;
	}
	/*
	* Create links for derivation and validation.
	*/
	if (type->facets != NULL) {
	    xmlSchemaFacetLinkPtr facetLink, lastFacetLink = NULL;

	    facet = type->facets;
	    do {
		facetLink = (xmlSchemaFacetLinkPtr)
		    xmlMalloc(sizeof(xmlSchemaFacetLink));
		if (facetLink == NULL) {
		    xmlSchemaPErrMemory(ctxt, "allocating a facet link", NULL);
		    xmlFree(facetLink);
		    return (NULL);
		}
		facetLink->facet = facet;
		facetLink->next = NULL;
		if (lastFacetLink == NULL)
		    type->facetSet = facetLink;
		else
		    lastFacetLink->next = facetLink;
		lastFacetLink = facetLink;
		facet = facet->next;
	    } while (facet != NULL);
	}
    }
    if (type->type == XML_SCHEMA_TYPE_COMPLEX) {
	/*
	* Attribute uses/declarations.
	*/
	if (xmlSchemaParseLocalAttributes(ctxt, schema, &child,
	    (xmlSchemaItemListPtr *) &(type->attrUses),
	    XML_SCHEMA_TYPE_RESTRICTION, NULL) == -1)
	    return(NULL);
	/*
	* Attribute wildcard.
	*/
	if (IS_SCHEMA(child, "anyAttribute")) {
	    type->attributeWildcard =
		xmlSchemaParseAnyAttribute(ctxt, schema, child);
	    child = child->next;
	}
    }
    if (child != NULL) {
	if (parentType == XML_SCHEMA_TYPE_COMPLEX_CONTENT) {
	    xmlSchemaPContentErr(ctxt,
		XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
		NULL, node, child, NULL,
		"annotation?, (group | all | choice | sequence)?, "
		"((attribute | attributeGroup)*, anyAttribute?))");
	} else if (parentType == XML_SCHEMA_TYPE_SIMPLE_CONTENT) {
	     xmlSchemaPContentErr(ctxt,
		XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
		NULL, node, child, NULL,
		"(annotation?, (simpleType?, (minExclusive | minInclusive | "
		"maxExclusive | maxInclusive | totalDigits | fractionDigits | "
		"length | minLength | maxLength | enumeration | whiteSpace | "
		"pattern)*)?, ((attribute | attributeGroup)*, anyAttribute?))");
	} else {
	    /* Simple type */
	    xmlSchemaPContentErr(ctxt,
		XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
		NULL, node, child, NULL,
		"(annotation?, (simpleType?, (minExclusive | minInclusive | "
		"maxExclusive | maxInclusive | totalDigits | fractionDigits | "
		"length | minLength | maxLength | enumeration | whiteSpace | "
		"pattern)*))");
	}
    }
    return (NULL);
}