xmlSchemaAddComponents(xmlSchemaParserCtxtPtr pctxt,
		       xmlSchemaBucketPtr bucket)
{
    xmlSchemaBasicItemPtr item;
    int err;
    xmlHashTablePtr *table;
    const xmlChar *name;
    int i;

#define WXS_GET_GLOBAL_HASH(c, slot) { \
    if (WXS_IS_BUCKET_IMPMAIN((c)->type)) \
	table = &(WXS_IMPBUCKET((c))->schema->slot); \
    else \
	table = &(WXS_INCBUCKET((c))->ownerImport->schema->slot); }

    /*
    * Add global components to the schema's hash tables.
    * This is the place where duplicate components will be
    * detected.
    * TODO: I think normally we should support imports of the
    *   same namespace from multiple locations. We don't do currently,
    *   but if we do then according to:
    *   http://www.w3.org/Bugs/Public/show_bug.cgi?id=2224
    *   we would need, if imported directly, to import redefined
    *   components as well to be able to catch clashing components.
    *   (I hope I'll still know what this means after some months :-()
    */
    if (bucket == NULL)
	return(-1);
    if (bucket->flags & XML_SCHEMA_BUCKET_COMPS_ADDED)
	return(0);
    bucket->flags |= XML_SCHEMA_BUCKET_COMPS_ADDED;

    for (i = 0; i < bucket->globals->nbItems; i++) {
	item = bucket->globals->items[i];
	table = NULL;
	switch (item->type) {
	    case XML_SCHEMA_TYPE_COMPLEX:
	    case XML_SCHEMA_TYPE_SIMPLE:
		if (WXS_REDEFINED_TYPE(item))
		    continue;
		name = (WXS_TYPE_CAST item)->name;
		WXS_GET_GLOBAL_HASH(bucket, typeDecl)
		break;
	    case XML_SCHEMA_TYPE_ELEMENT:
		name = (WXS_ELEM_CAST item)->name;
		WXS_GET_GLOBAL_HASH(bucket, elemDecl)
		break;
	    case XML_SCHEMA_TYPE_ATTRIBUTE:
		name = (WXS_ATTR_CAST item)->name;
		WXS_GET_GLOBAL_HASH(bucket, attrDecl)
		break;
	    case XML_SCHEMA_TYPE_GROUP:
		if (WXS_REDEFINED_MODEL_GROUP_DEF(item))
		    continue;
		name = (WXS_MODEL_GROUPDEF_CAST item)->name;
		WXS_GET_GLOBAL_HASH(bucket, groupDecl)
		break;
	    case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
		if (WXS_REDEFINED_ATTR_GROUP(item))
		    continue;
		name = (WXS_ATTR_GROUP_CAST item)->name;
		WXS_GET_GLOBAL_HASH(bucket, attrgrpDecl)
		break;
	    case XML_SCHEMA_TYPE_IDC_KEY:
	    case XML_SCHEMA_TYPE_IDC_UNIQUE:
	    case XML_SCHEMA_TYPE_IDC_KEYREF:
		name = (WXS_IDC_CAST item)->name;
		WXS_GET_GLOBAL_HASH(bucket, idcDef)
		break;
	    case XML_SCHEMA_TYPE_NOTATION:
		name = ((xmlSchemaNotationPtr) item)->name;
		WXS_GET_GLOBAL_HASH(bucket, notaDecl)
		break;
	    default:
		PERROR_INT("xmlSchemaAddComponents",
		    "Unexpected global component type");
		continue;
	}
	if (*table == NULL) {
	    *table = xmlHashCreateDict(10, pctxt->dict);
	    if (*table == NULL) {
		PERROR_INT("xmlSchemaAddComponents",
		    "failed to create a component hash table");
		return(-1);
	    }
	}
	err = xmlHashAddEntry(*table, name, item);
	if (err != 0) {
	    xmlChar *str = NULL;

	    xmlSchemaCustomErr(ACTXT_CAST pctxt,
		XML_SCHEMAP_REDEFINED_TYPE,
		WXS_ITEM_NODE(item),
		WXS_BASIC_CAST item,
		"A global %s '%s' does already exist",
		WXS_ITEM_TYPE_NAME(item),
		xmlSchemaGetComponentQName(&str, item));
	    FREE_AND_NULL(str);
	}
    }
    /*
    * Process imported/included schemas.
    */
    if (bucket->relations != NULL) {
	xmlSchemaSchemaRelationPtr rel = bucket->relations;
	do {
	    if ((rel->bucket != NULL) &&
		((rel->bucket->flags & XML_SCHEMA_BUCKET_COMPS_ADDED) == 0)) {
		if (xmlSchemaAddComponents(pctxt, rel->bucket) == -1)
		    return(-1);
	    }
	    rel = rel->next;
	} while (rel != NULL);
    }
    return(0);
}