xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                      xmlNodePtr node, int *isElemRef, int topLevel)
{
    xmlSchemaElementPtr decl = NULL;
    xmlSchemaParticlePtr particle = NULL;
    xmlSchemaAnnotPtr annot = NULL;
    xmlNodePtr child = NULL;
    xmlAttrPtr attr, nameAttr;
    int min, max, isRef = 0;
    xmlChar *des = NULL;

    /* 3.3.3 Constraints on XML Representations of Element Declarations */
    /* TODO: Complete implementation of 3.3.6 */

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

    if (isElemRef != NULL)
	*isElemRef = 0;
    /*
    * If we get a "ref" attribute on a local <element> we will assume it's
    * a reference - even if there's a "name" attribute; this seems to be more
    * robust.
    */
    nameAttr = xmlSchemaGetPropNode(node, "name");
    attr = xmlSchemaGetPropNode(node, "ref");
    if ((topLevel) || (attr == NULL)) {
	if (nameAttr == NULL) {
	    xmlSchemaPMissingAttrErr(ctxt,
		XML_SCHEMAP_S4S_ATTR_MISSING,
		NULL, node, "name", NULL);
	    return (NULL);
	}
    } else
	isRef = 1;

    xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
    child = node->children;
    if (IS_SCHEMA(child, "annotation")) {
	annot = xmlSchemaParseAnnotation(ctxt, child, 1);
	child = child->next;
    }
    /*
    * Skip particle part if a global declaration.
    */
    if (topLevel)
	goto declaration_part;
    /*
    * The particle part ==================================================
    */
    min = xmlGetMinOccurs(ctxt, node, 0, -1, 1, "xs:nonNegativeInteger");
    max = xmlGetMaxOccurs(ctxt, node, 0, UNBOUNDED, 1, "(xs:nonNegativeInteger | unbounded)");
    xmlSchemaPCheckParticleCorrect_2(ctxt, NULL, node, min, max);
    particle = xmlSchemaAddParticle(ctxt, node, min, max);
    if (particle == NULL)
	goto return_null;

    /* ret->flags |= XML_SCHEMAS_ELEM_REF; */

    if (isRef) {
	const xmlChar *refNs = NULL, *ref = NULL;
	xmlSchemaQNameRefPtr refer = NULL;
	/*
	* The reference part =============================================
	*/
	if (isElemRef != NULL)
	    *isElemRef = 1;

	xmlSchemaPValAttrNodeQName(ctxt, schema,
	    NULL, attr, &refNs, &ref);
	xmlSchemaCheckReference(ctxt, schema, node, attr, refNs);
	/*
	* SPEC (3.3.3 : 2.1) "One of ref or name must be present, but not both"
	*/
	if (nameAttr != NULL) {
	    xmlSchemaPMutualExclAttrErr(ctxt,
		XML_SCHEMAP_SRC_ELEMENT_2_1, NULL, nameAttr, "ref", "name");
	}
	/*
	* Check for illegal attributes.
	*/
	attr = node->properties;
	while (attr != NULL) {
	    if (attr->ns == NULL) {
		if (xmlStrEqual(attr->name, BAD_CAST "ref") ||
		    xmlStrEqual(attr->name, BAD_CAST "name") ||
		    xmlStrEqual(attr->name, BAD_CAST "id") ||
		    xmlStrEqual(attr->name, BAD_CAST "maxOccurs") ||
		    xmlStrEqual(attr->name, BAD_CAST "minOccurs"))
		{
		    attr = attr->next;
		    continue;
		} else {
		    /* SPEC (3.3.3 : 2.2) */
		    xmlSchemaPCustomAttrErr(ctxt,
			XML_SCHEMAP_SRC_ELEMENT_2_2,
			NULL, NULL, attr,
			"Only the attributes 'minOccurs', 'maxOccurs' and "
			"'id' are allowed in addition to 'ref'");
		    break;
		}
	    } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
		xmlSchemaPIllegalAttrErr(ctxt,
		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
	    }
	    attr = attr->next;
	}
	/*
	* No children except <annotation> expected.
	*/
	if (child != NULL) {
	    xmlSchemaPContentErr(ctxt, XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
		NULL, node, child, NULL, "(annotation?)");
	}
	if ((min == 0) && (max == 0))
	    goto return_null;
	/*
	* Create the reference item and attach it to the particle.
	*/
	refer = xmlSchemaNewQNameRef(ctxt, XML_SCHEMA_TYPE_ELEMENT,
	    ref, refNs);
	if (refer == NULL)
	    goto return_null;
	particle->children = (xmlSchemaTreeItemPtr) refer;
	particle->annot = annot;
	/*
	* Add the particle to pending components, since the reference
	* need to be resolved.
	*/
	WXS_ADD_PENDING(ctxt, particle);
	return ((xmlSchemaBasicItemPtr) particle);
    }
    /*
    * The declaration part ===============================================
    */
declaration_part:
    {
	const xmlChar *ns = NULL, *fixed, *name, *attrValue;
	xmlSchemaIDCPtr curIDC = NULL, lastIDC = NULL;

	if (xmlSchemaPValAttrNode(ctxt, NULL, nameAttr,
	    xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &name) != 0)
	    goto return_null;
	/*
	* Evaluate the target namespace.
	*/
	if (topLevel) {
	    ns = ctxt->targetNamespace;
	} else {
	    attr = xmlSchemaGetPropNode(node, "form");
	    if (attr != NULL) {
		attrValue = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
		if (xmlStrEqual(attrValue, BAD_CAST "qualified")) {
		    ns = ctxt->targetNamespace;
		} else if (!xmlStrEqual(attrValue, BAD_CAST "unqualified")) {
		    xmlSchemaPSimpleTypeErr(ctxt,
			XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
			NULL, (xmlNodePtr) attr,
			NULL, "(qualified | unqualified)",
			attrValue, NULL, NULL, NULL);
		}
	    } else if (schema->flags & XML_SCHEMAS_QUALIF_ELEM)
		ns = ctxt->targetNamespace;
	}
	decl = xmlSchemaAddElement(ctxt, name, ns, node, topLevel);
	if (decl == NULL) {
	    goto return_null;
	}
	/*
	* Check for illegal attributes.
	*/
	attr = node->properties;
	while (attr != NULL) {
	    if (attr->ns == NULL) {
		if ((!xmlStrEqual(attr->name, BAD_CAST "name")) &&
		    (!xmlStrEqual(attr->name, BAD_CAST "type")) &&
		    (!xmlStrEqual(attr->name, BAD_CAST "id")) &&
		    (!xmlStrEqual(attr->name, BAD_CAST "default")) &&
		    (!xmlStrEqual(attr->name, BAD_CAST "fixed")) &&
		    (!xmlStrEqual(attr->name, BAD_CAST "block")) &&
		    (!xmlStrEqual(attr->name, BAD_CAST "nillable")))
		{
		    if (topLevel == 0) {
			if ((!xmlStrEqual(attr->name, BAD_CAST "maxOccurs")) &&
			    (!xmlStrEqual(attr->name, BAD_CAST "minOccurs")) &&
			    (!xmlStrEqual(attr->name, BAD_CAST "form")))
			{
			    xmlSchemaPIllegalAttrErr(ctxt,
				XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
			}
		    } else if ((!xmlStrEqual(attr->name, BAD_CAST "final")) &&
			(!xmlStrEqual(attr->name, BAD_CAST "abstract")) &&
			(!xmlStrEqual(attr->name, BAD_CAST "substitutionGroup"))) {

			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/validate attributes.
	*/
	if (topLevel) {
	    /*
	    * Process top attributes of global element declarations here.
	    */
	    decl->flags |= XML_SCHEMAS_ELEM_GLOBAL;
	    decl->flags |= XML_SCHEMAS_ELEM_TOPLEVEL;
	    xmlSchemaPValAttrQName(ctxt, schema,
		NULL, node, "substitutionGroup",
		&(decl->substGroupNs), &(decl->substGroup));
	    if (xmlGetBooleanProp(ctxt, node, "abstract", 0))
		decl->flags |= XML_SCHEMAS_ELEM_ABSTRACT;
	    /*
	    * Attribute "final".
	    */
	    attr = xmlSchemaGetPropNode(node, "final");
	    if (attr == NULL) {
		if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_EXTENSION)
		    decl->flags |= XML_SCHEMAS_ELEM_FINAL_EXTENSION;
		if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION)
		    decl->flags |= XML_SCHEMAS_ELEM_FINAL_RESTRICTION;
	    } else {
		attrValue = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
		if (xmlSchemaPValAttrBlockFinal(attrValue, &(decl->flags),
		    -1,
		    XML_SCHEMAS_ELEM_FINAL_EXTENSION,
		    XML_SCHEMAS_ELEM_FINAL_RESTRICTION, -1, -1, -1) != 0) {
		    xmlSchemaPSimpleTypeErr(ctxt,
			XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
			NULL, (xmlNodePtr) attr,
			NULL, "(#all | List of (extension | restriction))",
			attrValue, NULL, NULL, NULL);
		}
	    }
	}
	/*
	* Attribute "block".
	*/
	attr = xmlSchemaGetPropNode(node, "block");
	if (attr == NULL) {
	    /*
	    * Apply default "block" values.
	    */
	    if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_RESTRICTION)
		decl->flags |= XML_SCHEMAS_ELEM_BLOCK_RESTRICTION;
	    if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_EXTENSION)
		decl->flags |= XML_SCHEMAS_ELEM_BLOCK_EXTENSION;
	    if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_SUBSTITUTION)
		decl->flags |= XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION;
	} else {
	    attrValue = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
	    if (xmlSchemaPValAttrBlockFinal(attrValue, &(decl->flags),
		-1,
		XML_SCHEMAS_ELEM_BLOCK_EXTENSION,
		XML_SCHEMAS_ELEM_BLOCK_RESTRICTION,
		XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION, -1, -1) != 0) {
		xmlSchemaPSimpleTypeErr(ctxt,
		    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
		    NULL, (xmlNodePtr) attr,
		    NULL, "(#all | List of (extension | "
		    "restriction | substitution))", attrValue,
		    NULL, NULL, NULL);
	    }
	}
	if (xmlGetBooleanProp(ctxt, node, "nillable", 0))
	    decl->flags |= XML_SCHEMAS_ELEM_NILLABLE;

	attr = xmlSchemaGetPropNode(node, "type");
	if (attr != NULL) {
	    xmlSchemaPValAttrNodeQName(ctxt, schema,
		NULL, attr,
		&(decl->namedTypeNs), &(decl->namedType));
	    xmlSchemaCheckReference(ctxt, schema, node,
		attr, decl->namedTypeNs);
	}
	decl->value = xmlSchemaGetProp(ctxt, node, "default");
	attr = xmlSchemaGetPropNode(node, "fixed");
	if (attr != NULL) {
	    fixed = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
	    if (decl->value != NULL) {
		/*
		* 3.3.3 : 1
		* default and fixed must not both be present.
		*/
		xmlSchemaPMutualExclAttrErr(ctxt,
		    XML_SCHEMAP_SRC_ELEMENT_1,
		    NULL, attr, "default", "fixed");
	    } else {
		decl->flags |= XML_SCHEMAS_ELEM_FIXED;
		decl->value = fixed;
	    }
	}
	/*
	* And now for the children...
	*/
	if (IS_SCHEMA(child, "complexType")) {
	    /*
	    * 3.3.3 : 3
	    * "type" and either <simpleType> or <complexType> are mutually
	    * exclusive
	    */
	    if (decl->namedType != NULL) {
		xmlSchemaPContentErr(ctxt,
		    XML_SCHEMAP_SRC_ELEMENT_3,
		    NULL, node, child,
		    "The attribute 'type' and the <complexType> child are "
		    "mutually exclusive", NULL);
	    } else
		WXS_ELEM_TYPEDEF(decl) = xmlSchemaParseComplexType(ctxt, schema, child, 0);
	    child = child->next;
	} else if (IS_SCHEMA(child, "simpleType")) {
	    /*
	    * 3.3.3 : 3
	    * "type" and either <simpleType> or <complexType> are
	    * mutually exclusive
	    */
	    if (decl->namedType != NULL) {
		xmlSchemaPContentErr(ctxt,
		    XML_SCHEMAP_SRC_ELEMENT_3,
		    NULL, node, child,
		    "The attribute 'type' and the <simpleType> child are "
		    "mutually exclusive", NULL);
	    } else
		WXS_ELEM_TYPEDEF(decl) = xmlSchemaParseSimpleType(ctxt, schema, child, 0);
	    child = child->next;
	}
	while ((IS_SCHEMA(child, "unique")) ||
	    (IS_SCHEMA(child, "key")) || (IS_SCHEMA(child, "keyref"))) {
	    if (IS_SCHEMA(child, "unique")) {
		curIDC = xmlSchemaParseIDC(ctxt, schema, child,
		    XML_SCHEMA_TYPE_IDC_UNIQUE, decl->targetNamespace);
	    } else if (IS_SCHEMA(child, "key")) {
		curIDC = xmlSchemaParseIDC(ctxt, schema, child,
		    XML_SCHEMA_TYPE_IDC_KEY, decl->targetNamespace);
	    } else if (IS_SCHEMA(child, "keyref")) {
		curIDC = xmlSchemaParseIDC(ctxt, schema, child,
		    XML_SCHEMA_TYPE_IDC_KEYREF, decl->targetNamespace);
	    }
	    if (lastIDC != NULL)
		lastIDC->next = curIDC;
	    else
		decl->idcs = (void *) curIDC;
	    lastIDC = curIDC;
	    child = child->next;
	}
	if (child != NULL) {
	    xmlSchemaPContentErr(ctxt,
		XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
		NULL, node, child,
		NULL, "(annotation?, ((simpleType | complexType)?, "
		"(unique | key | keyref)*))");
	}
	decl->annot = annot;
    }
    /*
    * NOTE: Element Declaration Representation OK 4. will be checked at a
    * different layer.
    */
    FREE_AND_NULL(des)
    if (topLevel)
	return ((xmlSchemaBasicItemPtr) decl);
    else {
	particle->children = (xmlSchemaTreeItemPtr) decl;
	return ((xmlSchemaBasicItemPtr) particle);
    }

return_null:
    FREE_AND_NULL(des);
    if (annot != NULL) {
	if (particle != NULL)
	    particle->annot = NULL;
	if (decl != NULL)
	    decl->annot = NULL;
	xmlSchemaFreeAnnot(annot);
    }
    return (NULL);
}