Added an initial skeleton for indentity-constraints. This is all defined

* xmlschemas.c include/libxml/schemasInternals.h:
  Added an initial skeleton for indentity-constraints. This is all
  defined out, since not complete, plus it needs support from other
  modules.
  Added machanism to store element information for the
  ancestor-or-self axis; this is needed for identity-constraints
  and should be helpfull for a future streamable validation.
* include/libxml/xmlerror.h: Added an error code for
  identity-constraints.
diff --git a/xmlschemas.c b/xmlschemas.c
index 4e4dd49..da1f0df 100644
--- a/xmlschemas.c
+++ b/xmlschemas.c
@@ -34,6 +34,7 @@
 #include <libxml/xmlautomata.h>
 #include <libxml/xmlregexp.h>
 #include <libxml/dict.h>
+#include <libxml/xpath.h>
 
 /* #define DEBUG 1 */
 
@@ -49,6 +50,16 @@
 
 /* #define DEBUG_UNION_VALIDATION 1 */
 
+#define ELEM_INFO_ENABLED 1
+
+/* #define IDC_ENABLED 1 */
+
+/* #define IDC_VALUE_SUPPORT 1 */
+
+/* #define IDC_XPATH_SUPPORT 1 */
+
+/* #define DEBUG_IDC 1 */
+
 
 #define UNBOUNDED (1 << 30)
 #define TODO 								\
@@ -216,6 +227,191 @@
     const xmlChar *value;
 };
 
+typedef struct _xmlSchemaBasicItem xmlSchemaBasicItem;
+typedef xmlSchemaBasicItem *xmlSchemaBasicItemPtr;
+struct _xmlSchemaBasicItem {
+    xmlSchemaTypeType type;
+    xmlSchemaAnnotPtr annot;
+};
+
+typedef struct _xmlSchemaItemQNRef xmlSchemaItemQNRef;
+typedef xmlSchemaItemQNRef *xmlSchemaItemQNRefPtr;
+struct _xmlSchemaItemQNRef {
+    xmlSchemaBasicItemPtr item;
+    const xmlChar *name;
+    const xmlChar *targetNamespace;
+};
+
+typedef struct _xmlSchemaIDC xmlSchemaIDC;
+typedef xmlSchemaIDC *xmlSchemaIDCPtr;
+
+/**
+ * xmlSchemaIDCSelect:
+ *
+ * The identity-constraint "field" and "selector" item, holding the
+ * XPath expression.
+ */
+typedef struct _xmlSchemaIDCSelect xmlSchemaIDCSelect;
+typedef xmlSchemaIDCSelect *xmlSchemaIDCSelectPtr;
+struct _xmlSchemaIDCSelect {    
+    xmlSchemaIDCSelectPtr next;
+    xmlSchemaIDCPtr idc;
+    int index; /* an index position if significant for IDC key-sequences */
+    const xmlChar *xpath; /* the XPath expression */
+    xmlXPathCompExprPtr xpathComp; /* the compiled XPath expression */
+};
+
+/**
+ * xmlSchemaIDC:
+ *
+ * The identity-constraint definition component.
+ */
+
+struct _xmlSchemaIDC {
+    xmlSchemaTypeType type;
+    xmlSchemaAnnotPtr annot;
+    xmlSchemaIDCPtr next;
+    xmlNodePtr node;
+    const xmlChar *name;    
+    const xmlChar *targetNamespace;
+    xmlSchemaIDCSelectPtr selector;
+    xmlSchemaIDCSelectPtr fields;
+    int nbFields;
+    xmlSchemaItemQNRefPtr ref;
+};
+
+/**
+ * xmlSchemaIDCAug:
+ *
+ * The augmented IDC information used for validation.
+ */
+typedef struct _xmlSchemaIDCAug xmlSchemaIDCAug;
+typedef xmlSchemaIDCAug *xmlSchemaIDCAugPtr;
+struct _xmlSchemaIDCAug {
+    xmlSchemaIDCAugPtr next; /* next in a list */
+    xmlSchemaIDCPtr def; /* the IDC definition */
+    int bubbleDepth; /* the lowest level to which IDC 
+                        tables need to be bubbled upwards */
+};
+
+/**
+ * xmlSchemaPSVIIDCKeySequence:
+ *
+ * The key sequence of a node table item.
+ */
+typedef struct _xmlSchemaPSVIIDCKey xmlSchemaPSVIIDCKey;
+typedef xmlSchemaPSVIIDCKey *xmlSchemaPSVIIDCKeyPtr;
+struct _xmlSchemaPSVIIDCKey {
+    xmlSchemaTypePtr type;
+    xmlSchemaValPtr compValue;
+};
+
+/**
+ * xmlSchemaPSVIIDCNode:
+ *
+ * The node table item of a node table.
+ */
+typedef struct _xmlSchemaPSVIIDCNode xmlSchemaPSVIIDCNode;
+typedef xmlSchemaPSVIIDCNode *xmlSchemaPSVIIDCNodePtr;
+struct _xmlSchemaPSVIIDCNode {
+    xmlNodePtr node;
+    xmlSchemaPSVIIDCKeyPtr *keys;
+};
+
+/**
+ * xmlSchemaPSVIIDCBinding:
+ *
+ * The identity-constraint binding item of the [identity-constraint table].
+ */
+typedef struct _xmlSchemaPSVIIDCBinding xmlSchemaPSVIIDCBinding;
+typedef xmlSchemaPSVIIDCBinding *xmlSchemaPSVIIDCBindingPtr;
+struct _xmlSchemaPSVIIDCBinding {
+    xmlSchemaPSVIIDCBindingPtr next; /* next binding of a specific node */
+    xmlSchemaIDCPtr definition; /* the IDC definition */
+    xmlSchemaPSVIIDCNodePtr *nodeTable; /* array of key-sequences */
+    int nbNodes; /* number of entries in the node table */
+    int sizeNodes; /* size of the node table */
+    int nbDupls; /* number of already identified duplicates in the node 
+                    table */
+    /* int nbKeys; number of keys in each key-sequence */
+};
+
+#define XPATH_STATE_OBJ_TYPE_IDC_SELECTOR 1
+#define XPATH_STATE_OBJ_TYPE_IDC_FIELD 2
+
+#define XPATH_STATE_OBJ_MATCHES -2
+#define XPATH_STATE_OBJ_BLOCKED -3
+
+typedef struct _xmlSchemaIDCMatcher xmlSchemaIDCMatcher;
+typedef xmlSchemaIDCMatcher *xmlSchemaIDCMatcherPtr;
+
+/**
+ * xmlSchemaIDCStateObj:
+ *
+ * The state object used to evaluate XPath expressions.
+ */
+typedef struct _xmlSchemaIDCStateObj xmlSchemaIDCStateObj;
+typedef xmlSchemaIDCStateObj *xmlSchemaIDCStateObjPtr;
+struct _xmlSchemaIDCStateObj {
+    int type;
+    xmlSchemaIDCStateObjPtr parent; /* the parent selector state object */
+    xmlSchemaIDCStateObjPtr next; /* next if in a list */
+    int topDown;
+    int **history; /* list of (depth, state-id) tuples */
+    int nbHistory;
+    int sizeHistory;
+    xmlSchemaIDCMatcherPtr matcher; /* the correspondent field/selector
+                                       matcher */
+    xmlSchemaIDCSelectPtr sel;
+};
+
+#define IDC_MATCHER 0
+
+/**
+ * xmlSchemaIDCMatcher:
+ *
+ * Used to  IDC selectors (and fields) successively.
+ */
+struct _xmlSchemaIDCMatcher {
+    int type;
+    int depth; /* the tree depth at creation time */
+    xmlSchemaIDCMatcherPtr next; /* next in the list */
+    xmlSchemaIDCAugPtr aidc; /* the augmented IDC item */
+    xmlSchemaPSVIIDCKeyPtr **keySeqs; /* the key-sequences of the target
+                                         elements */
+    int sizeKeySeqs;
+    xmlSchemaPSVIIDCKeyPtr **refKeySeqs;
+    int nbRefKeySeqs;
+    int sizeRefKeySeqs;
+    int targetDepth;
+};
+
+/*
+* Element info flags.
+*/
+#define XML_SCHEMA_ELEM_INFO_VALUE_NEEDED 1<<0
+
+/**
+ * xmlSchemaElemInfo:
+ *
+ * Holds information of an element node.
+ */
+typedef struct _xmlSchemaElemInfo xmlSchemaElemInfo;
+typedef xmlSchemaElemInfo *xmlSchemaElemInfoPtr;
+struct _xmlSchemaElemInfo {
+    int depth;
+    int flags; /* combination of element info flags */
+    xmlNodePtr node;
+    const xmlChar *localName;
+    const xmlChar *namespaceName;
+    xmlSchemaTypePtr typeDef; /* the complex/simple type definition if any */
+    xmlSchemaValPtr value; /* the pre-computed value if any */
+    xmlSchemaPSVIIDCBindingPtr idcTable; /* the table of PSVI IDC bindings
+                                            for the scope element*/
+    xmlSchemaIDCMatcherPtr idcMatchers; /* the IDC matchers for the scope
+                                           element */
+};
+
 /**
  * xmlSchemaValidCtxt:
  *
@@ -225,7 +421,7 @@
 struct _xmlSchemaValidCtxt {
     void *userData;             /* user specific data block */
     xmlSchemaValidityErrorFunc error;   /* the callback in case of errors */
-    xmlSchemaValidityWarningFunc warning;       /* the callback in case of warning */
+    xmlSchemaValidityWarningFunc warning; /* the callback in case of warning */
     xmlStructuredErrorFunc serror;
 
     xmlSchemaPtr schema;        /* The schema in use */
@@ -254,6 +450,26 @@
     xmlNodePtr validationRoot;    
     xmlSchemaParserCtxtPtr pctxt;
     int xsiAssemble;
+#ifdef ELEM_INFO_ENABLED
+    int depth;
+    xmlSchemaElemInfoPtr *elemInfos; /* array of element informations */
+    int sizeElemInfos;
+    xmlSchemaElemInfoPtr elemInfo; /* the current element information */
+#endif
+#ifdef IDC_ENABLED
+    xmlSchemaIDCAugPtr aidcs; /* a list of augmented IDC informations */
+
+    xmlSchemaIDCStateObjPtr xpathStates; /* first active state object. */
+    xmlSchemaIDCStateObjPtr xpathStatePool; /* first stored state object. */
+    
+    xmlSchemaPSVIIDCNodePtr *idcNodes; /* list of all IDC node-table entries*/
+    int nbIdcNodes;
+    int sizeIdcNodes;
+
+    xmlSchemaPSVIIDCKeyPtr *idcKeys; /* list of all IDC node-table entries */
+    int nbIdcKeys;
+    int sizeIdcKeys;
+#endif
 };
 
 /*
@@ -328,7 +544,7 @@
 xmlSchemaValidateSimpleTypeValue(xmlSchemaValidCtxtPtr ctxt, 
 				 xmlSchemaTypePtr type,
 				 const xmlChar *value,
-				 int fireErrors,				 
+				 int fireErrors,
 				 int applyFacets,
 				 int normalize,
 				 int checkNodes);
@@ -744,7 +960,8 @@
     if (itemDes != NULL) {
 	*buf = xmlStrdup(itemDes);	
     } else if (item != NULL) {
-	if (item->type == XML_SCHEMA_TYPE_BASIC) {
+	switch (item->type) {
+	case XML_SCHEMA_TYPE_BASIC:
 	    if (item->builtInType == XML_SCHEMAS_ANYTYPE)
 		*buf = xmlStrdup(BAD_CAST "'anyType'");
 	    else if (item->builtInType == XML_SCHEMAS_ANYSIMPLETYPE)
@@ -756,7 +973,8 @@
 		*buf = xmlStrcat(*buf, item->name);
 		*buf = xmlStrcat(*buf, BAD_CAST "'");
 	    }
-	} else if (item->type == XML_SCHEMA_TYPE_SIMPLE) {
+	    break;
+	case XML_SCHEMA_TYPE_SIMPLE:
 	    if (item->flags & XML_SCHEMAS_TYPE_GLOBAL) {
 		*buf = xmlStrdup(xmlSchemaElemDesST);
 		*buf = xmlStrcat(*buf, BAD_CAST " '");
@@ -764,11 +982,9 @@
 		*buf = xmlStrcat(*buf, BAD_CAST "'");
 	    } else {
 		*buf = xmlStrdup(xmlSchemaElemDesST);
-		/* Local types will get to name
-		*buf = xmlStrcat(*buf, BAD_CAST " ");
-		*/
 	    }
-	} else if (item->type == XML_SCHEMA_TYPE_COMPLEX) {
+	    break;
+	case XML_SCHEMA_TYPE_COMPLEX:
 	    if (item->flags & XML_SCHEMAS_TYPE_GLOBAL) {
 		*buf = xmlStrdup(xmlSchemaElemDesCT);
 		*buf = xmlStrcat(*buf, BAD_CAST " '");
@@ -776,48 +992,63 @@
 		*buf = xmlStrcat(*buf, BAD_CAST "'");
 	    } else {
 		*buf = xmlStrdup(xmlSchemaElemDesCT);
-		/* Local types will get to name 
-		*buf = xmlStrcat(*buf, BAD_CAST " ");
-		*/
 	    }
-	} else if (item->type == XML_SCHEMA_TYPE_ATTRIBUTE) {
-	    xmlSchemaAttributePtr attr;
+	    break;
+	case XML_SCHEMA_TYPE_ATTRIBUTE: {
+		xmlSchemaAttributePtr attr;
+	    
+		attr = (xmlSchemaAttributePtr) item;	    
+		if ((attr->flags & XML_SCHEMAS_TYPE_GLOBAL) ||
+		    (attr->ref == NULL)) {
+		    *buf = xmlStrdup(xmlSchemaElemDesAttrDecl);
+		    *buf = xmlStrcat(*buf, BAD_CAST " '");
+		    *buf = xmlStrcat(*buf, attr->name);
+		    *buf = xmlStrcat(*buf, BAD_CAST "'");
+		} else {
+		    *buf = xmlStrdup(xmlSchemaElemDesAttrRef);
+		    *buf = xmlStrcat(*buf, BAD_CAST " '");
+		    *buf = xmlStrcat(*buf, attr->refPrefix);
+		    *buf = xmlStrcat(*buf, BAD_CAST ":");
+		    *buf = xmlStrcat(*buf, attr->ref);
+		    *buf = xmlStrcat(*buf, BAD_CAST "'");
+		}	
+	    }
+	    break;
+	case XML_SCHEMA_TYPE_ELEMENT: {
+		xmlSchemaElementPtr elem;
 
-	    attr = (xmlSchemaAttributePtr) item;	    
-	    if ((attr->flags & XML_SCHEMAS_TYPE_GLOBAL) ||
-		(attr->ref == NULL)) {
-		*buf = xmlStrdup(xmlSchemaElemDesAttrDecl);
-		*buf = xmlStrcat(*buf, BAD_CAST " '");
-		*buf = xmlStrcat(*buf, attr->name);
-		*buf = xmlStrcat(*buf, BAD_CAST "'");
-	    } else {
-		*buf = xmlStrdup(xmlSchemaElemDesAttrRef);
-		*buf = xmlStrcat(*buf, BAD_CAST " '");
-		*buf = xmlStrcat(*buf, attr->refPrefix);
-		*buf = xmlStrcat(*buf, BAD_CAST ":");
-		*buf = xmlStrcat(*buf, attr->ref);
-		*buf = xmlStrcat(*buf, BAD_CAST "'");
-	   }		
-	} else if (item->type == XML_SCHEMA_TYPE_ELEMENT) {
-	    xmlSchemaElementPtr elem;
-
-	    elem = (xmlSchemaElementPtr) item;	    
-	    if ((elem->flags & XML_SCHEMAS_TYPE_GLOBAL) || 
-		(elem->ref == NULL)) {
-		*buf = xmlStrdup(xmlSchemaElemDesElemDecl);
-		*buf = xmlStrcat(*buf, BAD_CAST " '");
-		*buf = xmlStrcat(*buf, elem->name);
-		*buf = xmlStrcat(*buf, BAD_CAST "'");
-	    } else {
-		*buf = xmlStrdup(xmlSchemaElemDesElemRef);
-		*buf = xmlStrcat(*buf, BAD_CAST " '");
-		*buf = xmlStrcat(*buf, elem->refPrefix);
-		*buf = xmlStrcat(*buf, BAD_CAST ":");
-		*buf = xmlStrcat(*buf, elem->ref);
-		*buf = xmlStrcat(*buf, BAD_CAST "'");
-	    }		
-	} else
+		elem = (xmlSchemaElementPtr) item;	    
+		if ((elem->flags & XML_SCHEMAS_TYPE_GLOBAL) || 
+		    (elem->ref == NULL)) {
+		    *buf = xmlStrdup(xmlSchemaElemDesElemDecl);
+		    *buf = xmlStrcat(*buf, BAD_CAST " '");
+		    *buf = xmlStrcat(*buf, elem->name);
+		    *buf = xmlStrcat(*buf, BAD_CAST "'");
+		} else {
+		    *buf = xmlStrdup(xmlSchemaElemDesElemRef);
+		    *buf = xmlStrcat(*buf, BAD_CAST " '");
+		    *buf = xmlStrcat(*buf, elem->refPrefix);
+		    *buf = xmlStrcat(*buf, BAD_CAST ":");
+		    *buf = xmlStrcat(*buf, elem->ref);
+		    *buf = xmlStrcat(*buf, BAD_CAST "'");
+		}
+	    }
+	    break;
+	case XML_SCHEMA_TYPE_IDC_UNIQUE:
+	case XML_SCHEMA_TYPE_IDC_KEY:
+	case XML_SCHEMA_TYPE_IDC_KEYREF:		
+	    if (item->type == XML_SCHEMA_TYPE_IDC_UNIQUE)
+		*buf = xmlStrdup(BAD_CAST "unique '");
+	    else if (item->type == XML_SCHEMA_TYPE_IDC_KEY)
+		*buf = xmlStrdup(BAD_CAST "key '");
+	    else
+		*buf = xmlStrdup(BAD_CAST "keyRef '");
+	    *buf = xmlStrcat(*buf, ((xmlSchemaIDCPtr) item)->name);
+	    *buf = xmlStrcat(*buf, BAD_CAST "'");
+	    break;
+	default:
 	    named = 0;
+	}
     } else 
 	named = 0;
 
@@ -2305,6 +2536,64 @@
     xmlFree(type);
 }
 
+static void
+xmlSchemaFreeIDCStateObjList(xmlSchemaIDCStateObjPtr sto)
+{
+    xmlSchemaIDCStateObjPtr next;
+    while (sto != NULL) {
+	next = sto->next;
+	if (sto->history != NULL) {
+	    int i;
+	    for (i = 0; i < sto->sizeHistory; i++) {
+		if (sto->history[i] != NULL)
+		    xmlFree(sto->history[i]);
+		else 
+		    break;
+	    }
+	    xmlFree(sto->history);
+	}
+	xmlFree(sto);
+	sto = next;
+    }
+}
+
+/**
+ * xmlSchemaFreeIDC:
+ * @idc: a identity-constraint definition
+ *
+ * Deallocates an identity-constraint definition.
+ */
+void
+xmlSchemaFreeIDC(xmlSchemaIDCPtr idc)
+{
+    xmlSchemaIDCSelectPtr cur, prev;
+
+    if (idc == NULL)
+	return;
+    if (idc->annot != NULL)
+        xmlSchemaFreeAnnot(idc->annot);
+    if (idc->ref != NULL)
+	xmlFree(idc->ref);
+    /* Selector */
+    if (idc->selector != NULL) {
+	if (idc->selector->xpathComp != NULL)
+	    xmlXPathFreeCompExpr(idc->selector->xpathComp);
+	xmlFree(idc->selector);
+    }
+    /* Fields */
+    if (idc->fields != NULL) {
+	cur = idc->fields;
+	do {
+	    prev = cur;
+	    cur = cur->next;
+	    if (prev->xpathComp != NULL)
+		xmlXPathFreeCompExpr(prev->xpathComp);
+	    xmlFree(prev);	    
+	} while (cur != NULL);
+    }
+    xmlFree(idc);
+}
+
 /**
  * xmlSchemaFreeTypeList:
  * @type:  a schema type structure
@@ -2631,6 +2920,65 @@
     xmlHashScanFull(schema->elemDecl,
                     (xmlHashScannerFull) xmlSchemaElementDump, output);
 }
+
+/**
+ * xmlSchemaDebugDumpIDCTable: 
+ * @vctxt: the WXS validation context
+ *
+ * Displays the current IDC table for debug purposes.
+ */
+static void
+xmlSchemaDebugDumpIDCTable(FILE * output,
+			   const xmlChar *namespaceName,
+			   const xmlChar *localName,
+			   xmlSchemaPSVIIDCBindingPtr bind)
+{
+    xmlChar *str = NULL, *value;    
+    xmlSchemaPSVIIDCNodePtr tab;
+    xmlSchemaPSVIIDCKeyPtr key;
+    int i, j, res;
+    
+    fprintf(output, "IDC: TABLES on %s\n", 
+	xmlSchemaFormatNsUriLocal(&str, namespaceName, localName));
+    FREE_AND_NULL(str)
+
+    if (bind == NULL)
+	return;
+    do {
+	fprintf(output, "IDC:   BINDING %s\n", 
+	    xmlSchemaFormatNsUriLocal(&str, bind->definition->targetNamespace,
+	    bind->definition->name));
+	FREE_AND_NULL(str)	
+	for (i = 0; i < bind->nbNodes; i++) {
+	    tab = bind->nodeTable[i];
+	    fprintf(output, "         ( ");
+	    for (j = 0; j < bind->definition->nbFields; j++) {
+		key = tab->keys[j];		
+		if ((key != NULL) && (key->compValue != NULL)) {
+#ifdef IDC_VALUE_SUPPORT
+		    res = xmlSchemaGetCanonValue(key->compValue, &value);
+#else
+		    value = xmlStrdup(BAD_CAST "dummy-value");
+		    res = 0;
+#endif
+		    if (res == 0)
+			fprintf(output, "\"%s\" ", value);
+		    else
+			fprintf(output, "CANON-VALUE-FAILED ", value);
+		    if (value != NULL) {
+			xmlFree(value);
+			value = NULL;
+		    }
+		} else if (key != NULL)
+		    fprintf(output, "(no val), ", key->compValue);
+		else
+		    fprintf(output, "(key missing), ");
+	    }
+	    fprintf(output, ")\n");
+	}
+	bind = bind->next;
+    } while (bind != NULL);
+}
 #endif /* LIBXML_OUTPUT_ENABLED */
 
 /************************************************************************
@@ -5415,6 +5763,370 @@
     return (ret);
 }
 
+static int
+xmlSchemaCheckCSelectorXPath(xmlSchemaParserCtxtPtr ctxt, 
+			     xmlSchemaPtr schema,
+			     xmlSchemaIDCPtr idc,
+			     xmlSchemaIDCSelectPtr selector,
+			     xmlNodePtr parNode,
+			     xmlAttrPtr attr,
+			     int isField)
+{
+    xmlNodePtr node;
+
+    /*
+    * c-selector-xpath: 
+    * Schema Component Constraint: Selector Value OK
+    *
+    * TODO: 1 The {selector} must be a valid XPath expression, as defined 
+    * in [XPath].
+    */
+    if (selector == NULL) {
+	xmlSchemaPErr(ctxt, idc->node, 
+	    XML_SCHEMAP_INTERNAL,
+	    "Internal error: xmlSchemaCheckCSelectorXPath, "
+	    "the selector is not specified.\n", NULL, NULL);
+	return (-1);
+    }
+    if (attr == NULL)
+	node = idc->node;
+    else
+	node = (xmlNodePtr) attr;
+    if (selector->xpath == NULL) {
+	xmlSchemaPCustomErr(ctxt,
+	    /* TODO: Adjust error code. */
+	    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, 
+	    NULL, NULL, node, 
+	    "The XPath expression of the selector is not valid", NULL);
+	return (XML_SCHEMAP_S4S_ATTR_INVALID_VALUE);
+    } else {
+	/*
+	* Compile the XPath expression.
+	*/
+	/*
+	* TODO: We need the array of in-scope namespaces for compilation.
+	*/	
+	selector->xpathComp = xmlXPathCompile(selector->xpath);
+#ifdef IDC_XPATH_SUPPORT
+	if ((selector->xpathComp == NULL) || 
+	    (xmlXPathWXSIDCValid(selector->xpathComp, isField) != 0)) {
+	    xmlSchemaPCustomErr(ctxt,
+		/* TODO: Adjust error code? */
+		XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, 
+		NULL, NULL, node, 
+		"The XPath expression '%s' could not be "
+		"compiled", selector->xpath);
+	    return (XML_SCHEMAP_S4S_ATTR_INVALID_VALUE);
+	}		
+#endif
+    }
+    return (0);
+}
+
+/**
+ * xmlSchemaAssignAnnotation:
+ * @item: the schema component
+ * @annot: the annotation
+ *
+ * Adds the annotation to the given schema component.
+ *
+ * Returns the given annotaion.
+ */
+static xmlSchemaAnnotPtr
+xmlSchemaAssignAnnotation(xmlSchemaBasicItemPtr item,
+			  xmlSchemaAnnotPtr annot)
+{
+    xmlSchemaAnnotPtr cur = item->annot;
+
+    if (item->annot == NULL) {
+	item->annot = annot;
+	return (annot);
+    }
+    cur = item->annot;
+    if (cur->next != NULL) {
+	cur = cur->next;	
+    }
+    cur->next = annot;
+    return (annot);
+}
+
+/**
+ * xmlSchemaParseIDCSelectorAndField:
+ * @ctxt:  a schema validation context
+ * @schema:  the schema being built
+ * @node:  a subtree containing XML Schema informations
+ *
+ * Parses a XML Schema identity-contraint definition's
+ * <selector> and <field> elements.
+ *
+ * Returns the parsed identity-constraint definition.
+ */
+static xmlSchemaIDCSelectPtr
+xmlSchemaParseIDCSelectorAndField(xmlSchemaParserCtxtPtr ctxt, 
+			  xmlSchemaPtr schema,
+			  xmlSchemaIDCPtr idc,
+			  xmlNodePtr node,
+			  int isField)
+{
+    xmlSchemaIDCSelectPtr item;
+    xmlNodePtr child = NULL;
+    xmlAttrPtr attr;
+    
+    /*
+    * 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 "xpath"))) {
+		xmlSchemaPIllegalAttrErr(ctxt, 
+		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, 
+		    NULL, NULL, attr);		    
+	    }
+	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
+	    xmlSchemaPIllegalAttrErr(ctxt, 
+		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, 
+		NULL, NULL, attr);	
+	}
+	attr = attr->next;
+    }      
+    /*
+    * Create the item.
+    */       
+    item = (xmlSchemaIDCSelectPtr) xmlMalloc(sizeof(xmlSchemaIDCSelect));
+    if (item == NULL) {
+        xmlSchemaPErrMemory(ctxt, 
+	    "allocating a 'selector' of an identity-constraint definition", 
+	    NULL);
+        return (NULL);
+    }
+    memset(item, 0, sizeof(xmlSchemaIDCSelect));   
+    /*
+    * Attribute "xpath" (mandatory).
+    */
+    attr = xmlSchemaGetPropNode(node, "xpath");
+    if (attr == NULL) {
+    	xmlSchemaPMissingAttrErr(ctxt, 
+	    XML_SCHEMAP_S4S_ATTR_MISSING, 
+	    NULL, NULL, node,
+	    "name", NULL);
+    } else {
+	item->xpath = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
+	/*
+	* URGENT TODO: "field"s have an other syntax than "selector"s.
+	*/
+
+	if (xmlSchemaCheckCSelectorXPath(ctxt, schema, 
+	    idc, item, node, attr, isField) == -1) 
+	{
+	    xmlSchemaPErr(ctxt, 
+		(xmlNodePtr) attr, 
+		XML_SCHEMAP_INTERNAL,		
+		"Internal error: xmlSchemaParseIDCSelectorAndField, "
+		"validating the XPath expression of a IDC selector.\n", 
+		NULL, NULL);
+	}
+
+    }    
+    /*
+    * And now for the children...
+    */
+    child = node->children;
+    if (IS_SCHEMA(child, "annotation")) {
+	/*
+	* Add the annotation to the parent IDC.
+	*/
+	xmlSchemaAssignAnnotation((xmlSchemaBasicItemPtr) idc, 
+	    xmlSchemaParseAnnotation(ctxt, schema, child));
+	child = child->next;
+    }  		    
+    if (child != NULL) {
+	xmlSchemaPContentErr(ctxt,
+	    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
+	    NULL, NULL, node, child, 
+	    NULL, "(annotation?)");
+    }
+    
+    return (item);
+}
+
+/**
+ * xmlSchemaParseIDC:
+ * @ctxt:  a schema validation context
+ * @schema:  the schema being built
+ * @node:  a subtree containing XML Schema informations
+ *
+ * Parses a XML Schema identity-contraint definition.
+ *
+ * Returns the parsed identity-constraint definition.
+ */
+static xmlSchemaIDCPtr
+xmlSchemaParseIDC(xmlSchemaParserCtxtPtr ctxt, 
+		  xmlSchemaPtr schema,
+		  xmlNodePtr node,
+		  xmlSchemaTypeType idcCategory,
+		  const xmlChar *targetNamespace)
+{
+    xmlSchemaIDCPtr item = NULL;
+    xmlNodePtr child = NULL;
+    xmlAttrPtr attr;
+    const xmlChar *name = NULL;
+    xmlSchemaIDCSelectPtr field = NULL, lastField = NULL;
+    int resAdd;
+    
+    /*
+    * 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")) &&
+		((idcCategory != XML_SCHEMA_TYPE_IDC_KEYREF) ||
+		 (!xmlStrEqual(attr->name, BAD_CAST "refer")))) {
+		xmlSchemaPIllegalAttrErr(ctxt, 
+		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, 
+		    NULL, NULL, attr);		    
+	    }
+	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
+	    xmlSchemaPIllegalAttrErr(ctxt, 
+		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, 
+		NULL, NULL, attr);	
+	}
+	attr = attr->next;
+    }  
+    /*
+    * Attribute "name" (mandatory).
+    */
+    attr = xmlSchemaGetPropNode(node, "name");
+    if (attr == NULL) {
+	xmlSchemaPMissingAttrErr(ctxt, 
+	    XML_SCHEMAP_S4S_ATTR_MISSING, 
+	    NULL, NULL, node,
+	    "name", NULL);
+	return (NULL);
+    } else if (xmlSchemaPValAttrNode(ctxt, 
+	NULL, NULL, attr, 
+	xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &name) != 0) {
+	return (NULL);
+    }    
+    /*
+    * Create the component.
+    */
+    if (schema->idcDef == NULL)
+        schema->idcDef = xmlHashCreateDict(10, ctxt->dict);
+    if (schema->idcDef == NULL) 
+        return (NULL);
+
+    item = (xmlSchemaIDCPtr) xmlMalloc(sizeof(xmlSchemaIDC));
+    if (item == NULL) {
+        xmlSchemaPErrMemory(ctxt, 
+	    "allocating an identity-constraint definition", NULL);
+        return (NULL);
+    }    
+    /*
+    * Add the IDC to the list of IDCs on the schema component.
+    */
+    resAdd = xmlHashAddEntry2(schema->idcDef, name, targetNamespace, item);
+    if (resAdd != 0) {	           
+	xmlSchemaPCustomErrExt(ctxt,
+	    XML_SCHEMAP_REDEFINED_TYPE,
+	    NULL, NULL, node, 
+	    "An identity-constraint definition with the name '%s' "
+	    "and targetNamespace '%s' does already exist", 
+	    name, targetNamespace, NULL);
+	xmlFree(item);
+	return (NULL);
+    }
+    
+    memset(item, 0, sizeof(xmlSchemaIDC));
+    item->name = name;
+    item->type = idcCategory;  
+    item->node = node;
+    /*
+    * The target namespace of the parent element declaration.
+    */
+    item->targetNamespace = targetNamespace;   
+    /* TODO: Handle attribute "id". */
+    if (idcCategory == XML_SCHEMA_TYPE_IDC_KEYREF) {
+	/*
+	* Attribute "refer" (mandatory).
+	*/
+	attr = xmlSchemaGetPropNode(node, "refer");
+	if (attr == NULL) {
+	    xmlSchemaPMissingAttrErr(ctxt, 
+		XML_SCHEMAP_S4S_ATTR_MISSING, 
+		NULL, NULL, node,
+		"refer", NULL);
+	} else {
+	    /*
+	    * Create a reference item.
+	    */
+	    item->ref = (xmlSchemaItemQNRefPtr) xmlMalloc(
+		sizeof(xmlSchemaItemQNRef));
+	    if (item->ref == NULL) {
+		xmlSchemaPErrMemory(ctxt, 
+		    "allocating a QName reference item", NULL);
+		return (NULL);
+	    }
+	    memset(item->ref, 0, sizeof(xmlSchemaItemQNRef));
+	    xmlSchemaPValAttrNodeQName(ctxt, schema,
+		NULL, NULL, attr, 
+		&(item->ref->targetNamespace), 0, 
+		&(item->ref->name));
+	}
+    }
+    /*
+    * And now for the children...
+    */
+    child = node->children;
+    if (IS_SCHEMA(child, "annotation")) {
+	item->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
+	child = child->next;
+    }
+    /*
+    * Child element <selector>.
+    */
+    if (IS_SCHEMA(child, "selector")) {    
+	item->selector = xmlSchemaParseIDCSelectorAndField(ctxt, schema, 
+	    item, child, 0);
+	child = child->next;
+	/*
+	* Child elements <field>.
+	*/
+	if (IS_SCHEMA(child, "field")) {
+	    do {
+		field = xmlSchemaParseIDCSelectorAndField(ctxt, schema, 
+		    item, child, 1);
+		if (field != NULL) {
+		    field->index = item->nbFields;
+		    item->nbFields++;
+		    if (lastField != NULL)
+			lastField->next = field;		    
+		    else
+			item->fields = field;
+		    lastField = field;
+		}
+		child = child->next;
+	    } while (IS_SCHEMA(child, "field"));
+	} else {
+	    xmlSchemaPContentErr(ctxt,
+		XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
+		NULL, NULL, node, child, 
+		NULL, "(annotation?, (selector, field+))");
+	}
+    }    
+    if (child != NULL) {
+	xmlSchemaPContentErr(ctxt,
+	    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
+	    NULL, NULL, node, child, 
+	    NULL, "(annotation?, (selector, field+))");
+    }		
+
+    return (item);
+}
+
 /**
  * xmlSchemaParseElement:
  * @ctxt:  a schema validation context
@@ -5439,6 +6151,9 @@
     xmlAttrPtr attr, nameAttr;
     int minOccurs, maxOccurs;
     int isRef = 0;
+#ifdef IDC_ENABLED
+    xmlSchemaIDCPtr curIDC, lastIDC = NULL;
+#endif
 
     /* 3.3.3 Constraints on XML Representations of Element Declarations */
     /* TODO: Complete implementation of 3.3.6 */
@@ -5486,7 +6201,7 @@
 	* Parse as a particle.
 	*/
 	xmlSchemaPValAttrNodeQName(ctxt, schema,
-	    (xmlChar **) &xmlSchemaElemDesAttrRef, 
+	    (xmlChar **) &xmlSchemaElemDesElemRef, 
 	    NULL, attr, &refNs, &refPrefix, &ref);			
 	 
         snprintf(buf, 49, "#eRef %d", ctxt->counter++ + 1);
@@ -5780,7 +6495,24 @@
 	}	
 	while ((IS_SCHEMA(child, "unique")) ||
 	    (IS_SCHEMA(child, "key")) || (IS_SCHEMA(child, "keyref"))) {
-	    TODO child = child->next;
+#ifdef IDC_ENABLED
+	    if (IS_SCHEMA(child, "unique")) {
+		curIDC = xmlSchemaParseIDC(ctxt, schema, child, 
+		    XML_SCHEMA_TYPE_IDC_UNIQUE, ret->targetNamespace);
+	    } else if (IS_SCHEMA(child, "key")) {
+		curIDC = xmlSchemaParseIDC(ctxt, schema, child,
+		    XML_SCHEMA_TYPE_IDC_KEY, ret->targetNamespace);
+	    } else if (IS_SCHEMA(child, "keyref")) {
+		curIDC = xmlSchemaParseIDC(ctxt, schema, child,
+		    XML_SCHEMA_TYPE_IDC_KEYREF, ret->targetNamespace);
+	    }
+	    if (lastIDC != NULL)
+		lastIDC->next = curIDC;
+	    else
+		(xmlSchemaIDCPtr) ret->idcs = curIDC;
+	    lastIDC = curIDC;
+#endif
+	    child = child->next;
 	}
 	if (child != NULL) {
 	    xmlSchemaPContentErr(ctxt,
@@ -11402,10 +12134,11 @@
 		* thus a check for equality can be skipped.
 		*/
 		/*
-		* TODO: Even worse: I cannot see a scenario where a restricting
+		* Even worse: I cannot see a scenario where a restricting
 		* union simple type can have other member types as the member 
 		* types of it's base type. This check seems not necessary with
 		* respect to the derivation process in libxml2.
+		* But necessary if constructing types with an API.
 		*/
 		if (type->memberTypes != NULL) {
 		    member = type->memberTypes;
@@ -12542,6 +13275,30 @@
 			item->contentType =
 			    item->subtypes->contentType;
 		    }
+
+		    /*
+		    * Some optimization for validation:
+		    * If there are no facets beside the "whitespace" facet,
+		    * then a value needs not to checked against against a
+		    * facet, thus no computed value is needed.
+		    * TODO URGENT: This is just a workaround, we need to
+		    * introduce the correct usage of contentType to store the
+		    * facets in!
+		    */
+		    if (item->baseType->flags && XML_SCHEMAS_TYPE_FACETSNEEDVALUE)
+			item->flags |= XML_SCHEMAS_TYPE_FACETSNEEDVALUE;
+		    else {
+			xmlSchemaFacetLinkPtr cur;
+
+			for (cur = item->facetSet; cur != NULL;
+			    cur = cur->next) {
+			    if (cur->facet->type != XML_SCHEMA_FACET_WHITESPACE) {
+				item->flags |= XML_SCHEMAS_TYPE_FACETSNEEDVALUE;
+				break;
+			    }
+			}
+		    }	
+
 		    xmlSchemaBuildAttributeValidation(ctxt, item);
 		    xmlSchemaCheckDefaults(item, ctxt, item->name);
 		    ctxt->ctxtType = ctxtType;
@@ -12647,49 +13404,75 @@
 			    if (last != NULL)
 				while (last->next != NULL)
 				    last = last->next;
-				cur = item->baseType->facetSet;
-				for (; cur != NULL; cur = cur->next) {
-				    /* 
-				    * Base patterns won't be add here:
-				    * they are ORed in a type and
-				    * ANDed in derived types. This will
-				    * happed at validation level by
-				    * walking the base axis of the type.
+			    cur = item->baseType->facetSet;
+			    for (; cur != NULL; cur = cur->next) {
+				/* 
+				* Base patterns won't be add here:
+				* they are ORed in a type and
+				* ANDed in derived types. This will
+				* happed at validation level by
+				* walking the base axis of the type.
+				*/
+				if (cur->facet->type == 
+				    XML_SCHEMA_FACET_PATTERN) 
+				    continue;
+				facet = NULL;
+				if ((item->facetSet != NULL) &&
+				    /* REMOVED: a check for
+				    * XML_SCHEMA_FACET_PATTERN was already
+				    * performed above.
+				
+				    * (cur->facet->type != 
+				    * XML_SCHEMA_FACET_PATTERN) &&
 				    */
-				    if (cur->facet->type == 
-					XML_SCHEMA_FACET_PATTERN) 
-					continue;
-				    facet = NULL;
-				    if ((item->facetSet != NULL) &&
-					(cur->facet->type != 
-					XML_SCHEMA_FACET_PATTERN) &&
-					(cur->facet->type != 
-					XML_SCHEMA_FACET_ENUMERATION)) {				
-					facet = item->facetSet;
-					do {
-					    if (cur->facet->type == 
-						facet->facet->type) 
-						break;
-					    facet = facet->next;
-					} while (facet != NULL);
-				    }
-				    if (facet == NULL) {
-					facet = (xmlSchemaFacetLinkPtr) 
-					    xmlMalloc(sizeof(xmlSchemaFacetLink));
-					if (facet == NULL) {
-					    xmlSchemaPErrMemory(ctxt, 
-						"fixing simpleType", NULL);
-					    return;
-					}
-					facet->facet = cur->facet;
-					facet->next = NULL;
-					if (last == NULL)
-					    item->facetSet = facet;		    
-					else 
-					    last->next = facet;
-					last = facet;				
-				    }				    
+				  (cur->facet->type != 
+				  XML_SCHEMA_FACET_ENUMERATION)) {				
+				    facet = item->facetSet;
+				    do {
+					if (cur->facet->type == 
+					    facet->facet->type) 
+					    break;
+					facet = facet->next;
+				    } while (facet != NULL);
 				}
+				if (facet == NULL) {
+				    facet = (xmlSchemaFacetLinkPtr) 
+					xmlMalloc(sizeof(xmlSchemaFacetLink));
+				    if (facet == NULL) {
+					xmlSchemaPErrMemory(ctxt, 
+					    "fixing simpleType", NULL);
+					return;
+				    }
+				    /*
+				    * The facets are not copied but referenced
+				    * via the facet link.
+				    */
+				    facet->facet = cur->facet;
+				    facet->next = NULL;
+				    if (last == NULL)
+					item->facetSet = facet;		    
+				    else 
+					last->next = facet;
+				    last = facet;				
+				}				    
+			    }
+			}
+			/*
+			* Some optimization for validation:
+			* If there are no facets beside the "whitespace" facet,
+			* then a value needs not to checked against against a
+			* facet, thus no computed value is needed.
+			*/
+			if (item->baseType->flags && XML_SCHEMAS_TYPE_FACETSNEEDVALUE)
+			    item->flags |= XML_SCHEMAS_TYPE_FACETSNEEDVALUE;
+			else {
+			    for (cur = item->facetSet; cur != NULL;
+			    cur = cur->next) {
+				if (cur->facet->type != XML_SCHEMA_FACET_WHITESPACE) {
+				    item->flags |= XML_SCHEMAS_TYPE_FACETSNEEDVALUE;
+				    break;
+				}
+			    }
 			}
 		    }
 		}	
@@ -13593,6 +14376,41 @@
 }
 
 /**
+ * xmlSchemaResolveIDCKeyRef:
+ * @idc:  the identity-constraint definition
+ * @ctxt:  the schema parser context
+ * @name:  the attribute name
+ *
+ * Resolve keyRef references to key/unique IDCs.
+ */
+static void
+xmlSchemaResolveIDCKeyRef(xmlSchemaIDCPtr idc,
+			  xmlSchemaParserCtxtPtr ctxt, 
+			  const xmlChar * name)
+{  
+    if (idc->type != XML_SCHEMA_TYPE_IDC_KEYREF)
+        return;
+    if (idc->ref->name != NULL) { 	
+	idc->ref->item = (xmlSchemaBasicItemPtr) xmlHashLookup2(
+	    ctxt->schema->idcDef, 
+	    idc->ref->name, 
+	    idc->ref->targetNamespace);
+        if (idc->ref->item == NULL) {
+	    /* 
+	    * TODO: It is actually not an error to fail to resolve.
+	    */
+	    xmlSchemaPResCompAttrErr(ctxt, 
+		XML_SCHEMAP_SRC_RESOLVE,
+		NULL, (xmlSchemaTypePtr) idc, idc->node,
+		"refer", idc->ref->name, 
+		idc->ref->targetNamespace, 
+		XML_SCHEMA_TYPE_IDC_KEYREF, NULL);
+            return;
+	}        
+    }
+}
+
+/**
  * xmlSchemaParse:
  * @ctxt:  a schema validation context
  *
@@ -13707,6 +14525,11 @@
                 ctxt);
 
     /*
+    * Resolve identity-constraint keyRefs.
+    */
+    xmlHashScan(ret->idcDef, (xmlHashScanner) xmlSchemaResolveIDCKeyRef, ctxt);
+
+    /*
     * Check attribute groups for circular references.
     */
     xmlHashScan(ret->attrgrpDecl, (xmlHashScanner) 
@@ -14115,6 +14938,79 @@
 					  xmlSchemaTypePtr type,
 					  int valSimpleContent);
 
+static void xmlSchemaBeginElement(xmlSchemaValidCtxtPtr vctxt);
+static void xmlSchemaEndElement(xmlSchemaValidCtxtPtr vctxt);
+
+#ifdef ELEM_INFO_ENABLED
+/**
+ * xmlSchemaGetFreshElemInfo:
+ * @vctxt: the schema validation context
+ *
+ * Creates/reuses and initializes the element info item for 
+ * the currect tree depth.
+ *
+ * Returns the element info item or NULL on API or internal errors.
+ */
+static xmlSchemaElemInfoPtr
+xmlSchemaGetFreshElemInfo(xmlSchemaValidCtxtPtr vctxt)
+{
+    xmlSchemaElemInfoPtr info = NULL;
+    
+    if (vctxt->depth > vctxt->sizeElemInfos) {
+	xmlSchemaVErr(vctxt, NULL, XML_SCHEMAV_INTERNAL,
+	    "Internal error: xmlSchemaPushDepthInfo, "
+	    "an inconsistent depth encountered.\n",
+	    NULL, NULL);
+	return (NULL);
+    }
+    if (vctxt->elemInfos == NULL) {	
+	vctxt->elemInfos = (xmlSchemaElemInfoPtr *) 
+	    xmlMalloc(10 * sizeof(xmlSchemaElemInfoPtr));
+	if (vctxt->elemInfos == NULL) {
+	    xmlSchemaVErrMemory(vctxt, 
+		"allocating the element info array", NULL);
+	    return (NULL);
+	}
+	memset(vctxt->elemInfos, 0, 10 * sizeof(xmlSchemaElemInfoPtr));
+	vctxt->sizeElemInfos = 10;
+    } else if (vctxt->sizeElemInfos == vctxt->depth) {
+	int i = vctxt->sizeElemInfos;
+
+	vctxt->sizeElemInfos *= 2;
+	vctxt->elemInfos = (xmlSchemaElemInfoPtr *) 
+	    xmlRealloc(vctxt->elemInfos, vctxt->sizeElemInfos * 
+	    sizeof(xmlSchemaElemInfoPtr));
+	if (vctxt->elemInfos == NULL) {
+	    xmlSchemaVErrMemory(vctxt, 
+		"re-allocating the element info array", NULL);
+	    return (NULL);
+	}
+	/*
+	* We need the new memory to be NULLed.
+	* TODO: Use memset instead?
+	*/
+	for (; i < vctxt->sizeElemInfos; i++)
+	    vctxt->elemInfos[i] = NULL;
+    } else
+	info = vctxt->elemInfos[vctxt->depth];
+
+    if (info == NULL) {
+	info = (xmlSchemaElemInfoPtr) 
+	    xmlMalloc(sizeof(xmlSchemaElemInfo));
+	if (info == NULL) {
+	    xmlSchemaVErrMemory(vctxt, 
+		"allocating an element info", NULL);
+	    return (NULL);
+	}	
+	vctxt->elemInfos[vctxt->depth] = info;
+    }
+    memset(info, 0, sizeof(xmlSchemaElemInfo));
+    info->depth = vctxt->depth;
+  
+    return (info);
+}
+#endif /* ELEM_INFO_ENABLED */
+
 
 /**
  * xmlSchemaFreeAttrStates:
@@ -14583,6 +15479,11 @@
     ctxt->type = type;
     ctxt->node = node;    
     ctxt->cur = node->children;
+
+#ifdef ELEM_INFO_ENABLED
+    xmlSchemaBeginElement(ctxt);
+#endif
+
     /*
     * Assemble new schemata using xsi.
     */
@@ -14596,7 +15497,7 @@
 		ctxt->node, NULL, 	
 		"Internal error: xmlSchemaValidateElement, "
 		"assembling schema by xsi", NULL);
-	    return;
+	    goto leave;
 	}
 	/*
 	* NOTE: We won't react on schema parser errors here.
@@ -14622,7 +15523,7 @@
 		    "element declaration 'reference' encountered, "
 		    "but an element declaration was expected", 
 		    NULL);
-		return;
+		goto leave;
 	    }
 	    xmlSchemaValidateElementByDeclaration(ctxt, 
 		(xmlSchemaElementPtr) type);
@@ -14634,6 +15535,17 @@
 	default: 
 	    break;
     }
+leave:
+
+#ifdef ELEM_INFO_ENABLED
+    xmlSchemaEndElement(ctxt);
+    /*
+    xmlSchemaDebugDumpIDCTable(stdout,
+	    NULL,
+	    ctxt->node->name,
+	    ctxt->elemInfo->idcTable);
+    */
+#endif
     ctxt->type = oldtype;
     ctxt->node = oldnode;
 }  
@@ -15096,7 +16008,7 @@
     if ((valSimpleContent == 1) &&
 	((type->type != XML_SCHEMA_TYPE_BASIC) ||
 	 (type->builtInType != XML_SCHEMAS_ANYSIMPLETYPE))) {
-	xmlChar *value;	
+	xmlChar *value;
 
 	value = xmlNodeGetContent(node);
 	/*
@@ -15237,6 +16149,1781 @@
     return (0);
 }
 
+/************************************************************************
+ * 									*
+ *  Identity-constraints (IDC)                                          *
+ * 									*
+ ************************************************************************/
+
+#ifdef IDC_ENABLED
+
+/**
+ * xmlSchemaIDCNewBinding:
+ * @idcDef: the IDC definition of this binding
+ *
+ * Creates a new IDC binding.
+ *
+ * Returns the new binding in case of succeeded, NULL on internal errors.
+ */
+static xmlSchemaPSVIIDCBindingPtr
+xmlSchemaIDCNewBinding(xmlSchemaIDCPtr idcDef)
+{
+    xmlSchemaPSVIIDCBindingPtr ret;
+
+    ret = (xmlSchemaPSVIIDCBindingPtr) xmlMalloc(
+	    sizeof(xmlSchemaPSVIIDCBinding));
+    if (ret == NULL) {
+	xmlSchemaVErrMemory(NULL, 
+	    "allocating a PSVI IDC binding item", NULL);
+	return (NULL);
+    }
+    memset(ret, 0, sizeof(xmlSchemaPSVIIDCBinding));
+    ret->definition = idcDef;
+    return (ret);
+}
+
+/**
+ * xmlSchemaIDCStoreNodeTableItem:
+ * @vctxt: the WXS validation context
+ * @item: the IDC node table item
+ *
+ * The validation context is used to store an IDC node table items.
+ * They are stored to avoid copying them if IDC node-tables are merged
+ * with corresponding parent IDC node-tables (bubbling).
+ *
+ * Returns 0 if succeeded, -1 on internal errors.
+ */
+static int
+xmlSchemaIDCStoreNodeTableItem(xmlSchemaValidCtxtPtr vctxt, 
+			       xmlSchemaPSVIIDCNodePtr item)
+{
+    /*
+    * Add to gobal list.
+    */    
+    if (vctxt->idcNodes == NULL) {			
+	vctxt->idcNodes = (xmlSchemaPSVIIDCNodePtr *) 
+	    xmlMalloc(20 * sizeof(xmlSchemaPSVIIDCNodePtr));
+	if (vctxt->idcNodes == NULL) {
+	    xmlSchemaVErrMemory(vctxt, 
+		"allocating the IDC node table item list", NULL);
+	    return (-1);
+	}
+	vctxt->sizeIdcNodes = 20;
+    } else if (vctxt->sizeIdcNodes <= vctxt->nbIdcNodes) {
+	vctxt->sizeIdcNodes *= 2;
+	vctxt->idcNodes = (xmlSchemaPSVIIDCNodePtr *) 
+	    xmlRealloc(vctxt->idcNodes, vctxt->sizeIdcNodes * 
+	    sizeof(xmlSchemaPSVIIDCNodePtr));
+	if (vctxt->idcNodes == NULL) {
+	    xmlSchemaVErrMemory(vctxt, 
+		"re-allocating the IDC node table item list", NULL);
+	    return (-1);
+	}
+    }
+    vctxt->idcNodes[vctxt->nbIdcNodes++] = item;
+   
+    return (0);
+}
+
+/**
+ * xmlSchemaIDCStoreKey:
+ * @vctxt: the WXS validation context
+ * @item: the IDC key
+ *
+ * The validation context is used to store an IDC key.
+ *
+ * Returns 0 if succeeded, -1 on internal errors.
+ */
+static int
+xmlSchemaIDCStoreKey(xmlSchemaValidCtxtPtr vctxt, 
+		     xmlSchemaPSVIIDCKeyPtr key)
+{
+    /*
+    * Add to gobal list.
+    */    
+    if (vctxt->idcKeys == NULL) {
+	vctxt->idcKeys = (xmlSchemaPSVIIDCKeyPtr *) 
+	    xmlMalloc(40 * sizeof(xmlSchemaPSVIIDCKeyPtr));
+	if (vctxt->idcKeys == NULL) {
+	    xmlSchemaVErrMemory(vctxt, 
+		"allocating the IDC key storage list", NULL);
+	    return (-1);
+	}
+	vctxt->sizeIdcKeys = 40;
+    } else if (vctxt->sizeIdcKeys <= vctxt->nbIdcKeys) {
+	vctxt->sizeIdcKeys *= 2;
+	vctxt->idcKeys = (xmlSchemaPSVIIDCKeyPtr *) 
+	    xmlRealloc(vctxt->idcKeys, vctxt->sizeIdcKeys * 
+	    sizeof(xmlSchemaPSVIIDCKeyPtr));
+	if (vctxt->idcKeys == NULL) {
+	    xmlSchemaVErrMemory(vctxt, 
+		"re-allocating the IDC key storage list", NULL);
+	    return (-1);
+	}
+    }
+    vctxt->idcKeys[vctxt->nbIdcKeys++] = key;
+   
+    return (0);
+}
+
+/**
+ * xmlSchemaIDCAppendNodeTableItem:
+ * @bind: the IDC binding
+ * @ntItem: the node-table item
+ *
+ * Appends the IDC node-table item to the binding.
+ *
+ * Returns 0 on success and -1 on internal errors.
+ */
+static int 
+xmlSchemaIDCAppendNodeTableItem(xmlSchemaPSVIIDCBindingPtr bind,
+				xmlSchemaPSVIIDCNodePtr ntItem)
+{
+    if (bind->nodeTable == NULL) {
+	bind->sizeNodes = 10;
+	bind->nodeTable = (xmlSchemaPSVIIDCNodePtr *) 
+	    xmlMalloc(10 * sizeof(xmlSchemaPSVIIDCNodePtr));
+	if (bind->nodeTable == NULL) {
+	    xmlSchemaVErrMemory(NULL, 
+		"allocating an array of IDC node-table items", NULL);
+	    return(-1);
+	}	
+    } else if (bind->sizeNodes <= bind->nbNodes) {
+	bind->sizeNodes *= 2;
+	bind->nodeTable = (xmlSchemaPSVIIDCNodePtr *) 
+	    xmlRealloc(bind->nodeTable, bind->sizeNodes * 
+		sizeof(xmlSchemaPSVIIDCNodePtr));
+	if (bind->nodeTable == NULL) {
+	    xmlSchemaVErrMemory(NULL, 
+		"re-allocating an array of IDC node-table items", NULL);
+	    return(-1);
+	}
+    }
+    bind->nodeTable[bind->nbNodes++] = ntItem;
+    return(0);   
+}
+
+/**
+ * xmlSchemaIDCAquireBinding: 
+ * @vctxt: the WXS validation context
+ * @matcher: the IDC matcher
+ *
+ * Looks up an PSVI IDC binding, for the IDC definition and 
+ * of the given matcher. If none found, a new one is created
+ * and added to the IDC table.
+ *
+ * Returns an IDC binding or NULL on internal errors.
+ */
+static xmlSchemaPSVIIDCBindingPtr
+xmlSchemaIDCAquireBinding(xmlSchemaValidCtxtPtr vctxt,
+			  xmlSchemaIDCMatcherPtr matcher)
+{
+    xmlSchemaElemInfoPtr info;
+
+    info = vctxt->elemInfos[matcher->depth];
+
+    if (info->idcTable == NULL) {
+	info->idcTable = xmlSchemaIDCNewBinding(matcher->aidc->def);
+	if (info->idcTable == NULL)
+	    return (NULL);
+	return(info->idcTable);
+    } else {
+	xmlSchemaPSVIIDCBindingPtr bind = NULL;
+	
+	bind = info->idcTable;
+	do {
+	    if (bind->definition == matcher->aidc->def)
+		return(bind);
+	    if (bind->next == NULL) {
+		bind->next = xmlSchemaIDCNewBinding(matcher->aidc->def);
+		if (bind->next == NULL)
+		    return (NULL);
+		return(bind->next);
+	    }
+	    bind = bind->next;
+	} while (bind != NULL);	
+    }
+    return (NULL);
+}
+
+/**
+ * xmlSchemaIDCFreeKey: 
+ * @key: the IDC key
+ *
+ * Frees an IDC key together with its compiled value.
+ */
+static void 
+xmlSchemaIDCFreeKey(xmlSchemaPSVIIDCKeyPtr key)
+{
+    if (key->compValue != NULL)
+	xmlSchemaFreeValue(key->compValue);
+    xmlFree(key);
+}
+
+/**
+ * xmlSchemaIDCFreeBinding:
+ *
+ * Frees an IDC binding. Note that the node table-items
+ * are not freed.
+ */
+xmlSchemaIDCFreeBinding(xmlSchemaPSVIIDCBindingPtr bind)
+{
+    if (bind->nodeTable != NULL) {
+	xmlFree(bind->nodeTable);
+    }
+    xmlFree(bind);
+}
+
+/**
+ * xmlSchemaIDCFreeIDCTable:
+ * @bind: the first IDC binding in the list
+ *
+ * Frees an IDC table, i.e. all the IDC bindings in the list.
+ */
+static void
+xmlSchemaIDCFreeIDCTable(xmlSchemaPSVIIDCBindingPtr bind)
+{
+    xmlSchemaPSVIIDCBindingPtr prev;
+
+    while (bind != NULL) {
+	prev = bind;		    
+	bind = bind->next;
+	xmlSchemaIDCFreeBinding(prev);
+    }
+}
+
+/**
+ * xmlSchemaIDCFreeMatcherList:
+ * @matcher: the first IDC matcher in the list
+ *
+ * Frees a list of IDC matchers.
+ */
+static void
+xmlSchemaIDCFreeMatcherList(xmlSchemaIDCMatcherPtr matcher)
+{
+    xmlSchemaIDCMatcherPtr next;
+
+    while (matcher != NULL) {
+	next = matcher->next;
+	if (matcher->keySeqs != NULL) {
+	    int i;
+	    for (i = 0; i < matcher->sizeKeySeqs; i++)
+		if (matcher->keySeqs[i] != NULL)
+		    xmlFree(matcher->keySeqs[i]);
+	    xmlFree(matcher->keySeqs);
+	}
+	xmlFree(matcher);
+	matcher = next;
+    }
+}
+
+/**
+ * xmlSchemaAreValuesEqual:
+ * @ta: the first type
+ * @a: the first value
+ * @tb: the second type
+ * @b: the second value
+ *
+ * Compares two values.
+ *
+ * Returns 1 if they are equal, 0 if not and -1 on internal errors.
+ */
+static int
+xmlSchemaAreValuesEqual(xmlSchemaTypePtr ta,
+			xmlSchemaValPtr a,
+			xmlSchemaTypePtr tb,
+			xmlSchemaValPtr b) 
+{   
+    int typeEqual = 0;
+    
+    /* Same user derived/built-in derived/built-in primitive types. */
+    if (ta == tb)
+	goto compareValue;
+    
+    /*
+    * Comparison with anySimpleTypes is not supported by this implemention.
+    */
+    if ((ta->builtInType == XML_SCHEMAS_ANYSIMPLETYPE) ||
+	(tb->builtInType == XML_SCHEMAS_ANYSIMPLETYPE))
+	return(0);
+    
+    /*
+    * 4.2.1 equal (data-types)
+    *
+    * the ·value space·s of all ·primitive· datatypes are disjoint 
+    * (they do not share any values) 
+    */
+    if ((ta->builtInType != 0) && (tb->builtInType != 0) &&
+	(ta->flags & XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE) && 
+	(tb->flags & XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE))
+	return(0);
+
+    if ((ta->flags & XML_SCHEMAS_TYPE_VARIETY_LIST) ||
+	(ta->flags & XML_SCHEMAS_TYPE_VARIETY_UNION) ||
+	(tb->flags & XML_SCHEMAS_TYPE_VARIETY_LIST) ||
+	(tb->flags & XML_SCHEMAS_TYPE_VARIETY_UNION)) {
+	TODO
+	return(0);
+    }
+    /*
+    * (1) if a datatype T' is ·derived· by ·restriction· from an atomic datatype
+    * T then the ·value space· of T' is a subset of the ·value space· of T. 
+    */
+    /*
+    * (2) if datatypes T' and T'' are ·derived· by ·restriction· from a common 
+    * atomic ancestor T then the ·value space·s of T' and T'' may overlap. 
+    */
+    
+    {
+	xmlSchemaTypePtr pta = ta, ptb = tb;
+
+	/* Note that we will compare the primitives here. */
+	while ((pta->builtInType == 0) ||
+	       ((pta->flags & XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE) == 0))
+	    pta = pta->baseType;	
+	while ((ptb->builtInType == 0) ||
+	       ((ptb->flags & XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE) == 0))
+	    ptb = ptb->baseType;
+	if (pta == ptb)
+	    goto compareValue;
+	return(0);
+    }
+compareValue:
+    {	
+#ifdef IDC_VALUE_SUPPORT
+	int ret;
+	ret = xmlSchemaCompareValuesOpt(a, b,
+	    XML_SCHEMA_VALUECOMP_STRISNORM);
+	if (ret == 0) 
+	    return(1);
+	else if (ret == -2)
+	    return(-1);
+	else
+	    return(0);
+#else
+	return (1);
+#endif
+    }
+}
+
+/**
+ * xmlSchemaXPathChangeState:
+ * @vctxt: the WXS validation context
+ * @sto: the state object
+ * @newState: the state index to be added to the history
+ *
+ * Adds an entry (vctxt->depth and newState) to the history of the
+ * state object.
+ *
+ * Returns 1 if they are equal, 0 if not and -1 on internal errors.
+ */
+static int
+xmlSchemaXPathChangeState(xmlSchemaValidCtxtPtr vctxt,
+			xmlSchemaIDCStateObjPtr sto,
+			int newState)
+
+{
+    int *change = NULL;
+    /*
+    * Create/grow the array of history items.
+    */
+    if (sto->history == NULL) {
+	sto->history = (int **) xmlMalloc(5 * sizeof(int *));
+	if (sto->history == NULL) {
+	    xmlSchemaVErrMemory(NULL, 
+		"allocating an array of state change informations", NULL);
+	    xmlFree(sto);
+	    return(-1);
+	}
+	memset(sto->history, 0, 5 * sizeof(int *));
+	sto->sizeHistory = 10;
+    } else if (sto->sizeHistory > sto->nbHistory) {
+	/*
+	* Reuse a history item.
+	*/
+	change = sto->history[sto->nbHistory];
+    } else {
+	int i = sto->sizeHistory;
+
+	sto->sizeHistory *= 2;
+	sto->history = (int **) xmlRealloc(sto->history, 
+	    sto->sizeHistory * sizeof(int *));
+	if (sto->history == NULL) {
+	    xmlSchemaVErrMemory(NULL, 
+		"re-allocating an array of state change informations", NULL);
+	    return(-1);
+	}
+	/*
+	* The new memory needs to be NULLed.
+	* TODO: Use memset instead?
+	*/
+	for (; i < sto->sizeHistory; i++)
+	    sto->history[i] = NULL;    
+    }	
+    /*
+    * Create the history item.
+    */
+    if (change == NULL) {
+	change = (int *) xmlMalloc(2 * sizeof(int));
+	if (change == NULL) {
+	    xmlSchemaVErrMemory(NULL, 
+		"allocating a state change information", NULL);
+	    return(-1);
+	}
+	sto->history[sto->nbHistory] = change;
+    }
+    sto->nbHistory++;
+    /*
+    * Init the history item.
+    */
+    change[0] = vctxt->depth;
+    change[1] = newState;
+#ifdef DEBUG_IDC
+    xmlGenericError(xmlGenericErrorContext, "IDC:       push state '%d'\n",
+	newState);
+#endif
+    return(0);
+}
+
+/**
+ * xmlSchemaIDCAddStateObject:
+ * @vctxt: the WXS validation context
+ * @matcher: the IDC matcher
+ * @sel: the XPath information
+ * @parent: the parent "selector" state object if any
+ * @type: "selector" or "field"
+ *
+ * Creates/reuses and activates state objects for the given
+ * XPath information; if the XPath expression consists of unions,
+ * multiple state objects are created for every unioned expression.
+ *
+ * Returns 0 on success and -1 on internal errors.
+ */
+static int
+xmlSchemaIDCAddStateObject(xmlSchemaValidCtxtPtr vctxt,
+			xmlSchemaIDCMatcherPtr matcher,
+			xmlSchemaIDCSelectPtr sel,
+			xmlSchemaIDCStateObjPtr parent,
+			int type)
+{
+    xmlSchemaIDCStateObjPtr sto;
+    int i = 0, stateId, reversed;
+
+    /*
+    * Create a state object for every location path in the XPath expression.
+    */
+    while (1) {
+#ifdef IDC_XPATH_SUPPORT
+	stateId = xmlXPathWXSIDCGetLocationPath(sel->xpathComp, i, &reversed);
+#else
+	break;
+#endif
+	if (stateId < 0)
+	    break;
+	/*
+	* Reuse the state objects from the pool.
+	*/
+	if (vctxt->xpathStatePool != NULL) {
+	    sto = vctxt->xpathStatePool;
+	    vctxt->xpathStatePool = sto->next;
+	    sto->next = NULL;
+	} else {	
+	    /*
+	    * Create a new state object.
+	    */
+	    sto = (xmlSchemaIDCStateObjPtr) xmlMalloc(sizeof(xmlSchemaIDCStateObj));
+	    if (sto == NULL) {
+		xmlSchemaVErrMemory(NULL,
+		    "allocating an IDC state object", NULL);
+		return (-1);
+	    }
+	    memset(sto, 0, sizeof(xmlSchemaIDCStateObj));
+	}	
+	sto->type = type;
+	sto->parent = parent;
+	sto->matcher = matcher;
+	sto->sel = sel;
+	sto->nbHistory = 0;	
+	/*
+	* Add to global list. 
+	*/	
+	if (vctxt->xpathStates != NULL)
+	    sto->next = vctxt->xpathStates;
+	vctxt->xpathStates = sto;
+#if DEBUG_IDC
+	xmlGenericError(xmlGenericErrorContext, "IDC:   STO push '%s'\n",
+	    sto->sel->xpath);
+#endif		
+	xmlSchemaXPathChangeState(vctxt, sto, stateId);
+	/*
+	* Set if the state object should be processed as a push
+	* down transducer (topDown == 1) or upwards the ancestor axis of
+	* the tree.
+	*/
+	if (reversed)
+	    sto->topDown = 1;	
+	i++;
+    };
+
+    return (0);
+}
+
+/**
+ * xmlSchemaXPathEvaluate:
+ * @vctxt: the WXS validation context
+ * @nodeType: the nodeType of the current node
+ *
+ * Evaluates all active XPath state objects.
+ *
+ * Returns the number of IC "field" state objects which resolved to
+ * this node, 0 if none resolved and -1 on internal errors.
+ */
+static int
+xmlSchemaXPathEvaluate(xmlSchemaValidCtxtPtr vctxt,
+		       const xmlChar *namespaceName,
+		       const xmlChar *localName,
+		       xmlElementType nodeType)
+{
+    xmlSchemaIDCStateObjPtr sto, head = NULL, first;
+    int retState, *change;
+    int res, resolved = 0;
+        
+    if (vctxt->xpathStates == NULL)
+	return (0);
+#if DEBUG_IDC
+    {
+	xmlChar *str = NULL;
+	xmlGenericError(xmlGenericErrorContext, 
+	    "IDC: EVAL on %s, depth %d, type %d\n",	    
+	    xmlSchemaFormatNsUriLocal(&str, namespaceName,
+		localName), vctxt->depth, nodeType);
+	FREE_AND_NULL(str)
+    }
+#endif
+    /*
+    * Process all active XPath state objects.
+    */
+    first = vctxt->xpathStates;
+    sto = first;
+    while (sto != head) {
+	/*
+	* Evaluate:
+	* 1. all bottom-up state objs.
+	* 2. top-down state objs. which are not marked as
+	*    matching or blocking.
+	* Note: sto->history[0][0] will hold the depth of creation.
+	*/
+	if (sto->topDown == 0) {
+	    /*
+	    * Always start from the beginning with bottom-up
+	    * evaluation.
+	    */
+	    change = sto->history[0];
+	} else {
+	    change = sto->history[sto->nbHistory -1];
+	    if (change[1] < 0)
+		goto next_sto;
+	}
+	/*
+	* change[0] holds the depth of change.
+	* change[1] holds the state index or the "match" or "blocked"
+	* indicator.
+	*/
+	retState = -1;
+#if DEBUG_IDC
+	if (sto->type == XPATH_STATE_OBJ_IDC_SELECTOR)
+	    xmlGenericError(xmlGenericErrorContext, "IDC:   ['%s'] selector '%s'\n", 
+		sto->matcher->aidc->def->name, sto->sel->xpath);
+	else
+	    xmlGenericError(xmlGenericErrorContext, "IDC:   ['%s'] field '%s'\n", 
+		sto->matcher->aidc->def->name, sto->sel->xpath);
+#endif
+	if (sto->topDown == 0) {
+	    /*
+	    * The XPath will be evaluated using the
+	    * ancestor-or-self axis.
+	    */
+#ifdef IDC_XPATH_SUPPORT
+	    res = xmlXPathWXSIDCEvalOneNode(sto->sel->xpathComp, 
+		change[1], &retState, nodeType,
+		localName, namespaceName);
+#else
+	    res = 0;
+#endif
+	    if (res == 1) {
+		int i;
+
+		if (nodeType == XML_ELEMENT_NODE)
+		    i = vctxt->depth -1;
+		else
+		    i = vctxt->depth;
+		while ((res == 1) && (i >= 0)) {
+		    /*
+		    * If we get a partial match, evaluate the
+		    * ancestor axis.
+		    */
+#ifdef IDC_XPATH_SUPPORT
+		    res = xmlXPathWXSIDCEvalOneNode(sto->sel->xpathComp, 
+			retState, &retState, XML_ELEMENT_NODE,
+			vctxt->elemInfos[i]->localName, 
+			vctxt->elemInfos[i]->namespaceName);
+#endif
+		    i--;
+		}
+	    }
+	    if (res == -1) {
+		xmlSchemaVErr(vctxt, vctxt->node,
+		    XML_SCHEMAV_INTERNAL,
+		    "Internal error: xmlSchemaXPathEvaluate, "
+		    "failed to evaluate a node.\n",
+		    NULL, NULL);
+		return (-1);
+	    } else if (res != 2) {
+		/*
+		* We will record matches only.
+		*/
+#if DEBUG_IDC
+		xmlGenericError(xmlGenericErrorContext, "IDC:     "
+		    "no match\n");
+#endif
+		goto next_sto;
+	    }
+	} else {
+	    /*
+	    * Push-down.
+	    */
+#ifdef IDC_XPATH_SUPPORT
+	    res = xmlXPathWXSIDCEvalOneNode(sto->sel->xpathComp, 
+		change[1], &retState, nodeType,
+		localName, namespaceName);
+#else
+	    res = 0;
+#endif
+	    if (res == -1) {
+		xmlSchemaVErr(vctxt, vctxt->node,
+		    XML_SCHEMAV_INTERNAL,
+		    "Internal error: xmlSchemaXPathEvaluate, "
+		    "failed to evaluate a node.\n",
+		    NULL, NULL);
+		return (-1);
+	    } else if (res == 0) {
+		/*
+		* No Match.
+		*/
+#if DEBUG_IDC
+		xmlGenericError(xmlGenericErrorContext,
+		    "IDC:     no match, blocked\n");
+#endif
+		if (xmlSchemaXPathChangeState(vctxt, sto, -3) == -1)
+		    return (-1);
+	    } else if (res == 1) {
+		/*
+		* Partial match.
+		*/
+#if DEBUG_IDC
+		xmlGenericError(xmlGenericErrorContext,
+		    "IDC:     partial match\n");
+#endif
+		if (xmlSchemaXPathChangeState(vctxt, sto, retState) == -1)
+		    return (-1);
+	    }
+	}
+	if (res != 2)
+	    goto next_sto;
+	/*
+	* Full match.
+	*/
+#if DEBUG_IDC
+	xmlGenericError(xmlGenericErrorContext, "IDC:     "
+	    "final match\n");
+#endif
+	/*
+	* Register a state-change.
+	*/			
+	if (xmlSchemaXPathChangeState(vctxt, sto, -2) == -1)
+	    return (-1);
+	if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_SELECTOR) {
+	    xmlSchemaIDCSelectPtr sel;
+	    /*
+	    * Activate state objects for the IDC fields of
+	    * the IDC selector.
+	    */
+#if DEBUG_IDC
+	    xmlGenericError(xmlGenericErrorContext, "IDC:     "
+		"activating field states\n");
+#endif
+	    sel = sto->matcher->aidc->def->fields;
+	    while (sel != NULL) {
+		if (xmlSchemaIDCAddStateObject(vctxt, sto->matcher, 
+		    sel, sto, XPATH_STATE_OBJ_TYPE_IDC_FIELD) == -1)
+		    return (-1);				
+		sel = sel->next;
+	    }
+	} else if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_FIELD) {
+	    /*
+	    * An IDC key node was found.
+	    */
+#if DEBUG_IDC
+	    xmlGenericError(xmlGenericErrorContext,
+		"IDC:     key found\n");
+#endif
+	    /*
+	    * Notify that the character value of this node is
+	    * needed.
+	    */
+	    if (resolved == 0)
+		vctxt->elemInfo->flags |= XML_SCHEMA_ELEM_INFO_VALUE_NEEDED;
+	    resolved++;
+	}
+next_sto:
+	if (sto->next == NULL) {
+	    /*
+	    * Evaluate field state objects created on this node.
+	    */
+	    head = first;
+	    sto = vctxt->xpathStates;
+	} else
+	    sto = sto->next;
+    }
+    return (resolved);
+}
+
+/**
+ * xmlSchemaXPathProcessChanges:
+ * @vctxt: the WXS validation context
+ * @type: the simple/complex type of the current node if any at all
+ *
+ * Processes and pops the history items of the IDC state objects.
+ * IDC key-sequences are validated/created on IDC bindings.
+ * 
+ * Returns 0 on success and -1 on internal errors.
+ */
+static int
+xmlSchemaXPathProcessChanges(xmlSchemaValidCtxtPtr vctxt,
+			     xmlSchemaTypePtr type)
+{
+    xmlSchemaIDCStateObjPtr sto, nextsto;
+    int res, *change;
+    xmlSchemaPSVIIDCKeyPtr key = NULL;
+
+    if (vctxt->xpathStates == NULL)
+	return (0);
+    sto = vctxt->xpathStates;
+
+#if DEBUG_IDC
+    {
+	xmlChar *str = NULL;
+	xmlGenericError(xmlGenericErrorContext, 
+	    "IDC: BACK on %s, depth %d\n",
+	    xmlSchemaFormatNsUriLocal(&str, vctxt->elemInfo->namespaceName,
+		vctxt->elemInfo->localName), vctxt->depth);
+	FREE_AND_NULL(str)
+    }
+#endif
+
+    /*
+    * Evaluate the state objects.
+    */
+    while (sto != NULL) {
+	/*
+	* If (nbHistory == 1) then there are no history left
+	* (only the initial one), so deregister the state object.
+	*/
+    	if (sto->nbHistory == 1)
+	    goto deregister_check;
+
+	change = sto->history[sto->nbHistory -1];
+
+	/*
+	* Ony history at the current depth are of interest.
+	*/
+	if (change[0] != vctxt->depth) {
+	    sto = sto->next;
+	    continue;
+	}
+
+	if (change[1] == -2) {
+	    if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_FIELD) {
+		if (! IS_SIMPLE_TYPE(type)) {
+		    /*
+		    * Not qualified if the field resolves to a node of non
+		    * simple type.
+		    */	
+		    xmlSchemaVCustomErr(vctxt,
+			XML_SCHEMAV_CVC_IDC,
+			vctxt->node, 
+			(xmlSchemaTypePtr) sto->matcher->aidc->def,
+			"The field '%s' does evaluate to a node of "
+			"non-simple type", sto->sel->xpath);
+
+		    sto->nbHistory--;
+		    sto = sto->next;
+		    continue;
+		}
+		if (vctxt->value == NULL) {
+		    /*
+		    * Failed to provide the normalized value; maby
+		    * the value was invalid.
+		    */ 
+		    xmlSchemaVErr(vctxt, NULL, 
+			XML_SCHEMAV_INTERNAL,
+			"Internal error: xmlSchemaIDCEvaluateMatches, "
+			"normalized node value not available.\n", 
+			NULL, NULL);
+		    sto->nbHistory--;
+		    sto = sto->next;
+		    continue;
+		} else {
+		    xmlSchemaIDCMatcherPtr matcher = sto->matcher;
+		    xmlSchemaPSVIIDCKeyPtr *keySeq;
+		    int pos, sizeNeeded, index;
+
+		    /*
+		    * The key will be anchored on the matcher's list of
+		    * key-sequences. The position in this list is determined
+		    * by the target node's depth relative to the matcher's
+		    * depth of creation (i.e. the depth of the scope element).
+		    * Note that sto->parent will be the selector state object,
+		    * which resolved to a target node. Since this match was
+		    * recorded in the last change entry, we can obtain the
+		    * depth of the target node from there.
+		    */		    
+		    pos = sto->parent->history[sto->parent->nbHistory -1][0] -
+			matcher->depth;
+		    sizeNeeded = pos;
+		    index = sto->sel->index;
+
+		    /*
+		    * Create/grow the array of key-sequences.
+		    */
+		    if (matcher->keySeqs == NULL) {
+			if (pos > 9) 
+			    matcher->sizeKeySeqs = pos * 2;
+			else
+			    matcher->sizeKeySeqs = 10;
+			matcher->keySeqs = (xmlSchemaPSVIIDCKeyPtr **) 
+			    xmlMalloc(matcher->sizeKeySeqs *
+			    sizeof(xmlSchemaPSVIIDCKeyPtr *));			
+			if (matcher->keySeqs == NULL) {		
+			    xmlSchemaVErrMemory(NULL,
+				"allocating an array of key-sequences",
+				NULL);
+			    return(-1);
+			}
+			memset(matcher->keySeqs, 0,
+			    matcher->sizeKeySeqs *
+			    sizeof(xmlSchemaPSVIIDCKeyPtr *));
+		    } else if (pos >= matcher->sizeKeySeqs) {	
+			int i = matcher->sizeKeySeqs;
+
+			matcher->sizeKeySeqs *= 2;
+			matcher->keySeqs = (xmlSchemaPSVIIDCKeyPtr **)
+			    xmlRealloc(matcher->keySeqs,
+			    matcher->sizeKeySeqs *
+			    sizeof(xmlSchemaPSVIIDCKeyPtr *));
+			if (matcher->keySeqs == NULL) {
+			    xmlSchemaVErrMemory(NULL,
+				"reallocating an array of key-sequences",
+				NULL);
+			    return (-1);
+			}
+			/*
+			* The array needs to be NULLed.
+			* TODO: Use memset?
+			*/
+			for (; i < matcher->sizeKeySeqs; i++) 
+			    matcher->keySeqs[i] = NULL;			
+		    }
+		    
+		    /*
+		    * Get/create the key-sequence.
+		    */
+		    keySeq = matcher->keySeqs[pos];		    
+		    if (keySeq == NULL) {	
+			goto create_sequence;
+		    } else {
+			if (keySeq[index] != NULL) {
+			    /*
+			    * cvc-identity-constraint:
+			    * 3 For each node in the ·target node set· all
+			    * of the {fields}, with that node as the context
+			    * node, evaluate to either an empty node-set or
+			    * a node-set with exactly one member, which must
+			    * have a simple type.
+			    * 
+			    * The key was already set; report an error.
+			    */
+			    xmlSchemaVCustomErr(vctxt, 
+				XML_SCHEMAV_CVC_IDC,
+				vctxt->node, (xmlSchemaTypePtr) matcher->aidc->def,
+				"The field '%s' evaluates to a node-set "
+				"with more than one member", sto->sel->xpath);
+			    return (1);
+			} else {
+			    goto create_key;
+			}
+		    }
+
+create_sequence:
+		    /*
+		    * Create a key-sequence.
+		    */
+		    keySeq = (xmlSchemaPSVIIDCKeyPtr *) xmlMalloc(
+			matcher->aidc->def->nbFields * 
+			sizeof(xmlSchemaPSVIIDCKeyPtr));
+		    if (keySeq == NULL) {
+			xmlSchemaVErrMemory(NULL, 
+			    "allocating an IDC key-sequence", NULL);
+			return(-1);			
+		    }	
+		    memset(keySeq, 0, matcher->aidc->def->nbFields * 
+			sizeof(xmlSchemaPSVIIDCKeyPtr));
+		    matcher->keySeqs[pos] = keySeq;
+create_key:
+		    /*
+		    * Created a key once per node only.
+		    */  
+		    if (key == NULL) {
+			key = (xmlSchemaPSVIIDCKeyPtr) xmlMalloc(
+			    sizeof(xmlSchemaPSVIIDCKey));
+			if (key == NULL) {
+			    xmlSchemaVErrMemory(NULL,
+				"allocating a IDC key", NULL);
+			    xmlFree(keySeq);
+			    matcher->keySeqs[pos] = NULL;
+			    return(-1);			
+			}
+			/*
+			* Consume the compiled value.
+			*/
+			key->type = type;
+			key->compValue = vctxt->value;
+			vctxt->value = NULL;
+			/*
+			* Store the key in a global list.
+			*/
+			if (xmlSchemaIDCStoreKey(vctxt, key) == -1) {
+			    xmlSchemaIDCFreeKey(key);
+			    return (-1);
+			}
+		    }
+		    keySeq[index] = key;		    
+		}
+	    } else if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_SELECTOR) {
+		
+		xmlSchemaPSVIIDCKeyPtr **keySeq = NULL;
+		xmlSchemaPSVIIDCBindingPtr bind;
+		xmlSchemaPSVIIDCNodePtr ntItem;
+		xmlSchemaIDCMatcherPtr matcher;
+		xmlSchemaIDCPtr idc;
+		int pos, i, j, nbKeys;
+		/*
+		* Here we have the following scenario:
+		* An IDC 'selector' state object resolved to a target node,
+		* during the time this target node was in the 
+		* ancestor-or-self axis, the 'field' state object(s) looked 
+		* out for matching nodes to create a key-sequence for this 
+		* target node. Now we are back to this target node and need
+		* to put the key-sequence, together with the target node 
+		* itself, into the node-table of the corresponding IDC 
+		* binding.
+		*/
+		matcher = sto->matcher;
+		idc = matcher->aidc->def;
+		nbKeys = idc->nbFields;
+		pos = vctxt->depth - matcher->depth;		
+		/*
+		* Check if the matcher has any key-sequences at all, plus
+		* if it has a key-sequence for the current target node.
+		*/		
+		if ((matcher->keySeqs == NULL) ||
+		    (matcher->sizeKeySeqs <= pos)) {
+		    if (idc->type == XML_SCHEMA_TYPE_IDC_KEY)
+			goto selector_key_error;
+		    else
+			goto selector_leave;
+		}
+		
+		keySeq = &(matcher->keySeqs[pos]);		
+		if (*keySeq == NULL) {
+		    if (idc->type == XML_SCHEMA_TYPE_IDC_KEY)
+			goto selector_key_error;
+		    else
+			goto selector_leave;
+		}
+		
+		for (i = 0; i < nbKeys; i++) {
+		    if (*keySeq[i] == NULL) {
+			/*
+			* Not qualified, if not all fields did resolve.
+			*/
+			if (idc->type == XML_SCHEMA_TYPE_IDC_KEY) {
+			    /*
+			    * All fields of a "key" IDC must resolve.
+			    */
+			    goto selector_key_error;
+			}		    
+			goto selector_leave;
+		    }
+		}
+		/*
+		* All fields did resolve.
+		*/
+
+		/*
+		* 4.1 If the {identity-constraint category} is unique(/key),
+		* then no two members of the ·qualified node set· have
+		* ·key-sequences· whose members are pairwise equal, as
+		* defined by Equal in [XML Schemas: Datatypes].
+		*
+		* Get the IDC binding from the matcher and check for
+		* duplicate key-sequences.
+		*/
+		bind = xmlSchemaIDCAquireBinding(vctxt, matcher);
+		if ((idc->type != XML_SCHEMA_TYPE_IDC_KEYREF) && 
+		    (bind->nbNodes != 0)) {
+		    xmlSchemaPSVIIDCKeyPtr key, bkey, *bkeySeq;
+		    
+		    i = 0;
+		    /*
+		    * Compare the key-sequences, key by key.
+		    */
+		    do {
+			bkeySeq = bind->nodeTable[i]->keys;
+			for (j = 0; j < nbKeys; j++) {
+			    key = *keySeq[j];
+			    bkey = bkeySeq[j];							
+			    res = xmlSchemaAreValuesEqual(key->type,
+				key->compValue, bkey->type, bkey->compValue);
+			    if (res == -1) {
+				return (-1);
+			    } else if (res == 0)
+				break;
+			}
+			if (res == 1) {
+			    /*
+			    * Duplicate found.
+			    */
+			    break;
+			}
+			i++;
+		    } while (i < bind->nbNodes);
+		    if (i != bind->nbNodes) {
+			/*   
+			* TODO: Try to report the key-sequence.
+			*/
+			xmlSchemaVCustomErr(vctxt, 
+			    XML_SCHEMAV_CVC_IDC,
+			    vctxt->node,
+			    (xmlSchemaTypePtr) idc,
+			    "Duplicate key-sequence found", NULL);
+			
+			goto selector_leave;
+		    }
+		}
+		/*
+		* Add a node-table item to the IDC binding.
+		*/
+		ntItem = (xmlSchemaPSVIIDCNodePtr) xmlMalloc(
+		    sizeof(xmlSchemaPSVIIDCNode));
+		if (ntItem == NULL) {
+		    xmlSchemaVErrMemory(NULL, 
+			"allocating an IDC node-table item", NULL);
+		    xmlFree(*keySeq);
+		    *keySeq = NULL;
+		    return(-1);
+		}	
+		memset(ntItem, 0, sizeof(xmlSchemaPSVIIDCNode));		
+		
+		/* 
+		* Store the node-table item on global list.
+		*/
+		if (idc->type != XML_SCHEMA_TYPE_IDC_KEYREF) {
+		    if (xmlSchemaIDCStoreNodeTableItem(vctxt, ntItem) == -1) {
+			xmlFree(ntItem);
+			xmlFree(*keySeq);
+			*keySeq = NULL;
+			return (-1);
+		    }
+		}
+		/*
+		* Init the node-table item. Consume the key-sequence.
+		*/
+		ntItem->node = vctxt->node;
+		ntItem->keys = *keySeq;
+		*keySeq = NULL;
+		if (xmlSchemaIDCAppendNodeTableItem(bind, ntItem) == -1) {		    
+		    if (idc->type == XML_SCHEMA_TYPE_IDC_KEYREF) {
+			/* 
+			* Free the item, since keyref items won't be
+			* put on a global list.
+			*/
+			xmlFree(ntItem->keys);
+			xmlFree(ntItem);
+		    }
+		    return (-1);
+		}
+		
+		goto selector_leave;
+selector_key_error:
+		/*
+		* 4.2.1 (KEY) The ·target node set· and the 
+		* ·qualified node set· are equal, that is, every 
+		* member of the ·target node set· is also a member
+		* of the ·qualified node set· and vice versa.
+		*/
+		xmlSchemaVCustomErr(vctxt, 
+		    XML_SCHEMAV_CVC_IDC,
+		    vctxt->node, 
+		    (xmlSchemaTypePtr) idc,
+		    "All 'key' fields must evaluate to a node",
+		    NULL);
+selector_leave:
+		/*
+		* Free the key-sequence if not added to the IDC table.
+		*/
+		if (*keySeq != NULL) {
+		    xmlFree(*keySeq);
+		    *keySeq = NULL;
+		}
+	    } /* if selector */
+	} /* if matched */
+
+	sto->nbHistory--;
+
+deregister_check:
+	/*
+	* Deregister state objects if they reach the depth of creation.
+	* Note that this has to be checked before and after processing
+	* any history if the state object resolved to partially/fully
+	* to a node on which it was created as well, since this scenario
+	* created two entries in the list of history for the same node.
+	*/
+	if ((sto->nbHistory == 1) && (sto->history[0][0] == vctxt->depth)) {
+#if DEBUG_IDC
+	    xmlGenericError(xmlGenericErrorContext, "IDC:   STO pop '%s'\n",
+		sto->sel->xpath);
+#endif
+	    if (vctxt->xpathStates != sto) {
+		xmlSchemaVErr(vctxt, vctxt->node,
+		    XML_SCHEMAV_INTERNAL,
+		    "Internal error: xmlSchemaXPathProcessChanges, "
+		    "The state object to be removed is not the first "
+		    "in the list.\n",
+		    NULL, NULL);
+	    }
+	    sto->nbHistory = 0;
+	    nextsto = sto->next;
+	    /*
+	    * Unlink from the list of active XPath state objects.
+	    */
+	    vctxt->xpathStates = sto->next;
+	    sto->next = vctxt->xpathStatePool;
+	    /*
+	    * Link it to the pool of reusable state objects.
+	    */
+	    vctxt->xpathStatePool = sto;	    
+	    sto = nextsto;
+	} else
+	    sto = sto->next;
+    } /* while (sto != NULL) */
+    return (0);
+}
+
+/**
+ * xmlSchemaIDCRegisterMatchers:
+ * @vctxt: the WXS validation context
+ * @elemDecl: the element declaration
+ *
+ * Creates helper objects to evaluate IDC selectors/fields
+ * successively.
+ *
+ * Returns 0 if OK and -1 on internal errors.
+ */
+static int
+xmlSchemaIDCRegisterMatchers(xmlSchemaValidCtxtPtr vctxt,
+			     xmlSchemaElementPtr elemDecl)
+{
+    xmlSchemaIDCMatcherPtr matcher, last = NULL;
+    xmlSchemaIDCPtr idc, refIdc;
+    xmlSchemaIDCAugPtr aidc;
+        
+    idc = (xmlSchemaIDCPtr) elemDecl->idcs;
+    if (idc == NULL)
+	return (0);
+    
+#if DEBUG_IDC
+    {
+	xmlChar *str = NULL;
+	xmlGenericError(xmlGenericErrorContext, 
+	    "IDC: MATCHERS on %s, depth %d\n",
+	    xmlSchemaFormatNsUriLocal(&str, vctxt->elemInfo->namespaceName,
+		vctxt->elemInfo->localName), vctxt->depth);
+	FREE_AND_NULL(str)
+    }
+#endif
+    if (vctxt->elemInfo->idcMatchers != NULL) {
+	xmlSchemaVErr(vctxt, vctxt->node,
+	    XML_SCHEMAV_INTERNAL,
+	    "Internal error: xmlSchemaIDCRegisterMatchers: "
+	    "The chain of IDC matchers is expected to be empty.\n",
+	    NULL, NULL);
+	return (-1);
+    }
+    do {
+	if (idc->type == XML_SCHEMA_TYPE_IDC_KEYREF) {
+	    /*
+	    * Since IDCs bubbles are expensive we need to know the
+	    * depth at which the bubbles should stop; this will be
+	    * the depth of the top-most keyref IDC. If no keyref
+	    * references a key/unique IDC, the bubbleDepth will
+	    * be -1, indicating that no bubbles are needed.
+	    */
+	    refIdc = (xmlSchemaIDCPtr) idc->ref->item;
+	    if (refIdc != NULL) {
+		/*
+		* Lookup the augmented IDC.
+		*/
+		aidc = vctxt->aidcs;
+		while (aidc != NULL) {
+		    if (aidc->def == refIdc)
+			break;
+		    aidc = aidc->next;
+		}
+		if (aidc == NULL) {
+		    xmlSchemaVErr(vctxt, vctxt->node,
+			XML_SCHEMAV_INTERNAL,
+			"Internal error: xmlSchemaIDCRegisterMatchers: "
+			"Could not find an augmented IDC item for an IDC "
+			"definition.\n",
+			NULL, NULL);
+		    return (-1);
+		}		
+		if ((aidc->bubbleDepth == -1) ||
+		    (vctxt->depth < aidc->bubbleDepth))
+		    aidc->bubbleDepth = vctxt->depth;
+	    }
+	}
+	/*
+	* Lookup the augmented IDC item for the IDC definition.
+	*/
+	aidc = vctxt->aidcs;
+	while (aidc != NULL) {
+	    if (aidc->def == idc)
+		break;
+	    aidc = aidc->next;
+	}
+	if (aidc == NULL) {
+	    xmlSchemaVErr(vctxt, vctxt->node,
+		XML_SCHEMAV_INTERNAL,
+		"Internal error: xmlSchemaIDCRegisterMatchers: "
+		"Could not find an augmented IDC item for an IDC definition.\n",
+		NULL, NULL);
+	    return (-1);
+	}
+	/*
+	* Create an IDC matcher for every IDC definition.
+	*/
+	matcher = (xmlSchemaIDCMatcherPtr) 
+	    xmlMalloc(sizeof(xmlSchemaIDCMatcher));
+	if (matcher == NULL) {
+	    xmlSchemaVErrMemory(vctxt, 
+		"allocating an IDC matcher", NULL);
+	    return (-1);
+	}
+	memset(matcher, 0, sizeof(xmlSchemaIDCMatcher));
+	if (last == NULL)
+	    vctxt->elemInfo->idcMatchers = matcher;
+	else
+	    last->next = matcher;
+	last = matcher;
+
+	matcher->type = IDC_MATCHER;
+	matcher->depth = vctxt->depth;	
+	matcher->aidc = aidc;
+#if DEBUG_IDC	
+	xmlGenericError(xmlGenericErrorContext, "IDC:   register matcher\n");
+#endif 
+	/*
+	* Init the automaton state object. 
+	*/
+	if (xmlSchemaIDCAddStateObject(vctxt, matcher, 
+	    idc->selector, NULL, XPATH_STATE_OBJ_TYPE_IDC_SELECTOR) == -1)
+	    return (-1);
+
+	idc = idc->next;
+    } while (idc != NULL);
+    return (0);
+}
+
+/**
+ * xmlSchemaBubbleIDCNodeTables: 
+ * @depth: the current tree depth
+ *
+ * Merges IDC bindings of an element at @depth into the corresponding IDC 
+ * bindings of its parent element. If a duplicate note-table entry is found, 
+ * both, the parent node-table entry and child entry are discarded from the 
+ * node-table of the parent.
+ *
+ * Returns 0 if OK and -1 on internal errors.
+ */
+static int
+xmlSchemaBubbleIDCNodeTables(xmlSchemaValidCtxtPtr vctxt)
+{
+    xmlSchemaPSVIIDCBindingPtr bind; /* IDC bindings of the current node. */
+    xmlSchemaPSVIIDCBindingPtr *parTable, parBind, lastParBind; /* parent IDC bindings. */
+    xmlSchemaPSVIIDCNodePtr node, parNode; /* node-table entries. */
+    xmlSchemaPSVIIDCKeyPtr key, parKey; /* keys of in a key-sequence. */
+    xmlSchemaIDCAugPtr aidc;
+    int i, j, k, ret, oldNum, newDupls = 0;
+    int duplTop;
+
+    /*
+    * The node table has the following sections:
+    *
+    *  O --> old node-table entries (first)
+    *  O 
+    *  + --> new node-table entries
+    *  + 
+    *  % --> new duplicate node-table entries    
+    *  % 
+    *  # --> old duplicate node-table entries    
+    *  # (last)
+    *
+    */
+    bind = vctxt->elemInfo->idcTable;        
+    if (bind == NULL) {
+	/* Fine, no table, no bubbles. */
+	return (0);
+    }
+
+    parTable = &(vctxt->elemInfos[vctxt->depth -1]->idcTable);
+    /*
+    * Walk all bindings; create new or add to existing bindings.
+    * Remove duplicate key-sequences.
+    */
+start_binding:
+    while (bind != NULL) {
+	/*
+	* Skip keyref IDCs.
+	*/
+	if (bind->definition->type == XML_SCHEMA_TYPE_IDC_KEYREF)
+	    continue;
+	/*
+	* Check if the key/unique IDC table needs to be bubbled.
+	*/
+	aidc = vctxt->aidcs;
+	do {
+	    if (aidc->def == bind->definition) {
+		if (aidc->bubbleDepth == vctxt->depth) {
+		    bind = bind->next;
+		    goto start_binding;
+		}
+		break;
+	    }
+	    aidc = aidc->next;
+	} while (aidc != NULL);
+	if (parTable != NULL)
+	    parBind = *parTable;
+	while (parBind != NULL) {
+	    /*
+	    * Search a matching parent binding for the
+	    * IDC definition.
+	    */
+	    if (parBind->definition == bind->definition) {
+
+		/*
+		* Compare every node-table entry of the child node, 
+		* i.e. the key-sequence within, ...
+		*/
+		oldNum = parBind->nbNodes; /* Skip newly added items. */
+		duplTop = oldNum + parBind->nbDupls;
+
+		for (i = 0; i < bind->nbNodes; i++) {
+		    node = bind->nodeTable[i];
+		    if (node == NULL)
+			continue;
+		    /*
+		    * ...with every key-sequence of the parent node, already
+		    * evaluated to be a duplicate key-sequence.
+		    */
+		    if (parBind->nbDupls != 0) {
+			j = bind->nbNodes + newDupls; 
+			while (j < duplTop) {
+			    parNode = parBind->nodeTable[j];
+			    for (k = 0; k < bind->definition->nbFields; k++) {
+				key = node->keys[k];
+				parKey = parNode->keys[k];
+				ret = xmlSchemaAreValuesEqual(key->type, 
+				    key->compValue,
+				    parKey->type, parKey->compValue);
+				if (ret == -1) {
+				    /* TODO: Internal error */
+				    return(-1);
+				} else if (ret == 0)
+				    break;
+
+			    }
+			    if (ret == 1)
+				/* Duplicate found. */
+				break;
+			    j++;
+			}
+			if (j != duplTop) {
+			    /* Duplicate found. */
+			    continue;
+			}
+		    }		    
+		    /*
+		    * ... and with every key-sequence of the parent node.
+		    */		    		    
+		    j = 0;
+		    while (j < oldNum) {
+			parNode = parBind->nodeTable[j];
+			/*
+			* Compare key by key. 
+			*/
+			for (k = 0; k < parBind->definition->nbFields; k++) {
+			    key = node->keys[k];
+			    parKey = parNode->keys[k];			
+
+			    ret = xmlSchemaAreValuesEqual(key->type, 
+				key->compValue,
+				parKey->type, parKey->compValue);
+			    if (ret == -1) {
+				/* TODO: Internal error */
+			    } else if (ret == 0)
+				break;
+
+			}
+			if (ret == 1)
+			    /*
+			    * The key-sequences are equal.
+			    */
+			    break;
+			j++;
+		    }
+		    if (j != oldNum) {
+			/*
+			* Handle duplicates.
+			*/
+			newDupls++;
+			oldNum--;
+			parBind->nbNodes--;
+			/*
+			* Move last old item to pos of duplicate.
+			*/
+			parBind->nodeTable[j] = 
+			    parBind->nodeTable[oldNum];
+			
+			if (parBind->nbNodes != oldNum) {
+			    /*
+			    * If new items exist, move last new item to 
+			    * last of old items.
+			    */
+			    parBind->nodeTable[oldNum] = 
+				parBind->nodeTable[parBind->nbNodes];
+			}
+			/*
+			* Move duplicate to last pos of new/old items.
+			*/
+			parBind->nodeTable[parBind->nbNodes] = parNode;			
+			
+		    } else {
+			/*
+			* Add the node-table entry (node and key-sequence) of 
+			* the child node to the node table of the parent node.
+			*/
+			if (parBind->nodeTable == NULL) {			
+			    parBind->nodeTable = (xmlSchemaPSVIIDCNodePtr *) 
+				xmlMalloc(1 * sizeof(xmlSchemaPSVIIDCNodePtr));
+			    if (parBind->nodeTable == NULL) {
+				xmlSchemaVErrMemory(NULL, 
+				    "allocating IDC list of node-table items", NULL);
+				return(-1);
+			    }
+			    parBind->sizeNodes = 1;
+			} else if (duplTop >= parBind->sizeNodes) {
+			    parBind->sizeNodes++;
+			    parBind->nodeTable = (xmlSchemaPSVIIDCNodePtr *) 
+				xmlRealloc(parBind->nodeTable, parBind->sizeNodes * 
+				sizeof(xmlSchemaPSVIIDCNodePtr));
+			    if (parBind->nodeTable == NULL) {
+				xmlSchemaVErrMemory(NULL, 
+				    "re-allocating IDC list of node-table items", NULL);
+				return(-1);
+			    }
+			}
+			
+			/*
+			* Move first old duplicate to last position
+			* of old duplicates +1.
+			*/
+			if (parBind->nbDupls != 0) {
+			    parBind->nodeTable[duplTop] =
+				parBind->nodeTable[parBind->nbNodes + newDupls];
+			}
+			/*
+			* Move first new duplicate to last position of
+			* new duplicates +1.
+			*/
+			if (newDupls != 0) {
+			    parBind->nodeTable[parBind->nbNodes + newDupls] =
+				parBind->nodeTable[parBind->nbNodes];
+			}
+			/*
+			* Append the new node-table entry to the 'new node-table
+			* entries' section.
+			*/
+			parBind->nodeTable[parBind->nbNodes] = node;
+			parBind->nbNodes++;
+			duplTop++;
+		    }
+		}
+		parBind->nbDupls += newDupls;
+		break;
+	    }
+	    if (parBind->next == NULL)
+		lastParBind = parBind;
+	    parBind = parBind->next;
+	}
+	if (parBind == NULL) {
+	    /*
+	    * No binding for the IDC was found: create a new one and
+	    * copy all node-tables.
+	    */
+	    parBind = xmlSchemaIDCNewBinding(bind->definition);
+	    if (parBind == NULL)
+		return(-1);
+
+	    parBind->nodeTable = (xmlSchemaPSVIIDCNodePtr *) 
+		xmlMalloc(bind->nbNodes * sizeof(xmlSchemaPSVIIDCNodePtr));
+	    if (parBind->nodeTable == NULL) {
+		xmlSchemaVErrMemory(NULL, 
+		    "allocating an array of IDC node-table items", NULL);
+		xmlSchemaIDCFreeBinding(parBind);
+		return(-1);
+	    }
+	    parBind->sizeNodes = bind->nbNodes;
+	    memcpy(parBind->nodeTable, bind->nodeTable,
+		bind->nbNodes * sizeof(xmlSchemaPSVIIDCNodePtr));
+	    /*
+	    for (i = 1; i < bind->nbNodes; i++)
+		parBind->nodeTable[i] = bind->nodeTable[i];
+		*/
+	    if (*parTable == NULL)
+		*parTable = parBind;
+	    else
+		lastParBind->next = parBind;
+	}
+	bind = bind->next;
+    }  
+    return (0);
+}
+
+/**
+ * xmlSchemaCheckCVCIDCKeyRef:
+ * @vctxt: the WXS validation context
+ * @elemDecl: the element declaration
+ *
+ * Check the cvc-idc-keyref constraints.
+ */
+static int
+xmlSchemaCheckCVCIDCKeyRef(xmlSchemaValidCtxtPtr vctxt)
+{
+    xmlSchemaPSVIIDCBindingPtr refbind, bind;
+
+    refbind = vctxt->elemInfo->idcTable;
+    /*
+    * Find a keyref.
+    */
+    while (refbind != NULL) {
+	if (refbind->definition->type == XML_SCHEMA_TYPE_IDC_KEYREF) {
+	    int i, j, k, res;
+	    xmlSchemaPSVIIDCKeyPtr *refKeys, *keys;
+	    xmlSchemaPSVIIDCKeyPtr refKey, key;
+
+	    /*
+	    * Find the referred key/unique.
+	    */
+	    bind = vctxt->elemInfo->idcTable;
+	    do {
+		if ((xmlSchemaIDCPtr) refbind->definition->ref->item == 
+		    bind->definition)
+		    break;
+		bind = bind->next;
+	    } while (bind != NULL);
+
+	    /*
+	    * Search for a matching key-sequences.
+	    */
+	    for (i = 0; i < refbind->nbNodes; i++) {
+		res = 0;
+		if (bind != NULL) {		    
+		    refKeys = refbind->nodeTable[i]->keys;
+		    for (j = 0; j < bind->nbNodes; j++) {
+			keys = bind->nodeTable[j]->keys;
+			for (k = 0; k < bind->definition->nbFields; k++) {
+			    refKey = refKeys[k];
+			    key = keys[k];
+			    res = xmlSchemaAreValuesEqual(key->type, key->compValue,
+				refKey->type, refKey->compValue);
+			    if (res == 0)
+				break;
+			    else if (res == -1) {
+				return (-1);
+			    }
+			}
+			if (res == 1) {
+			    /*
+			    * Match found.
+			    */
+			    break;
+			}
+		    }
+		}
+		if (res == 0) {
+		    /* TODO: Report the key-sequence. */
+		    xmlSchemaVCustomErr(vctxt,
+			XML_SCHEMAV_CVC_IDC,
+			refbind->nodeTable[i]->node, 
+			(xmlSchemaTypePtr) refbind->definition,
+			"No matching key-sequence found", NULL);
+		}
+	    }
+	}
+	refbind = refbind->next;
+    }
+    return (0);
+}
+#endif /* IDC_ENABLED */
+
+#ifdef ELEM_INFO_ENABLED
+/**
+ * xmlSchemaBeginElement:
+ * @vctxt: the WXS validation context
+ *
+ * Just a temporary workaround to simulate streaming validation
+ * a bit.
+ */
+static void
+xmlSchemaBeginElement(xmlSchemaValidCtxtPtr vctxt)
+{
+    vctxt->depth++;
+    vctxt->elemInfo = xmlSchemaGetFreshElemInfo(vctxt);
+    vctxt->elemInfo->node = vctxt->node;
+    vctxt->elemInfo->localName = vctxt->node->name;
+    if (vctxt->node->ns != NULL)
+	vctxt->elemInfo->namespaceName = vctxt->node->ns->href;
+    else 
+	vctxt->elemInfo->namespaceName = NULL;    
+}
+
+/**
+ * xmlSchemaEndElement:
+ * @vctxt: the WXS validation context
+ *
+ * Just a temporary workaround to simulate streaming validation
+ * a bit.
+ */
+static void
+xmlSchemaEndElement(xmlSchemaValidCtxtPtr vctxt)
+{
+    if (vctxt->depth < 0) {
+	/* TODO: raise error? */
+	vctxt->depth--;
+	return;
+    }
+#ifdef IDC_ENABLED
+    /*
+    * Evaluate the history of changes of active state objects.
+    */
+    xmlSchemaXPathProcessChanges(vctxt, vctxt->elemInfo->typeDef);
+
+    if (vctxt->elemInfo->value != NULL) {
+	xmlSchemaFreeValue(vctxt->elemInfo->value);
+	vctxt->elemInfo->value = NULL;
+    }
+    /*
+    * TODO: 6 The element information item must be ·valid· with respect to each of 
+    * the {identity-constraint definitions} as per Identity-constraint 
+    * Satisfied (§3.11.4).
+    */
+    /*
+    * Validate IDC keyrefs.
+    */
+    xmlSchemaCheckCVCIDCKeyRef(vctxt);
+#endif
+    
+    /*
+    * Merge/free the IDC table.
+    */
+    if (vctxt->elemInfo->idcTable != NULL) {
+#ifdef DEBUG_IDC
+	xmlSchemaDebugDumpIDCTable(stdout,
+	    vctxt->elemInfo->namespaceName,
+	    vctxt->elemInfo->localName,
+	    vctxt->elemInfo->idcTable);
+#endif
+#ifdef IDC_ENABLED
+	if (vctxt->depth > 0) {
+	    /*
+	    * Merge the IDC node table with the table of the parent node.
+	    */
+	    xmlSchemaBubbleIDCNodeTables(vctxt);	    
+	}
+	/*
+	* TODO: Don't free the PSVI IDC tables if they are
+	* requested for the PSVI.
+	*/
+	xmlSchemaIDCFreeIDCTable(vctxt->elemInfo->idcTable);
+#endif
+	vctxt->elemInfo->idcTable = NULL;
+    }
+
+    /*
+    * Cleanup IDC matchers.
+    */
+#ifdef IDC_ENABLED
+    if (vctxt->elemInfo->idcMatchers != NULL) {	
+	xmlSchemaIDCFreeMatcherList(vctxt->elemInfo->idcMatchers);
+	vctxt->elemInfo->idcMatchers = NULL;
+    }
+#endif
+
+    /*
+    * Skip further processing if we are on the validation root.
+    */
+    if (vctxt->depth == 0) {
+	vctxt->depth--;
+	return;
+    }
+
+    /*
+    * Reset the bubbleDepth if needed.
+    */
+#ifdef IDC_ENABLED
+    if (vctxt->aidcs != NULL) {
+	xmlSchemaIDCAugPtr aidc = vctxt->aidcs;
+	do {
+	    if (aidc->bubbleDepth == vctxt->depth) {
+		/*
+		* A bubbleDepth of a key/unique IDC matches the current
+		* depth, this means that we are leaving the scope of the
+		* top-most keyref IDC.
+		*/
+		aidc->bubbleDepth = -1;
+	    }
+	    aidc = aidc->next;
+	} while (aidc != NULL);
+    }
+#endif
+    vctxt->depth--;
+    vctxt->elemInfo = vctxt->elemInfos[vctxt->depth];
+    vctxt->node = vctxt->elemInfo->node;
+}
+
+#endif /* ELEM_INFO_ENABLED */
 
 /**
  * xmlSchemaValidateElementByDeclaration:
@@ -15285,6 +17972,14 @@
 	    XML_SCHEMAV_CVC_ELT_1, 
 	    elem, NULL,
 	    "No matching declaration available", NULL);
+	/* 
+	* Evaluate IDCs even if an error occured.
+	*/
+#ifdef IDC_ENABLED
+	if (xmlSchemaXPathEvaluate(ctxt, ctxt->elemInfo->namespaceName,
+	    ctxt->elemInfo->localName, XML_ELEMENT_NODE) == -1)
+	    return (-1);
+#endif
         return (ctxt->err);
     }
     /*
@@ -15295,6 +17990,14 @@
 	    XML_SCHEMAV_CVC_ELT_2,
 	    elem, NULL, 
 	    "The element declaration is abstract", NULL);
+	/* 
+	* Evaluate IDCs even if an error occured.
+	*/
+#ifdef IDC_ENABLED
+	if (xmlSchemaXPathEvaluate(ctxt, ctxt->elemInfo->namespaceName,
+	    ctxt->elemInfo->localName, XML_ELEMENT_NODE) == -1)
+	    return (-1);
+#endif
         return (ctxt->err);
     }
      
@@ -15324,8 +18027,8 @@
 	    return (-1);
 	} 
 	if ((elemDecl->flags & XML_SCHEMAS_ELEM_NILLABLE) == 0) {
-	/* 
-	* cvc-elt (3.3.4) : 3.1 
+	    /* 
+	    * cvc-elt (3.3.4) : 3.1 
 	    */
 	    xmlSchemaVCustomErr(ctxt, 
 		XML_SCHEMAV_CVC_ELT_3_1, 
@@ -15447,6 +18150,14 @@
     	    XML_SCHEMAV_CVC_TYPE_1,
     	    elem, (xmlSchemaTypePtr) elemDecl, 
     	    "The type definition is absent", NULL);
+	/* 
+	* Evaluate IDCs even if an error occured.
+	*/
+#ifdef IDC_ENABLED
+	if (xmlSchemaXPathEvaluate(ctxt, ctxt->elemInfo->namespaceName,
+	    ctxt->elemInfo->localName, XML_ELEMENT_NODE) == -1)
+	    return (-1);
+#endif
     	return (XML_SCHEMAV_CVC_TYPE_1);
     }
     
@@ -15480,6 +18191,20 @@
     */    
     if (elemHasContent == -1)
 	elemHasContent = xmlSchemaHasElemOrCharContent(elem);
+
+    /*
+    * IDC: Register identity-constraint XPath matchers.
+    */
+#ifdef IDC_ENABLED
+    if (elemDecl->idcs != NULL)
+	xmlSchemaIDCRegisterMatchers(ctxt, elemDecl);
+    /* 
+    * Evaluate IDCs.
+    */
+    if (xmlSchemaXPathEvaluate(ctxt, ctxt->elemInfo->namespaceName,
+	    ctxt->elemInfo->localName, XML_ELEMENT_NODE) == -1)
+	return (-1);
+#endif
     /*
     * cvc-elt (3.3.4) : 5 
     * The appropriate case among the following must be true:
@@ -15668,13 +18393,6 @@
 	    
 	}
     }
-
-    /*
-    * TODO: 6 The element information item must be ·valid· with respect to each of 
-    * the {identity-constraint definitions} as per Identity-constraint 
-    * Satisfied (§3.11.4).
-    */
-
     /*
     * TODO: 7 If the element information item is the ·validation root·, it must be 
     * ·valid· per Validation Root Valid (ID/IDREF) (§3.3.4).
@@ -15725,7 +18443,8 @@
 	    decl = xmlHashLookup3(ctxt->schema->elemDecl,
 	    node->name, node->ns->href, NULL);
 	else 
-	    decl = xmlHashLookup3(ctxt->schema->elemDecl, node->name, NULL, NULL);
+	    decl = xmlHashLookup3(ctxt->schema->elemDecl, node->name,
+	    NULL, NULL);
 	if (decl != NULL) {		    
 	    ctxt->node = node;	
 	    ret = xmlSchemaValidateElementByDeclaration(ctxt, decl);
@@ -15740,8 +18459,27 @@
 	    /* TODO: Change to proper error code. */
 	    xmlSchemaVWildcardErr(ctxt, XML_SCHEMAV_CVC_ELT_1,
 		node, wild, "No matching global declaration available");
+	    /* 
+	    * Evaluate IDCs even if a validation error occured.
+	    */
+#ifdef IDC_ENABLED
+	    if (xmlSchemaXPathEvaluate(ctxt, ctxt->elemInfo->namespaceName,
+		ctxt->elemInfo->localName, XML_ELEMENT_NODE) == -1)
+		return(-1);
+#endif
 	    return (ctxt->err);
 	}
+	/* 
+	* Evaluate IDCs; we need to know if an IDC field resolves to
+	* such a node. This node has no type definition and will
+	* definitely result in an IDC validation error if an IDC field
+	* resolves.
+	*/
+#ifdef IDC_ENABLED
+	if (xmlSchemaXPathEvaluate(ctxt, ctxt->elemInfo->namespaceName,
+	    ctxt->elemInfo->localName, XML_ELEMENT_NODE) == -1)
+	    return(-1);
+#endif
     }
     if (node->children != NULL) {	   
 	child = node->children;
@@ -15758,8 +18496,18 @@
 			"The namespace of the element is not allowed");
 		    return (ctxt->err);  
 		}
+#ifdef ELEM_INFO_ENABLED
+		ctxt->node = child;
+		xmlSchemaBeginElement(ctxt);
+#endif
+		/*
+		* Recurse over the children.
+		*/
 		ret = xmlSchemaValidateElementByWildcardInternal(ctxt, 
 		    wild, child);
+#ifdef ELEM_INFO_ENABLED
+		xmlSchemaEndElement(ctxt);
+#endif
 		if (ret != 0)
 		    return (ret);		
 	    }
@@ -16296,6 +19044,10 @@
     	return (XML_SCHEMAV_CVC_TYPE_2);
     }
 
+#ifdef ELEM_INFO_ENABLED
+    ctxt->elemInfo->typeDef = type;
+#endif
+
     switch (type->type) {
 	case XML_SCHEMA_TYPE_COMPLEX:
             ret = xmlSchemaValidateElementByComplexType(ctxt, type,
@@ -16827,9 +19579,6 @@
 	ctxt->xsiAssemble = 1;
     } else
 	ctxt->xsiAssemble = 0;
-    /* ctxt->options |= XML_SCHEMA_VAL_VC_I_CREATE;
-    * ctxt->xsiAssemble = 1;
-    */
     /*
     * Assemble new schemata using xsi.
     */
@@ -16861,7 +19610,14 @@
 		"No matching global declaration available", NULL);
 	    ret = XML_SCHEMAV_CVC_ELT_1;
 	} else { 
+#ifdef ELEM_INFO_ENABLED
+	    ctxt->depth = -1;
+	    xmlSchemaBeginElement(ctxt);
+#endif
 	    ret = xmlSchemaValidateElementByDeclaration(ctxt, elemDecl);    
+#ifdef ELEM_INFO_ENABLED
+	    xmlSchemaEndElement(ctxt);
+#endif
 	    if (ret < 0) {
 		xmlSchemaVCustomErr(ctxt,
 		    XML_SCHEMAV_INTERNAL, ctxt->node, NULL,
@@ -16937,7 +19693,6 @@
 	    "The document has no document element", NULL);
         return (ctxt->err);
     }    
-    /* ctxt->options |= XML_SCHEMA_VAL_XSI_ASSEMBLE; */
     /*
      * Okay, start the recursive validation
      */
@@ -17003,6 +19758,73 @@
     if (ctxt->pctxt != NULL) {
 	xmlSchemaFreeParserCtxt(ctxt->pctxt);
     }
+
+#ifdef IDC_ENABLED
+    if (ctxt->idcNodes != NULL) {
+	int i;
+	xmlSchemaPSVIIDCNodePtr item;
+
+	for (i = 0; i < ctxt->nbIdcNodes; i++) {
+	    item = ctxt->idcNodes[i];	    
+	    xmlFree(item->keys);
+	    xmlFree(item);
+	}
+	xmlFree(ctxt->idcNodes);
+    }
+
+    if (ctxt->idcKeys != NULL) {
+	int i;
+	for (i = 0; i < ctxt->nbIdcKeys; i++)
+	    xmlSchemaIDCFreeKey(ctxt->idcKeys[i]);
+	xmlFree(ctxt->idcKeys);
+    }
+
+    if (ctxt->xpathStates != NULL)
+	xmlSchemaFreeIDCStateObjList(ctxt->xpathStates);
+    if (ctxt->xpathStatePool != NULL)
+	xmlSchemaFreeIDCStateObjList(ctxt->xpathStatePool);
+
+    /*
+    * Augmented IDC information.
+    */
+    if (ctxt->aidcs != NULL) {
+	xmlSchemaIDCAugPtr cur = ctxt->aidcs, next;
+	do {
+	    next = cur->next;
+	    xmlFree(cur);
+	    cur = next;
+	} while (cur != NULL);
+    }
+#endif /* IDC_ENABLED */
+#ifdef ELEM_INFO_ENABLED
+    if (ctxt->elemInfos != NULL) {
+	int i;
+	xmlSchemaElemInfoPtr info;
+
+	for (i = 0; i < ctxt->sizeElemInfos; i++) {
+	    info = ctxt->elemInfos[i];
+	    if (info == NULL)
+		continue;
+	    if (info->value != NULL)
+		xmlSchemaFreeValue(info->value);
+#ifdef IDC_ENABLED
+	    if (info->idcMatchers != NULL)
+		xmlSchemaIDCFreeMatcherList(info->idcMatchers);
+#endif
+	    /*
+	    *  TODO: Free the IDC table if still existent.
+	    */
+
+	    /*
+	    xmlFree(info->localName);
+	    if (info->namespaceName != NULL)
+		xmlFree(info->namespaceName);
+	    */
+	    xmlFree(info);
+	}
+	xmlFree(ctxt->elemInfos);
+    }
+#endif
     xmlFree(ctxt);
 }