xmlSchemaCheckAGPropsCorrect(xmlSchemaParserCtxtPtr pctxt,
				  xmlSchemaAttributeGroupPtr attrGr)
{
    /*
    * SPEC ag-props-correct
    * (1) "The values of the properties of an attribute group definition
    * must be as described in the property tableau in The Attribute
    * Group Definition Schema Component ($3.6.1), modulo the impact of
    * Missing Sub-components ($5.3);"
    */

    if ((attrGr->attrUses != NULL) &&
	(WXS_LIST_CAST attrGr->attrUses)->nbItems > 1)
    {
	xmlSchemaItemListPtr uses = WXS_LIST_CAST attrGr->attrUses;
	xmlSchemaAttributeUsePtr use, tmp;
	int i, j, hasId = 0;

	for (i = uses->nbItems -1; i >= 0; i--) {
	    use = uses->items[i];
	    /*
	    * SPEC ag-props-correct
	    * (2) "Two distinct members of the {attribute uses} must not have
	    * {attribute declaration}s both of whose {name}s match and whose
	    * {target namespace}s are identical."
	    */
	    if (i > 0) {
		for (j = i -1; j >= 0; j--) {
		    tmp = uses->items[j];
		    if ((WXS_ATTRUSE_DECL_NAME(use) ==
			WXS_ATTRUSE_DECL_NAME(tmp)) &&
			(WXS_ATTRUSE_DECL_TNS(use) ==
			WXS_ATTRUSE_DECL_TNS(tmp)))
		    {
			xmlChar *str = NULL;

			xmlSchemaCustomErr(ACTXT_CAST pctxt,
			    XML_SCHEMAP_AG_PROPS_CORRECT,
			    attrGr->node, WXS_BASIC_CAST attrGr,
			    "Duplicate %s",
			    xmlSchemaGetComponentDesignation(&str, use),
			    NULL);
			FREE_AND_NULL(str);
			/*
			* Remove the duplicate.
			*/
			if (xmlSchemaItemListRemove(uses, i) == -1)
			    return(-1);
			goto next_use;
		    }
		}
	    }
	    /*
	    * SPEC ag-props-correct
	    * (3) "Two distinct members of the {attribute uses} must not have
	    * {attribute declaration}s both of whose {type definition}s are or
	    * are derived from ID."
	    * TODO: Does 'derived' include member-types of unions?
	    */
	    if (WXS_ATTRUSE_TYPEDEF(use) != NULL) {
		if (xmlSchemaIsDerivedFromBuiltInType(
		    WXS_ATTRUSE_TYPEDEF(use), XML_SCHEMAS_ID))
		{
		    if (hasId) {
			xmlChar *str = NULL;

			xmlSchemaCustomErr(ACTXT_CAST pctxt,
			    XML_SCHEMAP_AG_PROPS_CORRECT,
			    attrGr->node, WXS_BASIC_CAST attrGr,
			    "There must not exist more than one attribute "
			    "declaration of type 'xs:ID' "
			    "(or derived from 'xs:ID'). The %s violates this "
			    "constraint",
			    xmlSchemaGetComponentDesignation(&str, use),
			    NULL);
			FREE_AND_NULL(str);
			if (xmlSchemaItemListRemove(uses, i) == -1)
			    return(-1);
		    }
		    hasId = 1;
		}
	    }
next_use: {}
	}
    }
    return(0);
}
xmlSchemaCheckAGPropsCorrect(xmlSchemaParserCtxtPtr pctxt,
				  xmlSchemaAttributeGroupPtr attrGr)
{
     

    if ((attrGr->attrUses != NULL) &&
	(WXS_LIST_CAST attrGr->attrUses)->nbItems > 1)
    {
	xmlSchemaItemListPtr uses = WXS_LIST_CAST attrGr->attrUses;
	xmlSchemaAttributeUsePtr use, tmp;
	int i, j, hasId = 0;

	for (i = uses->nbItems -1; i >= 0; i--) {
	    use = uses->items[i];
	     
	    if (i > 0) {
		for (j = i -1; j >= 0; j--) {
		    tmp = uses->items[j];
		    if ((WXS_ATTRUSE_DECL_NAME(use) ==
			WXS_ATTRUSE_DECL_NAME(tmp)) &&
			(WXS_ATTRUSE_DECL_TNS(use) ==
			WXS_ATTRUSE_DECL_TNS(tmp)))
		    {
			xmlChar *str = NULL;

			xmlSchemaCustomErr(ACTXT_CAST pctxt,
			    XML_SCHEMAP_AG_PROPS_CORRECT,
			    attrGr->node, WXS_BASIC_CAST attrGr,
			    "Duplicate %s",
			    xmlSchemaGetComponentDesignation(&str, use),
			    NULL);
			FREE_AND_NULL(str);
			 
			if (xmlSchemaItemListRemove(uses, i) == -1)
			    return(-1);
			goto next_use;
		    }
		}
	    }
	     
	    if (WXS_ATTRUSE_TYPEDEF(use) != NULL) {
		if (xmlSchemaIsDerivedFromBuiltInType(
		    WXS_ATTRUSE_TYPEDEF(use), XML_SCHEMAS_ID))
		{
		    if (hasId) {
			xmlChar *str = NULL;

			xmlSchemaCustomErr(ACTXT_CAST pctxt,
			    XML_SCHEMAP_AG_PROPS_CORRECT,
			    attrGr->node, WXS_BASIC_CAST attrGr,
			    "There must not exist more than one attribute "
			    "declaration of type 'xs:ID' "
			    "(or derived from 'xs:ID'). The %s violates this "
			    "constraint",
			    xmlSchemaGetComponentDesignation(&str, use),
			    NULL);
			FREE_AND_NULL(str);
			if (xmlSchemaItemListRemove(uses, i) == -1)
			    return(-1);
		    }
		    hasId = 1;
		}
	    }
next_use: {}
	}
    }
    return(0);
}